@forgeax/engine-pack 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +1 -1
  2. package/dist/build.d.ts +1 -1
  3. package/dist/build.d.ts.map +1 -1
  4. package/dist/build.mjs +129 -26
  5. package/dist/build.mjs.map +1 -1
  6. package/dist/cli-asset.mjs.map +1 -1
  7. package/dist/evidence/material-cook.d.ts +29 -3
  8. package/dist/evidence/material-cook.d.ts.map +1 -1
  9. package/dist/index.d.ts +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.mjs +123 -24
  12. package/dist/index.mjs.map +1 -1
  13. package/dist/material-cook.d.ts +1 -1
  14. package/dist/material-cook.d.ts.map +1 -1
  15. package/dist/material-cook.mjs +123 -24
  16. package/dist/material-cook.mjs.map +1 -1
  17. package/dist/pack-authoring-node.mjs.map +1 -1
  18. package/dist/scanner.d.ts +3 -1
  19. package/dist/scanner.d.ts.map +1 -1
  20. package/dist/scanner.mjs +7 -3
  21. package/dist/scanner.mjs.map +1 -1
  22. package/package.json +2 -2
  23. package/src/__tests__/material-cook-receipt.unit.test.ts +9 -9
  24. package/src/__tests__/material-cook-schema.unit.test.ts +172 -21
  25. package/src/__tests__/material-declaration-boundary.unit.test.ts +35 -0
  26. package/src/__tests__/material-surface-consumer-census.test.ts +24 -0
  27. package/src/__tests__/material-surface-publication.unit.test.ts +162 -0
  28. package/src/__tests__/material-surface-wire.unit.test.ts +30 -0
  29. package/src/build.ts +2 -0
  30. package/src/evidence/material-cook.ts +183 -31
  31. package/src/index.ts +5 -0
  32. package/src/material-cook.ts +5 -0
  33. package/src/scanner.ts +7 -3
  34. package/src/schema/material-cook.schema.json +254 -50
  35. package/dist/__tests__/ai-recovery.unit.test.d.ts +0 -2
  36. package/dist/__tests__/ai-recovery.unit.test.d.ts.map +0 -1
  37. package/dist/__tests__/artifact-path.test.d.ts +0 -2
  38. package/dist/__tests__/artifact-path.test.d.ts.map +0 -1
  39. package/dist/__tests__/asset-evidence-error-hints.test.d.ts +0 -2
  40. package/dist/__tests__/asset-evidence-error-hints.test.d.ts.map +0 -1
  41. package/dist/__tests__/asset-evidence-lifecycle.test.d.ts +0 -2
  42. package/dist/__tests__/asset-evidence-lifecycle.test.d.ts.map +0 -1
  43. package/dist/__tests__/asset-evidence-schema.test.d.ts +0 -2
  44. package/dist/__tests__/asset-evidence-schema.test.d.ts.map +0 -1
  45. package/dist/__tests__/atlas-cli-region-mismatch.test.d.ts +0 -2
  46. package/dist/__tests__/atlas-cli-region-mismatch.test.d.ts.map +0 -1
  47. package/dist/__tests__/atlas-error-code-owner.test-d.d.ts +0 -2
  48. package/dist/__tests__/atlas-error-code-owner.test-d.d.ts.map +0 -1
  49. package/dist/__tests__/cli-asset-evidence.integration.test.d.ts +0 -2
  50. package/dist/__tests__/cli-asset-evidence.integration.test.d.ts.map +0 -1
  51. package/dist/__tests__/cli.unit.test.d.ts +0 -2
  52. package/dist/__tests__/cli.unit.test.d.ts.map +0 -1
  53. package/dist/__tests__/evidence-source-inventory.unit.test.d.ts +0 -2
  54. package/dist/__tests__/evidence-source-inventory.unit.test.d.ts.map +0 -1
  55. package/dist/__tests__/guid-collision.unit.test.d.ts +0 -2
  56. package/dist/__tests__/guid-collision.unit.test.d.ts.map +0 -1
  57. package/dist/__tests__/guid-validator-surface.unit.test.d.ts +0 -2
  58. package/dist/__tests__/guid-validator-surface.unit.test.d.ts.map +0 -1
  59. package/dist/__tests__/inventory-schema.test.d.ts +0 -2
  60. package/dist/__tests__/inventory-schema.test.d.ts.map +0 -1
  61. package/dist/__tests__/material-cook-dependencies.unit.test.d.ts +0 -2
  62. package/dist/__tests__/material-cook-dependencies.unit.test.d.ts.map +0 -1
  63. package/dist/__tests__/material-cook-receipt-layer-plan.unit.test.d.ts +0 -2
  64. package/dist/__tests__/material-cook-receipt-layer-plan.unit.test.d.ts.map +0 -1
  65. package/dist/__tests__/material-cook-receipt.unit.test.d.ts +0 -2
  66. package/dist/__tests__/material-cook-receipt.unit.test.d.ts.map +0 -1
  67. package/dist/__tests__/material-cook-schema.unit.test.d.ts +0 -2
  68. package/dist/__tests__/material-cook-schema.unit.test.d.ts.map +0 -1
  69. package/dist/__tests__/mesh-bin-consumer-surface.unit.test.d.ts +0 -2
  70. package/dist/__tests__/mesh-bin-consumer-surface.unit.test.d.ts.map +0 -1
  71. package/dist/__tests__/mesh-bin-contract.unit.test.d.ts +0 -2
  72. package/dist/__tests__/mesh-bin-contract.unit.test.d.ts.map +0 -1
  73. package/dist/__tests__/meta-schema-optional.test.d.ts +0 -2
  74. package/dist/__tests__/meta-schema-optional.test.d.ts.map +0 -1
  75. package/dist/__tests__/meta-source-overrides.unit.test.d.ts +0 -2
  76. package/dist/__tests__/meta-source-overrides.unit.test.d.ts.map +0 -1
  77. package/dist/__tests__/native-cooker-registry.test.d.ts +0 -2
  78. package/dist/__tests__/native-cooker-registry.test.d.ts.map +0 -1
  79. package/dist/__tests__/offline-evidence-artifact-verification-owner.test-d.d.ts +0 -2
  80. package/dist/__tests__/offline-evidence-artifact-verification-owner.test-d.d.ts.map +0 -1
  81. package/dist/__tests__/offline-evidence.integration.test.d.ts +0 -2
  82. package/dist/__tests__/offline-evidence.integration.test.d.ts.map +0 -1
  83. package/dist/__tests__/owner-chain.integration.test.d.ts +0 -2
  84. package/dist/__tests__/owner-chain.integration.test.d.ts.map +0 -1
  85. package/dist/__tests__/pack-authoring-gateway.unit.test.d.ts +0 -2
  86. package/dist/__tests__/pack-authoring-gateway.unit.test.d.ts.map +0 -1
  87. package/dist/__tests__/pack-authoring.unit.test.d.ts +0 -2
  88. package/dist/__tests__/pack-authoring.unit.test.d.ts.map +0 -1
  89. package/dist/__tests__/pack-scanner.unit.test.d.ts +0 -2
  90. package/dist/__tests__/pack-scanner.unit.test.d.ts.map +0 -1
  91. package/dist/__tests__/pack-v2-fixture-migration.test.d.ts +0 -2
  92. package/dist/__tests__/pack-v2-fixture-migration.test.d.ts.map +0 -1
  93. package/dist/__tests__/pack-v2-schema.test.d.ts +0 -2
  94. package/dist/__tests__/pack-v2-schema.test.d.ts.map +0 -1
  95. package/dist/__tests__/pack.unit.test.d.ts +0 -2
  96. package/dist/__tests__/pack.unit.test.d.ts.map +0 -1
  97. package/dist/__tests__/package-finalizer.contract.test.d.ts +0 -2
  98. package/dist/__tests__/package-finalizer.contract.test.d.ts.map +0 -1
  99. package/dist/__tests__/producer-contract-schema.unit.test.d.ts +0 -2
  100. package/dist/__tests__/producer-contract-schema.unit.test.d.ts.map +0 -1
  101. package/dist/__tests__/resolve-asset-source.test.d.ts +0 -2
  102. package/dist/__tests__/resolve-asset-source.test.d.ts.map +0 -1
  103. package/dist/__tests__/runtime-projection.unit.test.d.ts +0 -2
  104. package/dist/__tests__/runtime-projection.unit.test.d.ts.map +0 -1
  105. package/dist/__tests__/runtime.browser.test.d.ts +0 -2
  106. package/dist/__tests__/runtime.browser.test.d.ts.map +0 -1
  107. package/dist/__tests__/scanner-blacklist.test.d.ts +0 -2
  108. package/dist/__tests__/scanner-blacklist.test.d.ts.map +0 -1
  109. package/dist/__tests__/scanner-inventory.contract.test.d.ts +0 -2
  110. package/dist/__tests__/scanner-inventory.contract.test.d.ts.map +0 -1
  111. package/dist/__tests__/scanner-inventory.test.d.ts +0 -2
  112. package/dist/__tests__/scanner-inventory.test.d.ts.map +0 -1
  113. package/dist/__tests__/scanner-mount-cycle.test.d.ts +0 -2
  114. package/dist/__tests__/scanner-mount-cycle.test.d.ts.map +0 -1
  115. package/dist/__tests__/scriptable-pack-cli.integration.test.d.ts +0 -2
  116. package/dist/__tests__/scriptable-pack-cli.integration.test.d.ts.map +0 -1
  117. package/dist/__tests__/scriptable-pack-ddc-key.unit.test.d.ts +0 -2
  118. package/dist/__tests__/scriptable-pack-ddc-key.unit.test.d.ts.map +0 -1
  119. package/dist/__tests__/topology-actions.unit.test.d.ts +0 -2
  120. package/dist/__tests__/topology-actions.unit.test.d.ts.map +0 -1
  121. package/dist/__tests__/topology.unit.test.d.ts +0 -2
  122. package/dist/__tests__/topology.unit.test.d.ts.map +0 -1
@@ -1,2 +1,2 @@
1
- export { type CookedMaterialRecord, collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, type MaterialCookArtifact, type MaterialCookReceipt, type MaterialCookRecordError, type MaterialCookRefs, type MaterialCookWasmProvenance, materialLayerPlanIdentity, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord, } from './evidence/material-cook.js';
1
+ export { type CookedMaterialRecord, collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, createMaterialProgramSetDigest, type MaterialCookArtifact, type MaterialCookProgram, type MaterialCookProgramContext, type MaterialCookReceipt, type MaterialCookRecordError, type MaterialCookRefs, type MaterialCookWasmProvenance, materialLayerPlanIdentity, materialProgramContextKey, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord, validateMaterialCookProgramContext, } from './evidence/material-cook.js';
2
2
  //# sourceMappingURL=material-cook.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"material-cook.d.ts","sourceRoot":"","sources":["../src/material-cook.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EACzB,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,GAC7B,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"material-cook.d.ts","sourceRoot":"","sources":["../src/material-cook.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,oBAAoB,EACzB,uBAAuB,EACvB,4BAA4B,EAC5B,0BAA0B,EAC1B,8BAA8B,EAC9B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,mBAAmB,EACxB,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,0BAA0B,EAC/B,yBAAyB,EACzB,yBAAyB,EACzB,2BAA2B,EAC3B,6BAA6B,EAC7B,4BAA4B,EAC5B,4BAA4B,EAC5B,kCAAkC,GACnC,MAAM,6BAA6B,CAAC"}
@@ -106,7 +106,7 @@ function serializeMaterialCookReceipt(receipt) {
106
106
  function invalid(field, actual) {
107
107
  return err({
108
108
  code: "material-cook-record-invalid",
109
- expected: "a complete material-cook/3 record with layered identity and provenance",
109
+ expected: "a complete material-cook/4 record with layered identity and provenance",
110
110
  hint: "re-cook the material and publish its record, artifact, references, and receipt together",
111
111
  detail: {
112
112
  field,
@@ -115,6 +115,14 @@ function invalid(field, actual) {
115
115
  }
116
116
  });
117
117
  }
118
+ function normalizeArtifactBytes(value) {
119
+ if (Array.isArray(value)) {
120
+ return value.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255) ? Uint8Array.from(value) : void 0;
121
+ }
122
+ if (!ArrayBuffer.isView(value)) return void 0;
123
+ const view = value;
124
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength).slice();
125
+ }
118
126
  var IDENTITY_FIELDS = [
119
127
  "materialContractDigest",
120
128
  "sourceRevision",
@@ -159,7 +167,7 @@ function validateIdentity(value) {
159
167
  function validateMaterialCookReceipt(value, expected = {}) {
160
168
  if (value === null || typeof value !== "object") return invalid("receipt");
161
169
  const candidate = value;
162
- if (candidate.schemaVersion !== "material-cook/3")
170
+ if (candidate.schemaVersion !== "material-cook/4")
163
171
  return invalid("receipt.schemaVersion", candidate.schemaVersion);
164
172
  const identityResult = validateIdentity(candidate.identity);
165
173
  if (!identityResult.ok) return identityResult;
@@ -197,7 +205,7 @@ function validateMaterialCookReceipt(value, expected = {}) {
197
205
  return invalid("receipt.identity.cookIdentity", identity.cookIdentity);
198
206
  }
199
207
  return ok({
200
- schemaVersion: "material-cook/3",
208
+ schemaVersion: "material-cook/4",
201
209
  sourceClosure: candidate.sourceClosure,
202
210
  profile: candidate.profile,
203
211
  compilerVersion: candidate.compilerVersion,
@@ -211,7 +219,7 @@ function validateMaterialCookReceipt(value, expected = {}) {
211
219
  function validateCookedMaterialRecord(value) {
212
220
  if (value === null || typeof value !== "object") return invalid("record");
213
221
  const candidate = value;
214
- if (candidate.schemaVersion !== "material-cook/3")
222
+ if (candidate.schemaVersion !== "material-cook/4")
215
223
  return invalid("schemaVersion", candidate.schemaVersion);
216
224
  if (typeof candidate.guid !== "string" || !candidate.guid) return invalid("guid");
217
225
  if (candidate.materialGuid !== void 0 && typeof candidate.materialGuid !== "string")
@@ -220,6 +228,8 @@ function validateCookedMaterialRecord(value) {
220
228
  return invalid("publicationGeneration", candidate.publicationGeneration);
221
229
  if (candidate.specializationKey !== void 0 && typeof candidate.specializationKey !== "string")
222
230
  return invalid("specializationKey");
231
+ if ("artifact" in candidate || "variants" in candidate || "variantContext" in candidate)
232
+ return invalid("programs", "legacy single-artifact publication");
223
233
  if (candidate.artifactDigest !== void 0 && typeof candidate.artifactDigest !== "string")
224
234
  return invalid("artifactDigest");
225
235
  if (candidate.sourceClosure !== void 0 && (!Array.isArray(candidate.sourceClosure) || candidate.sourceClosure.some((path) => typeof path !== "string")))
@@ -236,24 +246,72 @@ function validateCookedMaterialRecord(value) {
236
246
  if (candidate.resolved === null || typeof candidate.resolved !== "object")
237
247
  return invalid("resolved");
238
248
  if (candidate.refs === null || typeof candidate.refs !== "object") return invalid("refs");
239
- if (candidate.artifact === null || typeof candidate.artifact !== "object")
240
- return invalid("artifact");
241
249
  if (candidate.receipt === null || typeof candidate.receipt !== "object")
242
250
  return invalid("receipt");
243
- const artifact = candidate.artifact;
244
- if (typeof artifact.digest !== "string" || !Array.isArray(artifact.bytes) && !ArrayBuffer.isView(artifact.bytes)) {
245
- return invalid("artifact");
246
- }
247
- const receiptResult = validateMaterialCookReceipt(candidate.receipt, {
248
- artifactDigest: artifact.digest
249
- });
250
- if (!receiptResult.ok) return receiptResult;
251
251
  const resolved = candidate.resolved;
252
252
  if (!Array.isArray(resolved.passes)) return invalid("resolved.passes", resolved.passes);
253
253
  if (!Array.isArray(resolved.parameters))
254
254
  return invalid("resolved.parameters", resolved.parameters);
255
255
  if (resolved.values === null || typeof resolved.values !== "object" || Array.isArray(resolved.values))
256
256
  return invalid("resolved.values", resolved.values);
257
+ const passes = resolved.passes;
258
+ const passNames = /* @__PURE__ */ new Set();
259
+ for (const [index, pass] of passes.entries()) {
260
+ if (pass === null || typeof pass !== "object" || typeof pass.name !== "string" || !pass.name || passNames.has(pass.name) || pass.program === null || typeof pass.program !== "object" || typeof pass.program.module !== "string")
261
+ return invalid(`resolved.passes[${index}]`);
262
+ passNames.add(pass.name);
263
+ }
264
+ if (!Array.isArray(candidate.programs) || candidate.programs.length === 0)
265
+ return invalid("programs");
266
+ const programs = [];
267
+ const programKeys = /* @__PURE__ */ new Set();
268
+ const selections = /* @__PURE__ */ new Set();
269
+ const selectedPasses = /* @__PURE__ */ new Set();
270
+ for (const [index, entry] of candidate.programs.entries()) {
271
+ const field = `programs[${index}]`;
272
+ if (entry === null || typeof entry !== "object") return invalid(field);
273
+ const program = entry;
274
+ if (typeof program.specializationKey !== "string" || !program.specializationKey || programKeys.has(program.specializationKey))
275
+ return invalid(`${field}.specializationKey`);
276
+ programKeys.add(program.specializationKey);
277
+ if (program.artifact === null || typeof program.artifact !== "object")
278
+ return invalid(`${field}.artifact`);
279
+ const artifact = program.artifact;
280
+ const bytes = normalizeArtifactBytes(artifact.bytes);
281
+ if (artifact.mediaType !== "text/wgsl" || typeof artifact.path !== "string" || !artifact.path || typeof artifact.digest !== "string" || !artifact.digest || bytes === void 0)
282
+ return invalid(`${field}.artifact`);
283
+ if (!Array.isArray(program.selections) || program.selections.length === 0)
284
+ return invalid(`${field}.selections`);
285
+ const programSelections = [];
286
+ for (const [selectionIndex, selection] of program.selections.entries()) {
287
+ const selectionField = `${field}.selections[${selectionIndex}]`;
288
+ if (selection === null || typeof selection !== "object" || !passNames.has(selection.pass))
289
+ return invalid(selectionField);
290
+ const context = validateMaterialCookProgramContext(selection.context);
291
+ if (!context.ok)
292
+ return invalid(
293
+ `${selectionField}.${context.error.detail.field}`,
294
+ context.error.detail.actual
295
+ );
296
+ const key = JSON.stringify([selection.pass, materialProgramContextKey(context.value)]);
297
+ if (selections.has(key)) return invalid(selectionField, "ambiguous Pass/context selection");
298
+ selections.add(key);
299
+ selectedPasses.add(selection.pass);
300
+ programSelections.push({ pass: selection.pass, context: context.value });
301
+ }
302
+ programs.push({
303
+ specializationKey: program.specializationKey,
304
+ artifact: { mediaType: "text/wgsl", path: artifact.path, digest: artifact.digest, bytes },
305
+ selections: programSelections
306
+ });
307
+ }
308
+ if ([...passNames].some((pass) => !selectedPasses.has(pass)))
309
+ return invalid("programs.selections", "unpublished Pass");
310
+ const manifestDigest = createMaterialProgramSetDigest(programs, passes);
311
+ const receiptResult = validateMaterialCookReceipt(candidate.receipt, {
312
+ artifactDigest: manifestDigest
313
+ });
314
+ if (!receiptResult.ok) return receiptResult;
257
315
  let expectedLayerPlanIdentity;
258
316
  try {
259
317
  expectedLayerPlanIdentity = materialLayerPlanIdentity({
@@ -268,30 +326,71 @@ function validateCookedMaterialRecord(value) {
268
326
  receiptResult.value.derivedInterface.layerPlanIdentity
269
327
  );
270
328
  }
271
- if (candidate.artifactDigest !== void 0 && candidate.artifactDigest !== artifact.digest)
329
+ if (candidate.artifactDigest !== void 0 && candidate.artifactDigest !== manifestDigest)
272
330
  return invalid("artifactDigest", candidate.artifactDigest);
273
331
  if (candidate.publicationGeneration !== void 0 && receiptResult.value.identity.cookGeneration !== candidate.publicationGeneration)
274
332
  return invalid("receipt.identity.cookGeneration", receiptResult.value.identity.cookGeneration);
275
- const normalized = {
333
+ return ok({
276
334
  ...candidate,
277
- artifact: {
278
- ...artifact,
279
- bytes: ArrayBuffer.isView(artifact.bytes) ? Uint8Array.from(artifact.bytes) : Uint8Array.from(artifact.bytes)
280
- },
335
+ programs,
281
336
  receipt: receiptResult.value
282
- };
283
- return ok(normalized);
337
+ });
284
338
  }
285
339
  function projectCookedMaterialRecord(record) {
286
340
  return {
287
341
  resolved: record.resolved,
288
342
  refs: record.refs,
289
- artifact: record.artifact,
343
+ programs: record.programs,
290
344
  receipt: record.receipt,
291
345
  schemaVersion: record.schemaVersion
292
346
  };
293
347
  }
348
+ function materialProgramContextKey(context) {
349
+ return JSON.stringify(jsonValue(context));
350
+ }
351
+ function validateMaterialCookProgramContext(value) {
352
+ if (value === null || typeof value !== "object" || Array.isArray(value))
353
+ return invalid("context", value);
354
+ const context = value;
355
+ const fields = {
356
+ backend: ["webgpu", "webgl2", "wgpu-native"],
357
+ capability: ["storage-buffer", "uniform-fallback"],
358
+ pipeline: ["forward", "deferred"],
359
+ geometry: ["mesh", "skinned", "sprite"],
360
+ pass: ["forward", "shadow", "depth"],
361
+ profile: ["forgeax-material-wgsl-v1"],
362
+ toolchain: ["naga-oil"],
363
+ instrumentation: ["none", "validation"]
364
+ };
365
+ for (const field of Object.keys(context)) {
366
+ if (!(field in fields)) return invalid(`context.${field}`, context[field]);
367
+ }
368
+ for (const [field, allowed] of Object.entries(fields)) {
369
+ if (!allowed.includes(context[field]))
370
+ return invalid(`context.${field}`, context[field]);
371
+ }
372
+ return ok({ ...context });
373
+ }
374
+ function createMaterialProgramSetDigest(programs, passes) {
375
+ const manifest = {
376
+ passes,
377
+ programs: programs.map((program) => ({
378
+ specializationKey: program.specializationKey,
379
+ artifact: {
380
+ path: program.artifact.path,
381
+ mediaType: program.artifact.mediaType,
382
+ digest: program.artifact.digest
383
+ },
384
+ selections: [...program.selections].sort(
385
+ (a, b) => JSON.stringify(jsonValue(a)).localeCompare(JSON.stringify(jsonValue(b)))
386
+ )
387
+ })).sort((a, b) => a.specializationKey.localeCompare(b.specializationKey))
388
+ };
389
+ return createMaterialArtifactDigest(
390
+ new TextEncoder().encode(JSON.stringify(jsonValue(manifest)))
391
+ );
392
+ }
294
393
 
295
- export { collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, materialLayerPlanIdentity, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord };
394
+ export { collectMaterialCookRefs, createMaterialArtifactDigest, createMaterialCookIdentity, createMaterialProgramSetDigest, materialLayerPlanIdentity, materialProgramContextKey, projectCookedMaterialRecord, serializeCookedMaterialRecord, serializeMaterialCookReceipt, validateCookedMaterialRecord, validateMaterialCookProgramContext };
296
395
  //# sourceMappingURL=material-cook.mjs.map
297
396
  //# sourceMappingURL=material-cook.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/evidence/material-cook.ts"],"names":[],"mappings":"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","file":"material-cook.mjs","sourcesContent":["import type {\n MaterialAsset,\n MaterialParameter,\n MaterialPass,\n MaterialTextureReference,\n MaterialTextureValue,\n MaterialValue,\n Result,\n} from '@forgeax/engine-types';\nimport { deriveStandardLayerPlan, err, MATERIAL_TEXTURE_SLOTS, ok } from '@forgeax/engine-types';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport { bytesToHex } from '@noble/hashes/utils.js';\n\nexport interface MaterialCookRefs {\n readonly parent: readonly string[];\n readonly textures: readonly string[];\n readonly samplers: readonly string[];\n readonly modules: readonly string[];\n}\n\nexport interface MaterialCookArtifact {\n readonly mediaType: string;\n readonly path: string;\n readonly digest: string;\n readonly bytes: Uint8Array;\n}\n\nexport interface MaterialCookWasmProvenance {\n readonly sourceContentKey: string;\n readonly artifactSha256: string;\n readonly glueSha256: string;\n}\n\nexport interface MaterialCookIdentity {\n readonly materialContractDigest: string;\n readonly sourceRevision: string;\n readonly sourceClosureDigest: string;\n readonly layoutIdentity: string;\n readonly programIdentity: string;\n readonly pipelineIdentity: string;\n readonly materialPublicationIdentity: string;\n readonly cookIdentity: string;\n readonly compilerFingerprint: string;\n readonly wasm: MaterialCookWasmProvenance;\n readonly artifactDigest: string;\n readonly valueGeneration: number;\n readonly dependencyGeneration: number;\n readonly cookGeneration: number;\n}\n\nexport type MaterialCookIdentityInput = Omit<MaterialCookIdentity, 'cookIdentity'>;\n\nexport interface MaterialCookReceipt {\n readonly schemaVersion: 'material-cook/3';\n readonly sourceClosure: readonly string[];\n readonly profile: string;\n readonly compilerVersion: string;\n readonly identity: MaterialCookIdentity;\n readonly derivedInterface: {\n readonly layoutIdentity: string;\n /** Build-time Standard physical lowering identity, when the root is Standard. */\n readonly layerPlanIdentity?: string;\n };\n}\n\nexport interface MaterialParameterContract {\n readonly parameters: readonly MaterialParameter[];\n readonly values: Readonly<Record<string, MaterialValue | null>>;\n}\n\nexport interface CookedMaterialRecord {\n readonly schemaVersion: 'material-cook/3';\n readonly guid: string;\n readonly authored?: MaterialAsset;\n readonly materialGuid?: string;\n readonly publicationGeneration?: number;\n readonly specializationKey?: string;\n readonly artifactDigest?: string;\n readonly sourceClosure?: readonly string[];\n readonly parameterContract?: MaterialParameterContract;\n readonly resolved: {\n readonly passes: readonly MaterialPass[];\n readonly parameters: readonly MaterialParameter[];\n readonly values: Readonly<Record<string, MaterialValue | null>>;\n };\n readonly refs: MaterialCookRefs;\n readonly artifact: MaterialCookArtifact;\n readonly receipt: MaterialCookReceipt;\n}\n\nexport interface MaterialCookRecordError {\n readonly code: 'material-cook-record-invalid';\n readonly expected: string;\n readonly hint: string;\n readonly detail: {\n readonly field: string;\n readonly actual?: unknown;\n readonly action: string;\n };\n}\n\nexport interface MaterialCookIdentityExpectation {\n readonly layoutIdentity?: string;\n readonly artifactDigest?: string;\n readonly inputDigest?: string;\n}\n\nconst STANDARD_ROOT_MODULES = new Set([\n 'forgeax::default-standard-pbr',\n 'forgeax::pbr-skin',\n 'forgeax_material::standard',\n 'forgeax_material::pbr-skin',\n]);\n\n/** Shared ownership predicate for the built-in Standard material root. */\nexport function isStandardRootModule(module: string): boolean {\n return STANDARD_ROOT_MODULES.has(module);\n}\n\nexport function isStandardMaterialRecord(record: Pick<CookedMaterialRecord, 'resolved'>): boolean {\n return record.resolved.passes.some((pass) => isStandardRootModule(pass.program.module));\n}\n\n/**\n * Recompute the Standard layer identity from the admitted resolved root.\n * Material admission and runtime loading share this owner so a stale receipt\n * cannot select a different physical layer plan after cooking.\n */\nexport function materialLayerPlanIdentity(\n record: Pick<CookedMaterialRecord, 'resolved'>,\n): string | undefined {\n if (!isStandardMaterialRecord(record)) {\n return undefined;\n }\n return deriveStandardLayerPlan(record.resolved.parameters, record.resolved.passes).identity;\n}\n\nfunction unique(values: readonly string[]): readonly string[] {\n return [...new Set(values)].sort();\n}\n\nfunction guidText(value: string | Uint8Array): string {\n return typeof value === 'string'\n ? value\n : Array.from(value, (byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nfunction cookGuidText(value: MaterialTextureReference): string | undefined {\n return typeof value === 'number' ? undefined : guidText(value);\n}\n\nfunction textureValues(\n values: Readonly<Record<string, MaterialValue | null>> | undefined,\n textureFields: ReadonlySet<string>,\n): readonly MaterialTextureValue[] {\n return Object.entries(values ?? {}).flatMap(([name, value]) => {\n if (value === null) return [];\n if (typeof value === 'string') {\n return textureFields.has(name) ? [{ texture: value }] : [];\n }\n return value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n 'texture' in value\n ? [value as MaterialTextureValue]\n : [];\n });\n}\n\nexport function collectMaterialCookRefs(material: Partial<MaterialAsset>): MaterialCookRefs {\n const textureFields =\n material.parameters === undefined\n ? new Set<string>(MATERIAL_TEXTURE_SLOTS)\n : new Set(\n material.parameters\n .filter(\n (parameter) => parameter.type === 'texture' || parameter.type === 'texture_cube',\n )\n .map((parameter) => parameter.name),\n );\n const textures = textureValues(material.values, textureFields);\n return {\n parent: material.parent ? [guidText(material.parent)] : [],\n textures: unique(\n textures.flatMap((value) => {\n const guid = cookGuidText(value.texture);\n return guid === undefined ? [] : [guid];\n }),\n ),\n samplers: unique(\n textures.flatMap((value) => {\n if (value.sampler === undefined) return [];\n const guid = cookGuidText(value.sampler);\n return guid === undefined ? [] : [guid];\n }),\n ),\n modules: unique((material.passes ?? []).map((pass) => pass.program.module)),\n };\n}\n\nexport function createMaterialArtifactDigest(bytes: Uint8Array): string {\n return `sha256:${bytesToHex(sha256(bytes))}`;\n}\n\nfunction jsonValue(value: unknown): unknown {\n if (value instanceof Uint8Array) return [...value];\n if (Array.isArray(value)) return value.map(jsonValue);\n if (value !== null && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, entry]) => entry !== undefined)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, entry]) => [key, jsonValue(entry)]),\n );\n }\n return value;\n}\n\nexport function createMaterialCookIdentity(input: MaterialCookIdentityInput): MaterialCookIdentity {\n const cookIdentity = createMaterialArtifactDigest(\n new TextEncoder().encode(\n JSON.stringify(\n jsonValue({\n materialContractDigest: input.materialContractDigest,\n sourceRevision: input.sourceRevision,\n sourceClosureDigest: input.sourceClosureDigest,\n layoutIdentity: input.layoutIdentity,\n programIdentity: input.programIdentity,\n pipelineIdentity: input.pipelineIdentity,\n compilerFingerprint: input.compilerFingerprint,\n wasm: input.wasm,\n artifactDigest: input.artifactDigest,\n }),\n ),\n ),\n );\n return { ...input, cookIdentity };\n}\n\nexport function serializeCookedMaterialRecord(record: CookedMaterialRecord): string {\n return JSON.stringify(jsonValue(record));\n}\n\nexport function serializeMaterialCookReceipt(receipt: MaterialCookReceipt): string {\n return JSON.stringify(jsonValue({ ...receipt, sourceClosure: unique(receipt.sourceClosure) }));\n}\n\nfunction invalid(field: string, actual?: unknown): Result<never, MaterialCookRecordError> {\n return err({\n code: 'material-cook-record-invalid',\n expected: 'a complete material-cook/3 record with layered identity and provenance',\n hint: 're-cook the material and publish its record, artifact, references, and receipt together',\n detail: {\n field,\n ...(actual === undefined ? {} : { actual }),\n action: 'inspect the named field and recook the material generation',\n },\n });\n}\n\nconst IDENTITY_FIELDS = [\n 'materialContractDigest',\n 'sourceRevision',\n 'sourceClosureDigest',\n 'layoutIdentity',\n 'programIdentity',\n 'pipelineIdentity',\n 'materialPublicationIdentity',\n 'cookIdentity',\n 'compilerFingerprint',\n 'artifactDigest',\n] as const;\n\nfunction isGeneration(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 1;\n}\n\nfunction validateIdentity(value: unknown): Result<MaterialCookIdentity, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('receipt.identity', value);\n const candidate = value as Record<string, unknown>;\n for (const field of IDENTITY_FIELDS) {\n if (typeof candidate[field] !== 'string' || candidate[field].length === 0) {\n return invalid(`receipt.identity.${field}`, candidate[field]);\n }\n }\n if (candidate.wasm === null || typeof candidate.wasm !== 'object') {\n return invalid('receipt.identity.wasm', candidate.wasm);\n }\n const wasm = candidate.wasm as Record<string, unknown>;\n for (const field of ['sourceContentKey', 'artifactSha256', 'glueSha256']) {\n if (typeof wasm[field] !== 'string' || wasm[field].length === 0) {\n return invalid(`receipt.identity.wasm.${field}`, wasm[field]);\n }\n }\n for (const field of ['valueGeneration', 'dependencyGeneration', 'cookGeneration']) {\n if (!isGeneration(candidate[field]))\n return invalid(`receipt.identity.${field}`, candidate[field]);\n }\n return ok({\n ...candidate,\n wasm: wasm as unknown as MaterialCookWasmProvenance,\n } as MaterialCookIdentity);\n}\n\nexport function validateMaterialCookReceipt(\n value: unknown,\n expected: MaterialCookIdentityExpectation = {},\n): Result<MaterialCookReceipt, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('receipt');\n const candidate = value as Record<string, unknown>;\n if (candidate.schemaVersion !== 'material-cook/3')\n return invalid('receipt.schemaVersion', candidate.schemaVersion);\n const identityResult = validateIdentity(candidate.identity);\n if (!identityResult.ok) return identityResult;\n const identity = identityResult.value;\n if (candidate.derivedInterface === null || typeof candidate.derivedInterface !== 'object') {\n return invalid('receipt.derivedInterface', candidate.derivedInterface);\n }\n const derivedInterface = candidate.derivedInterface as Record<string, unknown>;\n if (derivedInterface.layoutIdentity !== identity.layoutIdentity) {\n return invalid('receipt.derivedInterface.layoutIdentity', derivedInterface.layoutIdentity);\n }\n if (\n derivedInterface.layerPlanIdentity !== undefined &&\n (typeof derivedInterface.layerPlanIdentity !== 'string' ||\n derivedInterface.layerPlanIdentity.length === 0)\n ) {\n return invalid(\n 'receipt.derivedInterface.layerPlanIdentity',\n derivedInterface.layerPlanIdentity,\n );\n }\n for (const field of ['sourceClosure', 'profile', 'compilerVersion']) {\n const fieldValue = candidate[field];\n if (\n (field === 'sourceClosure' && !Array.isArray(fieldValue)) ||\n (field !== 'sourceClosure' && typeof fieldValue !== 'string')\n ) {\n return invalid(`receipt.${field}`, fieldValue);\n }\n }\n const sourceClosure = candidate.sourceClosure;\n if (Array.isArray(sourceClosure) && sourceClosure.some((path) => typeof path !== 'string')) {\n return invalid('receipt.sourceClosure', sourceClosure);\n }\n if (\n expected.layoutIdentity !== undefined &&\n identity.layoutIdentity !== expected.layoutIdentity\n ) {\n return invalid('receipt.identity.layoutIdentity', identity.layoutIdentity);\n }\n if (\n expected.artifactDigest !== undefined &&\n identity.artifactDigest !== expected.artifactDigest\n ) {\n return invalid('receipt.identity.artifactDigest', identity.artifactDigest);\n }\n if (expected.inputDigest !== undefined && identity.cookIdentity !== expected.inputDigest) {\n return invalid('receipt.identity.cookIdentity', identity.cookIdentity);\n }\n return ok({\n schemaVersion: 'material-cook/3',\n sourceClosure: candidate.sourceClosure as string[],\n profile: candidate.profile as string,\n compilerVersion: candidate.compilerVersion as string,\n identity,\n derivedInterface: {\n layoutIdentity: derivedInterface.layoutIdentity as string,\n ...(derivedInterface.layerPlanIdentity === undefined\n ? {}\n : { layerPlanIdentity: derivedInterface.layerPlanIdentity as string }),\n },\n });\n}\n\nexport function validateCookedMaterialRecord(\n value: unknown,\n): Result<CookedMaterialRecord, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('record');\n const candidate = value as Record<string, unknown>;\n if (candidate.schemaVersion !== 'material-cook/3')\n return invalid('schemaVersion', candidate.schemaVersion);\n if (typeof candidate.guid !== 'string' || !candidate.guid) return invalid('guid');\n if (candidate.materialGuid !== undefined && typeof candidate.materialGuid !== 'string')\n return invalid('materialGuid');\n if (\n candidate.publicationGeneration !== undefined &&\n !isGeneration(candidate.publicationGeneration)\n )\n return invalid('publicationGeneration', candidate.publicationGeneration);\n if (candidate.specializationKey !== undefined && typeof candidate.specializationKey !== 'string')\n return invalid('specializationKey');\n if (candidate.artifactDigest !== undefined && typeof candidate.artifactDigest !== 'string')\n return invalid('artifactDigest');\n if (\n candidate.sourceClosure !== undefined &&\n (!Array.isArray(candidate.sourceClosure) ||\n candidate.sourceClosure.some((path) => typeof path !== 'string'))\n )\n return invalid('sourceClosure');\n if (candidate.parameterContract !== undefined) {\n if (candidate.parameterContract === null || typeof candidate.parameterContract !== 'object')\n return invalid('parameterContract');\n const parameterContract = candidate.parameterContract as Record<string, unknown>;\n if (!Array.isArray(parameterContract.parameters))\n return invalid('parameterContract.parameters');\n if (\n parameterContract.values === null ||\n typeof parameterContract.values !== 'object' ||\n Array.isArray(parameterContract.values)\n )\n return invalid('parameterContract.values');\n }\n if (candidate.resolved === null || typeof candidate.resolved !== 'object')\n return invalid('resolved');\n if (candidate.refs === null || typeof candidate.refs !== 'object') return invalid('refs');\n if (candidate.artifact === null || typeof candidate.artifact !== 'object')\n return invalid('artifact');\n if (candidate.receipt === null || typeof candidate.receipt !== 'object')\n return invalid('receipt');\n const artifact = candidate.artifact as Record<string, unknown>;\n if (\n typeof artifact.digest !== 'string' ||\n (!Array.isArray(artifact.bytes) && !ArrayBuffer.isView(artifact.bytes))\n ) {\n return invalid('artifact');\n }\n const receiptResult = validateMaterialCookReceipt(candidate.receipt, {\n artifactDigest: artifact.digest as string,\n });\n if (!receiptResult.ok) return receiptResult;\n const resolved = candidate.resolved as Record<string, unknown>;\n if (!Array.isArray(resolved.passes)) return invalid('resolved.passes', resolved.passes);\n if (!Array.isArray(resolved.parameters))\n return invalid('resolved.parameters', resolved.parameters);\n if (\n resolved.values === null ||\n typeof resolved.values !== 'object' ||\n Array.isArray(resolved.values)\n )\n return invalid('resolved.values', resolved.values);\n let expectedLayerPlanIdentity: string | undefined;\n try {\n expectedLayerPlanIdentity = materialLayerPlanIdentity({\n resolved: resolved as unknown as CookedMaterialRecord['resolved'],\n });\n } catch (error) {\n return invalid('resolved.layerPlanIdentity', error instanceof Error ? error.message : error);\n }\n if (\n expectedLayerPlanIdentity !== undefined &&\n receiptResult.value.derivedInterface.layerPlanIdentity !== expectedLayerPlanIdentity\n ) {\n return invalid(\n 'receipt.derivedInterface.layerPlanIdentity',\n receiptResult.value.derivedInterface.layerPlanIdentity,\n );\n }\n if (candidate.artifactDigest !== undefined && candidate.artifactDigest !== artifact.digest)\n return invalid('artifactDigest', candidate.artifactDigest);\n if (\n candidate.publicationGeneration !== undefined &&\n receiptResult.value.identity.cookGeneration !== candidate.publicationGeneration\n )\n return invalid('receipt.identity.cookGeneration', receiptResult.value.identity.cookGeneration);\n const normalized = {\n ...candidate,\n artifact: {\n ...artifact,\n bytes: ArrayBuffer.isView(artifact.bytes)\n ? Uint8Array.from(artifact.bytes as Uint8Array)\n : Uint8Array.from(artifact.bytes as number[]),\n },\n receipt: receiptResult.value,\n } as CookedMaterialRecord;\n return ok(normalized);\n}\n\nexport function projectCookedMaterialRecord(\n record: CookedMaterialRecord,\n): Omit<CookedMaterialRecord, 'guid' | 'authored'> {\n return {\n resolved: record.resolved,\n refs: record.refs,\n artifact: record.artifact,\n receipt: record.receipt,\n schemaVersion: record.schemaVersion,\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/evidence/material-cook.ts"],"names":[],"mappings":"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","file":"material-cook.mjs","sourcesContent":["import type {\n MaterialAsset,\n MaterialParameter,\n MaterialPass,\n MaterialTextureReference,\n MaterialTextureValue,\n MaterialValue,\n Result,\n} from '@forgeax/engine-types';\nimport { deriveStandardLayerPlan, err, MATERIAL_TEXTURE_SLOTS, ok } from '@forgeax/engine-types';\nimport { sha256 } from '@noble/hashes/sha2.js';\nimport { bytesToHex } from '@noble/hashes/utils.js';\n\nexport interface MaterialCookRefs {\n readonly parent: readonly string[];\n readonly textures: readonly string[];\n readonly samplers: readonly string[];\n readonly modules: readonly string[];\n}\n\nexport interface MaterialCookArtifact {\n readonly mediaType: string;\n readonly path: string;\n readonly digest: string;\n readonly bytes: Uint8Array;\n}\n\n/** Domain-owned inputs used to compile and select a material program. */\nexport interface MaterialCookProgramContext {\n readonly backend: 'webgpu' | 'webgl2' | 'wgpu-native';\n readonly capability: 'storage-buffer' | 'uniform-fallback';\n readonly pipeline: 'forward' | 'deferred';\n readonly geometry: 'mesh' | 'skinned' | 'sprite';\n readonly pass: 'forward' | 'shadow' | 'depth';\n readonly profile: 'forgeax-material-wgsl-v1';\n readonly toolchain: 'naga-oil';\n readonly instrumentation: 'none' | 'validation';\n}\n\n/** Programs are derived artifacts, never independently authored assets. */\nexport interface MaterialCookProgram {\n readonly specializationKey: string;\n readonly artifact: MaterialCookArtifact;\n readonly selections: readonly {\n readonly pass: string;\n readonly context: MaterialCookProgramContext;\n }[];\n}\n\nexport interface MaterialCookWasmProvenance {\n readonly sourceContentKey: string;\n readonly artifactSha256: string;\n readonly glueSha256: string;\n}\n\nexport interface MaterialCookIdentity {\n readonly materialContractDigest: string;\n readonly sourceRevision: string;\n readonly sourceClosureDigest: string;\n readonly layoutIdentity: string;\n readonly programIdentity: string;\n readonly pipelineIdentity: string;\n readonly materialPublicationIdentity: string;\n readonly cookIdentity: string;\n readonly compilerFingerprint: string;\n readonly wasm: MaterialCookWasmProvenance;\n readonly artifactDigest: string;\n readonly valueGeneration: number;\n readonly dependencyGeneration: number;\n readonly cookGeneration: number;\n}\n\nexport type MaterialCookIdentityInput = Omit<MaterialCookIdentity, 'cookIdentity'>;\n\nexport interface MaterialCookReceipt {\n readonly schemaVersion: 'material-cook/4';\n readonly sourceClosure: readonly string[];\n readonly profile: string;\n readonly compilerVersion: string;\n readonly identity: MaterialCookIdentity;\n readonly derivedInterface: {\n readonly layoutIdentity: string;\n /** Build-time Standard physical lowering identity, when the root is Standard. */\n readonly layerPlanIdentity?: string;\n };\n}\n\nexport interface MaterialParameterContract {\n readonly parameters: readonly MaterialParameter[];\n readonly values: Readonly<Record<string, MaterialValue | null>>;\n}\n\nexport interface CookedMaterialRecord {\n readonly schemaVersion: 'material-cook/4';\n readonly guid: string;\n readonly authored?: MaterialAsset;\n readonly materialGuid?: string;\n readonly publicationGeneration?: number;\n readonly specializationKey?: string;\n readonly programs: readonly MaterialCookProgram[];\n /** Digest of the complete program/Pass/context manifest. */\n readonly artifactDigest?: string;\n readonly sourceClosure?: readonly string[];\n readonly parameterContract?: MaterialParameterContract;\n readonly resolved: {\n readonly passes: readonly MaterialPass[];\n readonly parameters: readonly MaterialParameter[];\n readonly values: Readonly<Record<string, MaterialValue | null>>;\n };\n readonly refs: MaterialCookRefs;\n readonly receipt: MaterialCookReceipt;\n}\n\nexport interface MaterialCookRecordError {\n readonly code: 'material-cook-record-invalid';\n readonly expected: string;\n readonly hint: string;\n readonly detail: {\n readonly field: string;\n readonly actual?: unknown;\n readonly action: string;\n };\n}\n\nexport interface MaterialCookIdentityExpectation {\n readonly layoutIdentity?: string;\n readonly artifactDigest?: string;\n readonly inputDigest?: string;\n}\n\nconst STANDARD_ROOT_MODULES = new Set([\n 'forgeax::default-standard-pbr',\n 'forgeax::pbr-skin',\n 'forgeax_material::standard',\n 'forgeax_material::pbr-skin',\n]);\n\n/** Shared ownership predicate for the built-in Standard material root. */\nexport function isStandardRootModule(module: string): boolean {\n return STANDARD_ROOT_MODULES.has(module);\n}\n\nexport function isStandardMaterialRecord(record: Pick<CookedMaterialRecord, 'resolved'>): boolean {\n return record.resolved.passes.some((pass) => isStandardRootModule(pass.program.module));\n}\n\n/**\n * Recompute the Standard layer identity from the admitted resolved root.\n * Material admission and runtime loading share this owner so a stale receipt\n * cannot select a different physical layer plan after cooking.\n */\nexport function materialLayerPlanIdentity(\n record: Pick<CookedMaterialRecord, 'resolved'>,\n): string | undefined {\n if (!isStandardMaterialRecord(record)) {\n return undefined;\n }\n return deriveStandardLayerPlan(record.resolved.parameters, record.resolved.passes).identity;\n}\n\nfunction unique(values: readonly string[]): readonly string[] {\n return [...new Set(values)].sort();\n}\n\nfunction guidText(value: string | Uint8Array): string {\n return typeof value === 'string'\n ? value\n : Array.from(value, (byte) => byte.toString(16).padStart(2, '0')).join('');\n}\n\nfunction cookGuidText(value: MaterialTextureReference): string | undefined {\n return typeof value === 'number' ? undefined : guidText(value);\n}\n\nfunction textureValues(\n values: Readonly<Record<string, MaterialValue | null>> | undefined,\n textureFields: ReadonlySet<string>,\n): readonly MaterialTextureValue[] {\n return Object.entries(values ?? {}).flatMap(([name, value]) => {\n if (value === null) return [];\n if (typeof value === 'string') {\n return textureFields.has(name) ? [{ texture: value }] : [];\n }\n return value !== null &&\n typeof value === 'object' &&\n !Array.isArray(value) &&\n 'texture' in value\n ? [value as MaterialTextureValue]\n : [];\n });\n}\n\nexport function collectMaterialCookRefs(material: Partial<MaterialAsset>): MaterialCookRefs {\n const textureFields =\n material.parameters === undefined\n ? new Set<string>(MATERIAL_TEXTURE_SLOTS)\n : new Set(\n material.parameters\n .filter(\n (parameter) => parameter.type === 'texture' || parameter.type === 'texture_cube',\n )\n .map((parameter) => parameter.name),\n );\n const textures = textureValues(material.values, textureFields);\n return {\n parent: material.parent ? [guidText(material.parent)] : [],\n textures: unique(\n textures.flatMap((value) => {\n const guid = cookGuidText(value.texture);\n return guid === undefined ? [] : [guid];\n }),\n ),\n samplers: unique(\n textures.flatMap((value) => {\n if (value.sampler === undefined) return [];\n const guid = cookGuidText(value.sampler);\n return guid === undefined ? [] : [guid];\n }),\n ),\n modules: unique((material.passes ?? []).map((pass) => pass.program.module)),\n };\n}\n\nexport function createMaterialArtifactDigest(bytes: Uint8Array): string {\n return `sha256:${bytesToHex(sha256(bytes))}`;\n}\n\nfunction jsonValue(value: unknown): unknown {\n if (value instanceof Uint8Array) return [...value];\n if (Array.isArray(value)) return value.map(jsonValue);\n if (value !== null && typeof value === 'object') {\n return Object.fromEntries(\n Object.entries(value)\n .filter(([, entry]) => entry !== undefined)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, entry]) => [key, jsonValue(entry)]),\n );\n }\n return value;\n}\n\nexport function createMaterialCookIdentity(input: MaterialCookIdentityInput): MaterialCookIdentity {\n const cookIdentity = createMaterialArtifactDigest(\n new TextEncoder().encode(\n JSON.stringify(\n jsonValue({\n materialContractDigest: input.materialContractDigest,\n sourceRevision: input.sourceRevision,\n sourceClosureDigest: input.sourceClosureDigest,\n layoutIdentity: input.layoutIdentity,\n programIdentity: input.programIdentity,\n pipelineIdentity: input.pipelineIdentity,\n compilerFingerprint: input.compilerFingerprint,\n wasm: input.wasm,\n artifactDigest: input.artifactDigest,\n }),\n ),\n ),\n );\n return { ...input, cookIdentity };\n}\n\nexport function serializeCookedMaterialRecord(record: CookedMaterialRecord): string {\n return JSON.stringify(jsonValue(record));\n}\n\nexport function serializeMaterialCookReceipt(receipt: MaterialCookReceipt): string {\n return JSON.stringify(jsonValue({ ...receipt, sourceClosure: unique(receipt.sourceClosure) }));\n}\n\nfunction invalid(field: string, actual?: unknown): Result<never, MaterialCookRecordError> {\n return err({\n code: 'material-cook-record-invalid',\n expected: 'a complete material-cook/4 record with layered identity and provenance',\n hint: 're-cook the material and publish its record, artifact, references, and receipt together',\n detail: {\n field,\n ...(actual === undefined ? {} : { actual }),\n action: 'inspect the named field and recook the material generation',\n },\n });\n}\n\nfunction normalizeArtifactBytes(value: unknown): Uint8Array | undefined {\n if (Array.isArray(value)) {\n return value.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255)\n ? Uint8Array.from(value)\n : undefined;\n }\n if (!ArrayBuffer.isView(value)) return undefined;\n const view = value as ArrayBufferView;\n return new Uint8Array(view.buffer, view.byteOffset, view.byteLength).slice();\n}\n\nconst IDENTITY_FIELDS = [\n 'materialContractDigest',\n 'sourceRevision',\n 'sourceClosureDigest',\n 'layoutIdentity',\n 'programIdentity',\n 'pipelineIdentity',\n 'materialPublicationIdentity',\n 'cookIdentity',\n 'compilerFingerprint',\n 'artifactDigest',\n] as const;\n\nfunction isGeneration(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 1;\n}\n\nfunction validateIdentity(value: unknown): Result<MaterialCookIdentity, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('receipt.identity', value);\n const candidate = value as Record<string, unknown>;\n for (const field of IDENTITY_FIELDS) {\n if (typeof candidate[field] !== 'string' || candidate[field].length === 0) {\n return invalid(`receipt.identity.${field}`, candidate[field]);\n }\n }\n if (candidate.wasm === null || typeof candidate.wasm !== 'object') {\n return invalid('receipt.identity.wasm', candidate.wasm);\n }\n const wasm = candidate.wasm as Record<string, unknown>;\n for (const field of ['sourceContentKey', 'artifactSha256', 'glueSha256']) {\n if (typeof wasm[field] !== 'string' || wasm[field].length === 0) {\n return invalid(`receipt.identity.wasm.${field}`, wasm[field]);\n }\n }\n for (const field of ['valueGeneration', 'dependencyGeneration', 'cookGeneration']) {\n if (!isGeneration(candidate[field]))\n return invalid(`receipt.identity.${field}`, candidate[field]);\n }\n return ok({\n ...candidate,\n wasm: wasm as unknown as MaterialCookWasmProvenance,\n } as MaterialCookIdentity);\n}\n\nexport function validateMaterialCookReceipt(\n value: unknown,\n expected: MaterialCookIdentityExpectation = {},\n): Result<MaterialCookReceipt, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('receipt');\n const candidate = value as Record<string, unknown>;\n if (candidate.schemaVersion !== 'material-cook/4')\n return invalid('receipt.schemaVersion', candidate.schemaVersion);\n const identityResult = validateIdentity(candidate.identity);\n if (!identityResult.ok) return identityResult;\n const identity = identityResult.value;\n if (candidate.derivedInterface === null || typeof candidate.derivedInterface !== 'object') {\n return invalid('receipt.derivedInterface', candidate.derivedInterface);\n }\n const derivedInterface = candidate.derivedInterface as Record<string, unknown>;\n if (derivedInterface.layoutIdentity !== identity.layoutIdentity) {\n return invalid('receipt.derivedInterface.layoutIdentity', derivedInterface.layoutIdentity);\n }\n if (\n derivedInterface.layerPlanIdentity !== undefined &&\n (typeof derivedInterface.layerPlanIdentity !== 'string' ||\n derivedInterface.layerPlanIdentity.length === 0)\n ) {\n return invalid(\n 'receipt.derivedInterface.layerPlanIdentity',\n derivedInterface.layerPlanIdentity,\n );\n }\n for (const field of ['sourceClosure', 'profile', 'compilerVersion']) {\n const fieldValue = candidate[field];\n if (\n (field === 'sourceClosure' && !Array.isArray(fieldValue)) ||\n (field !== 'sourceClosure' && typeof fieldValue !== 'string')\n ) {\n return invalid(`receipt.${field}`, fieldValue);\n }\n }\n const sourceClosure = candidate.sourceClosure;\n if (Array.isArray(sourceClosure) && sourceClosure.some((path) => typeof path !== 'string')) {\n return invalid('receipt.sourceClosure', sourceClosure);\n }\n if (\n expected.layoutIdentity !== undefined &&\n identity.layoutIdentity !== expected.layoutIdentity\n ) {\n return invalid('receipt.identity.layoutIdentity', identity.layoutIdentity);\n }\n if (\n expected.artifactDigest !== undefined &&\n identity.artifactDigest !== expected.artifactDigest\n ) {\n return invalid('receipt.identity.artifactDigest', identity.artifactDigest);\n }\n if (expected.inputDigest !== undefined && identity.cookIdentity !== expected.inputDigest) {\n return invalid('receipt.identity.cookIdentity', identity.cookIdentity);\n }\n return ok({\n schemaVersion: 'material-cook/4',\n sourceClosure: candidate.sourceClosure as string[],\n profile: candidate.profile as string,\n compilerVersion: candidate.compilerVersion as string,\n identity,\n derivedInterface: {\n layoutIdentity: derivedInterface.layoutIdentity as string,\n ...(derivedInterface.layerPlanIdentity === undefined\n ? {}\n : { layerPlanIdentity: derivedInterface.layerPlanIdentity as string }),\n },\n });\n}\n\nexport function validateCookedMaterialRecord(\n value: unknown,\n): Result<CookedMaterialRecord, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object') return invalid('record');\n const candidate = value as Record<string, unknown>;\n if (candidate.schemaVersion !== 'material-cook/4')\n return invalid('schemaVersion', candidate.schemaVersion);\n if (typeof candidate.guid !== 'string' || !candidate.guid) return invalid('guid');\n if (candidate.materialGuid !== undefined && typeof candidate.materialGuid !== 'string')\n return invalid('materialGuid');\n if (\n candidate.publicationGeneration !== undefined &&\n !isGeneration(candidate.publicationGeneration)\n )\n return invalid('publicationGeneration', candidate.publicationGeneration);\n if (candidate.specializationKey !== undefined && typeof candidate.specializationKey !== 'string')\n return invalid('specializationKey');\n if ('artifact' in candidate || 'variants' in candidate || 'variantContext' in candidate)\n return invalid('programs', 'legacy single-artifact publication');\n if (candidate.artifactDigest !== undefined && typeof candidate.artifactDigest !== 'string')\n return invalid('artifactDigest');\n if (\n candidate.sourceClosure !== undefined &&\n (!Array.isArray(candidate.sourceClosure) ||\n candidate.sourceClosure.some((path) => typeof path !== 'string'))\n )\n return invalid('sourceClosure');\n if (candidate.parameterContract !== undefined) {\n if (candidate.parameterContract === null || typeof candidate.parameterContract !== 'object')\n return invalid('parameterContract');\n const parameterContract = candidate.parameterContract as Record<string, unknown>;\n if (!Array.isArray(parameterContract.parameters))\n return invalid('parameterContract.parameters');\n if (\n parameterContract.values === null ||\n typeof parameterContract.values !== 'object' ||\n Array.isArray(parameterContract.values)\n )\n return invalid('parameterContract.values');\n }\n if (candidate.resolved === null || typeof candidate.resolved !== 'object')\n return invalid('resolved');\n if (candidate.refs === null || typeof candidate.refs !== 'object') return invalid('refs');\n if (candidate.receipt === null || typeof candidate.receipt !== 'object')\n return invalid('receipt');\n const resolved = candidate.resolved as Record<string, unknown>;\n if (!Array.isArray(resolved.passes)) return invalid('resolved.passes', resolved.passes);\n if (!Array.isArray(resolved.parameters))\n return invalid('resolved.parameters', resolved.parameters);\n if (\n resolved.values === null ||\n typeof resolved.values !== 'object' ||\n Array.isArray(resolved.values)\n )\n return invalid('resolved.values', resolved.values);\n const passes = resolved.passes as MaterialPass[];\n const passNames = new Set<string>();\n for (const [index, pass] of passes.entries()) {\n if (\n pass === null ||\n typeof pass !== 'object' ||\n typeof pass.name !== 'string' ||\n !pass.name ||\n passNames.has(pass.name) ||\n pass.program === null ||\n typeof pass.program !== 'object' ||\n typeof pass.program.module !== 'string'\n )\n return invalid(`resolved.passes[${index}]`);\n passNames.add(pass.name);\n }\n if (!Array.isArray(candidate.programs) || candidate.programs.length === 0)\n return invalid('programs');\n const programs: MaterialCookProgram[] = [];\n const programKeys = new Set<string>();\n const selections = new Set<string>();\n const selectedPasses = new Set<string>();\n for (const [index, entry] of candidate.programs.entries()) {\n const field = `programs[${index}]`;\n if (entry === null || typeof entry !== 'object') return invalid(field);\n const program = entry as Record<string, unknown>;\n if (\n typeof program.specializationKey !== 'string' ||\n !program.specializationKey ||\n programKeys.has(program.specializationKey)\n )\n return invalid(`${field}.specializationKey`);\n programKeys.add(program.specializationKey);\n if (program.artifact === null || typeof program.artifact !== 'object')\n return invalid(`${field}.artifact`);\n const artifact = program.artifact as Record<string, unknown>;\n const bytes = normalizeArtifactBytes(artifact.bytes);\n if (\n artifact.mediaType !== 'text/wgsl' ||\n typeof artifact.path !== 'string' ||\n !artifact.path ||\n typeof artifact.digest !== 'string' ||\n !artifact.digest ||\n bytes === undefined\n )\n return invalid(`${field}.artifact`);\n if (!Array.isArray(program.selections) || program.selections.length === 0)\n return invalid(`${field}.selections`);\n const programSelections: MaterialCookProgram['selections'][number][] = [];\n for (const [selectionIndex, selection] of program.selections.entries()) {\n const selectionField = `${field}.selections[${selectionIndex}]`;\n if (selection === null || typeof selection !== 'object' || !passNames.has(selection.pass))\n return invalid(selectionField);\n const context = validateMaterialCookProgramContext(selection.context);\n if (!context.ok)\n return invalid(\n `${selectionField}.${context.error.detail.field}`,\n context.error.detail.actual,\n );\n const key = JSON.stringify([selection.pass, materialProgramContextKey(context.value)]);\n if (selections.has(key)) return invalid(selectionField, 'ambiguous Pass/context selection');\n selections.add(key);\n selectedPasses.add(selection.pass);\n programSelections.push({ pass: selection.pass, context: context.value });\n }\n programs.push({\n specializationKey: program.specializationKey,\n artifact: { mediaType: 'text/wgsl', path: artifact.path, digest: artifact.digest, bytes },\n selections: programSelections,\n });\n }\n if ([...passNames].some((pass) => !selectedPasses.has(pass)))\n return invalid('programs.selections', 'unpublished Pass');\n const manifestDigest = createMaterialProgramSetDigest(programs, passes);\n const receiptResult = validateMaterialCookReceipt(candidate.receipt, {\n artifactDigest: manifestDigest,\n });\n if (!receiptResult.ok) return receiptResult;\n let expectedLayerPlanIdentity: string | undefined;\n try {\n expectedLayerPlanIdentity = materialLayerPlanIdentity({\n resolved: resolved as unknown as CookedMaterialRecord['resolved'],\n });\n } catch (error) {\n return invalid('resolved.layerPlanIdentity', error instanceof Error ? error.message : error);\n }\n if (\n expectedLayerPlanIdentity !== undefined &&\n receiptResult.value.derivedInterface.layerPlanIdentity !== expectedLayerPlanIdentity\n ) {\n return invalid(\n 'receipt.derivedInterface.layerPlanIdentity',\n receiptResult.value.derivedInterface.layerPlanIdentity,\n );\n }\n if (candidate.artifactDigest !== undefined && candidate.artifactDigest !== manifestDigest)\n return invalid('artifactDigest', candidate.artifactDigest);\n if (\n candidate.publicationGeneration !== undefined &&\n receiptResult.value.identity.cookGeneration !== candidate.publicationGeneration\n )\n return invalid('receipt.identity.cookGeneration', receiptResult.value.identity.cookGeneration);\n return ok({\n ...candidate,\n programs,\n receipt: receiptResult.value,\n } as unknown as CookedMaterialRecord);\n}\n\nexport function projectCookedMaterialRecord(\n record: CookedMaterialRecord,\n): Omit<CookedMaterialRecord, 'guid' | 'authored'> {\n return {\n resolved: record.resolved,\n refs: record.refs,\n programs: record.programs,\n receipt: record.receipt,\n schemaVersion: record.schemaVersion,\n };\n}\n\n/** Canonical context key shared by publication validation and runtime selection. */\nexport function materialProgramContextKey(context: MaterialCookProgramContext): string {\n return JSON.stringify(jsonValue(context));\n}\n\nexport function validateMaterialCookProgramContext(\n value: unknown,\n): Result<MaterialCookProgramContext, MaterialCookRecordError> {\n if (value === null || typeof value !== 'object' || Array.isArray(value))\n return invalid('context', value);\n const context = value as Record<string, unknown>;\n const fields = {\n backend: ['webgpu', 'webgl2', 'wgpu-native'],\n capability: ['storage-buffer', 'uniform-fallback'],\n pipeline: ['forward', 'deferred'],\n geometry: ['mesh', 'skinned', 'sprite'],\n pass: ['forward', 'shadow', 'depth'],\n profile: ['forgeax-material-wgsl-v1'],\n toolchain: ['naga-oil'],\n instrumentation: ['none', 'validation'],\n };\n for (const field of Object.keys(context)) {\n if (!(field in fields)) return invalid(`context.${field}`, context[field]);\n }\n for (const [field, allowed] of Object.entries(fields)) {\n if (!allowed.includes(context[field] as string))\n return invalid(`context.${field}`, context[field]);\n }\n return ok({ ...context } as unknown as MaterialCookProgramContext);\n}\n\n/** Covers every selection and artifact while excluding transport copies of the bytes. */\nexport function createMaterialProgramSetDigest(\n programs: readonly MaterialCookProgram[],\n passes: readonly MaterialPass[],\n): string {\n const manifest = {\n passes,\n programs: programs\n .map((program) => ({\n specializationKey: program.specializationKey,\n artifact: {\n path: program.artifact.path,\n mediaType: program.artifact.mediaType,\n digest: program.artifact.digest,\n },\n selections: [...program.selections].sort((a, b) =>\n JSON.stringify(jsonValue(a)).localeCompare(JSON.stringify(jsonValue(b))),\n ),\n }))\n .sort((a, b) => a.specializationKey.localeCompare(b.specializationKey)),\n };\n return createMaterialArtifactDigest(\n new TextEncoder().encode(JSON.stringify(jsonValue(manifest))),\n );\n}\n"]}