@forgeax/engine-pack 0.1.23 → 0.1.25

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 (157) hide show
  1. package/README.md +12 -6
  2. package/dist/build.d.ts +4 -4
  3. package/dist/build.d.ts.map +1 -1
  4. package/dist/build.mjs +390 -294
  5. package/dist/build.mjs.map +1 -1
  6. package/dist/cli-asset.mjs +33 -35
  7. package/dist/cli-asset.mjs.map +1 -1
  8. package/dist/evidence/material-cook.d.ts +26 -0
  9. package/dist/evidence/material-cook.d.ts.map +1 -1
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.mjs +121 -27
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/material-cook.d.ts +1 -1
  15. package/dist/material-cook.d.ts.map +1 -1
  16. package/dist/material-cook.mjs +102 -4
  17. package/dist/material-cook.mjs.map +1 -1
  18. package/dist/{parameterized-pack-node.d.ts → pack-authoring-node.d.ts} +7 -7
  19. package/dist/pack-authoring-node.d.ts.map +1 -0
  20. package/dist/{parameterized-pack-node.mjs → pack-authoring-node.mjs} +59 -63
  21. package/dist/pack-authoring-node.mjs.map +1 -0
  22. package/dist/{parameterized-pack.d.ts → pack-authoring.d.ts} +28 -31
  23. package/dist/pack-authoring.d.ts.map +1 -0
  24. package/dist/pack-authoring.mjs +1137 -0
  25. package/dist/pack-authoring.mjs.map +1 -0
  26. package/dist/runtime.mjs +1 -1
  27. package/dist/runtime.mjs.map +1 -1
  28. package/dist/scanner.d.ts +11 -9
  29. package/dist/scanner.d.ts.map +1 -1
  30. package/dist/scanner.mjs +36 -34
  31. package/dist/scanner.mjs.map +1 -1
  32. package/dist/schema.mjs +1 -1
  33. package/dist/schema.mjs.map +1 -1
  34. package/dist/scriptable-pack-node.d.ts +4 -4
  35. package/dist/scriptable-pack-node.d.ts.map +1 -1
  36. package/dist/scriptable-pack-node.mjs +18 -20
  37. package/dist/scriptable-pack-node.mjs.map +1 -1
  38. package/dist/scriptable-pack.d.ts +3 -2
  39. package/dist/scriptable-pack.d.ts.map +1 -1
  40. package/dist/scriptable-pack.mjs +19 -23
  41. package/dist/scriptable-pack.mjs.map +1 -1
  42. package/package.json +2 -7
  43. package/schema/pack.schema.json +1 -1
  44. package/src/__tests__/material-cook-receipt-layer-plan.unit.test.ts +16 -0
  45. package/src/__tests__/material-cook-schema.unit.test.ts +62 -0
  46. package/src/__tests__/material-declaration-boundary.unit.test.ts +35 -0
  47. package/src/__tests__/material-surface-consumer-census.test.ts +24 -0
  48. package/src/__tests__/material-surface-publication.unit.test.ts +159 -0
  49. package/src/__tests__/material-surface-wire.unit.test.ts +30 -0
  50. package/src/__tests__/{parameterized-pack-authoring-gateway.unit.test.ts → pack-authoring-gateway.unit.test.ts} +9 -9
  51. package/src/__tests__/{parameterized-pack.unit.test.ts → pack-authoring.unit.test.ts} +10 -10
  52. package/src/__tests__/{parameterized-pack-scanner.unit.test.ts → pack-scanner.unit.test.ts} +6 -6
  53. package/src/__tests__/scanner-inventory.contract.test.ts +2 -4
  54. package/src/__tests__/scanner-inventory.test.ts +7 -6
  55. package/src/__tests__/scriptable-pack-cli.integration.test.ts +1 -1
  56. package/src/build.ts +10 -8
  57. package/src/catalog-builder.ts +3 -3
  58. package/src/cli-asset.ts +5 -5
  59. package/src/evidence/material-cook.ts +170 -7
  60. package/src/evidence/source-inventory.ts +3 -3
  61. package/src/index.ts +6 -1
  62. package/src/material-cook.ts +3 -0
  63. package/src/{parameterized-pack-node.ts → pack-authoring-node.ts} +71 -73
  64. package/src/{parameterized-pack.ts → pack-authoring.ts} +59 -74
  65. package/src/scanner.ts +33 -31
  66. package/src/schema/material-cook.schema.json +47 -1
  67. package/src/scriptable-pack-node.ts +25 -25
  68. package/src/scriptable-pack.ts +3 -2
  69. package/dist/__tests__/ai-recovery.unit.test.d.ts +0 -2
  70. package/dist/__tests__/ai-recovery.unit.test.d.ts.map +0 -1
  71. package/dist/__tests__/artifact-path.test.d.ts +0 -2
  72. package/dist/__tests__/artifact-path.test.d.ts.map +0 -1
  73. package/dist/__tests__/asset-evidence-error-hints.test.d.ts +0 -2
  74. package/dist/__tests__/asset-evidence-error-hints.test.d.ts.map +0 -1
  75. package/dist/__tests__/asset-evidence-lifecycle.test.d.ts +0 -2
  76. package/dist/__tests__/asset-evidence-lifecycle.test.d.ts.map +0 -1
  77. package/dist/__tests__/asset-evidence-schema.test.d.ts +0 -2
  78. package/dist/__tests__/asset-evidence-schema.test.d.ts.map +0 -1
  79. package/dist/__tests__/atlas-cli-region-mismatch.test.d.ts +0 -2
  80. package/dist/__tests__/atlas-cli-region-mismatch.test.d.ts.map +0 -1
  81. package/dist/__tests__/atlas-error-code-owner.test-d.d.ts +0 -2
  82. package/dist/__tests__/atlas-error-code-owner.test-d.d.ts.map +0 -1
  83. package/dist/__tests__/cli-asset-evidence.integration.test.d.ts +0 -2
  84. package/dist/__tests__/cli-asset-evidence.integration.test.d.ts.map +0 -1
  85. package/dist/__tests__/cli.unit.test.d.ts +0 -2
  86. package/dist/__tests__/cli.unit.test.d.ts.map +0 -1
  87. package/dist/__tests__/evidence-source-inventory.unit.test.d.ts +0 -2
  88. package/dist/__tests__/evidence-source-inventory.unit.test.d.ts.map +0 -1
  89. package/dist/__tests__/guid-collision.unit.test.d.ts +0 -2
  90. package/dist/__tests__/guid-collision.unit.test.d.ts.map +0 -1
  91. package/dist/__tests__/guid-validator-surface.unit.test.d.ts +0 -2
  92. package/dist/__tests__/guid-validator-surface.unit.test.d.ts.map +0 -1
  93. package/dist/__tests__/inventory-schema.test.d.ts +0 -2
  94. package/dist/__tests__/inventory-schema.test.d.ts.map +0 -1
  95. package/dist/__tests__/material-cook-dependencies.unit.test.d.ts +0 -2
  96. package/dist/__tests__/material-cook-dependencies.unit.test.d.ts.map +0 -1
  97. package/dist/__tests__/material-cook-receipt.unit.test.d.ts +0 -2
  98. package/dist/__tests__/material-cook-receipt.unit.test.d.ts.map +0 -1
  99. package/dist/__tests__/material-cook-schema.unit.test.d.ts +0 -2
  100. package/dist/__tests__/material-cook-schema.unit.test.d.ts.map +0 -1
  101. package/dist/__tests__/mesh-bin-consumer-surface.unit.test.d.ts +0 -2
  102. package/dist/__tests__/mesh-bin-consumer-surface.unit.test.d.ts.map +0 -1
  103. package/dist/__tests__/mesh-bin-contract.unit.test.d.ts +0 -2
  104. package/dist/__tests__/mesh-bin-contract.unit.test.d.ts.map +0 -1
  105. package/dist/__tests__/meta-schema-optional.test.d.ts +0 -2
  106. package/dist/__tests__/meta-schema-optional.test.d.ts.map +0 -1
  107. package/dist/__tests__/meta-source-overrides.unit.test.d.ts +0 -2
  108. package/dist/__tests__/meta-source-overrides.unit.test.d.ts.map +0 -1
  109. package/dist/__tests__/native-cooker-registry.test.d.ts +0 -2
  110. package/dist/__tests__/native-cooker-registry.test.d.ts.map +0 -1
  111. package/dist/__tests__/offline-evidence-artifact-verification-owner.test-d.d.ts +0 -2
  112. package/dist/__tests__/offline-evidence-artifact-verification-owner.test-d.d.ts.map +0 -1
  113. package/dist/__tests__/offline-evidence.integration.test.d.ts +0 -2
  114. package/dist/__tests__/offline-evidence.integration.test.d.ts.map +0 -1
  115. package/dist/__tests__/owner-chain.integration.test.d.ts +0 -2
  116. package/dist/__tests__/owner-chain.integration.test.d.ts.map +0 -1
  117. package/dist/__tests__/pack-v2-fixture-migration.test.d.ts +0 -2
  118. package/dist/__tests__/pack-v2-fixture-migration.test.d.ts.map +0 -1
  119. package/dist/__tests__/pack-v2-schema.test.d.ts +0 -2
  120. package/dist/__tests__/pack-v2-schema.test.d.ts.map +0 -1
  121. package/dist/__tests__/pack.unit.test.d.ts +0 -2
  122. package/dist/__tests__/pack.unit.test.d.ts.map +0 -1
  123. package/dist/__tests__/package-finalizer.contract.test.d.ts +0 -2
  124. package/dist/__tests__/package-finalizer.contract.test.d.ts.map +0 -1
  125. package/dist/__tests__/parameterized-pack-authoring-gateway.unit.test.d.ts +0 -2
  126. package/dist/__tests__/parameterized-pack-authoring-gateway.unit.test.d.ts.map +0 -1
  127. package/dist/__tests__/parameterized-pack-scanner.unit.test.d.ts +0 -2
  128. package/dist/__tests__/parameterized-pack-scanner.unit.test.d.ts.map +0 -1
  129. package/dist/__tests__/parameterized-pack.unit.test.d.ts +0 -2
  130. package/dist/__tests__/parameterized-pack.unit.test.d.ts.map +0 -1
  131. package/dist/__tests__/producer-contract-schema.unit.test.d.ts +0 -2
  132. package/dist/__tests__/producer-contract-schema.unit.test.d.ts.map +0 -1
  133. package/dist/__tests__/resolve-asset-source.test.d.ts +0 -2
  134. package/dist/__tests__/resolve-asset-source.test.d.ts.map +0 -1
  135. package/dist/__tests__/runtime-projection.unit.test.d.ts +0 -2
  136. package/dist/__tests__/runtime-projection.unit.test.d.ts.map +0 -1
  137. package/dist/__tests__/runtime.browser.test.d.ts +0 -2
  138. package/dist/__tests__/runtime.browser.test.d.ts.map +0 -1
  139. package/dist/__tests__/scanner-blacklist.test.d.ts +0 -2
  140. package/dist/__tests__/scanner-blacklist.test.d.ts.map +0 -1
  141. package/dist/__tests__/scanner-inventory.contract.test.d.ts +0 -2
  142. package/dist/__tests__/scanner-inventory.contract.test.d.ts.map +0 -1
  143. package/dist/__tests__/scanner-inventory.test.d.ts +0 -2
  144. package/dist/__tests__/scanner-inventory.test.d.ts.map +0 -1
  145. package/dist/__tests__/scanner-mount-cycle.test.d.ts +0 -2
  146. package/dist/__tests__/scanner-mount-cycle.test.d.ts.map +0 -1
  147. package/dist/__tests__/scriptable-pack-cli.integration.test.d.ts +0 -2
  148. package/dist/__tests__/scriptable-pack-cli.integration.test.d.ts.map +0 -1
  149. package/dist/__tests__/scriptable-pack-ddc-key.unit.test.d.ts +0 -2
  150. package/dist/__tests__/scriptable-pack-ddc-key.unit.test.d.ts.map +0 -1
  151. package/dist/__tests__/topology-actions.unit.test.d.ts +0 -2
  152. package/dist/__tests__/topology-actions.unit.test.d.ts.map +0 -1
  153. package/dist/__tests__/topology.unit.test.d.ts +0 -2
  154. package/dist/__tests__/topology.unit.test.d.ts.map +0 -1
  155. package/dist/parameterized-pack-node.d.ts.map +0 -1
  156. package/dist/parameterized-pack-node.mjs.map +0 -1
  157. package/dist/parameterized-pack.d.ts.map +0 -1
@@ -7,7 +7,7 @@ import type {
7
7
  MaterialValue,
8
8
  Result,
9
9
  } from '@forgeax/engine-types';
10
- import { err, MATERIAL_TEXTURE_SLOTS, ok } from '@forgeax/engine-types';
10
+ import { deriveStandardLayerPlan, err, MATERIAL_TEXTURE_SLOTS, ok } from '@forgeax/engine-types';
11
11
  import { sha256 } from '@noble/hashes/sha2.js';
12
12
  import { bytesToHex } from '@noble/hashes/utils.js';
13
13
 
@@ -25,6 +25,19 @@ export interface MaterialCookArtifact {
25
25
  readonly bytes: Uint8Array;
26
26
  }
27
27
 
28
+ /** Backend capability projection for one immutable cooked material artifact. */
29
+ export interface MaterialCookVariantContext {
30
+ readonly backend: 'webgpu' | 'webgl2' | 'wgpu-native';
31
+ readonly capability: 'storage-buffer' | 'uniform-fallback';
32
+ }
33
+
34
+ /** Additional backend artifact published with one material generation. */
35
+ export interface MaterialCookVariant {
36
+ readonly context: MaterialCookVariantContext;
37
+ readonly specializationKey: string;
38
+ readonly artifact: MaterialCookArtifact;
39
+ }
40
+
28
41
  export interface MaterialCookWasmProvenance {
29
42
  readonly sourceContentKey: string;
30
43
  readonly artifactSha256: string;
@@ -56,7 +69,11 @@ export interface MaterialCookReceipt {
56
69
  readonly profile: string;
57
70
  readonly compilerVersion: string;
58
71
  readonly identity: MaterialCookIdentity;
59
- readonly derivedInterface: { readonly layoutIdentity: string };
72
+ readonly derivedInterface: {
73
+ readonly layoutIdentity: string;
74
+ /** Build-time Standard physical lowering identity, when the root is Standard. */
75
+ readonly layerPlanIdentity?: string;
76
+ };
60
77
  }
61
78
 
62
79
  export interface MaterialParameterContract {
@@ -71,6 +88,10 @@ export interface CookedMaterialRecord {
71
88
  readonly materialGuid?: string;
72
89
  readonly publicationGeneration?: number;
73
90
  readonly specializationKey?: string;
91
+ /** Compiler context used by the primary `artifact` entry. */
92
+ readonly variantContext?: MaterialCookVariantContext;
93
+ /** Additional immutable artifacts for other backend capability lanes. */
94
+ readonly variants?: readonly MaterialCookVariant[];
74
95
  readonly artifactDigest?: string;
75
96
  readonly sourceClosure?: readonly string[];
76
97
  readonly parameterContract?: MaterialParameterContract;
@@ -101,6 +122,37 @@ export interface MaterialCookIdentityExpectation {
101
122
  readonly inputDigest?: string;
102
123
  }
103
124
 
125
+ const STANDARD_ROOT_MODULES = new Set([
126
+ 'forgeax::default-standard-pbr',
127
+ 'forgeax::pbr-skin',
128
+ 'forgeax_material::standard',
129
+ 'forgeax_material::pbr-skin',
130
+ 'forgeax::default-shadow-caster',
131
+ ]);
132
+
133
+ /** Shared ownership predicate for the built-in Standard material root. */
134
+ export function isStandardRootModule(module: string): boolean {
135
+ return STANDARD_ROOT_MODULES.has(module);
136
+ }
137
+
138
+ export function isStandardMaterialRecord(record: Pick<CookedMaterialRecord, 'resolved'>): boolean {
139
+ return record.resolved.passes.some((pass) => isStandardRootModule(pass.program.module));
140
+ }
141
+
142
+ /**
143
+ * Recompute the Standard layer identity from the admitted resolved root.
144
+ * Material admission and runtime loading share this owner so a stale receipt
145
+ * cannot select a different physical layer plan after cooking.
146
+ */
147
+ export function materialLayerPlanIdentity(
148
+ record: Pick<CookedMaterialRecord, 'resolved'>,
149
+ ): string | undefined {
150
+ if (!isStandardMaterialRecord(record)) {
151
+ return undefined;
152
+ }
153
+ return deriveStandardLayerPlan(record.resolved.parameters, record.resolved.passes).identity;
154
+ }
155
+
104
156
  function unique(values: readonly string[]): readonly string[] {
105
157
  return [...new Set(values)].sort();
106
158
  }
@@ -224,6 +276,17 @@ function invalid(field: string, actual?: unknown): Result<never, MaterialCookRec
224
276
  });
225
277
  }
226
278
 
279
+ function normalizeArtifactBytes(value: unknown): Uint8Array | undefined {
280
+ if (Array.isArray(value)) {
281
+ return value.every((byte) => Number.isInteger(byte) && byte >= 0 && byte <= 255)
282
+ ? Uint8Array.from(value)
283
+ : undefined;
284
+ }
285
+ if (!ArrayBuffer.isView(value)) return undefined;
286
+ const view = value as ArrayBufferView;
287
+ return new Uint8Array(view.buffer, view.byteOffset, view.byteLength).slice();
288
+ }
289
+
227
290
  const IDENTITY_FIELDS = [
228
291
  'materialContractDigest',
229
292
  'sourceRevision',
@@ -286,6 +349,16 @@ export function validateMaterialCookReceipt(
286
349
  if (derivedInterface.layoutIdentity !== identity.layoutIdentity) {
287
350
  return invalid('receipt.derivedInterface.layoutIdentity', derivedInterface.layoutIdentity);
288
351
  }
352
+ if (
353
+ derivedInterface.layerPlanIdentity !== undefined &&
354
+ (typeof derivedInterface.layerPlanIdentity !== 'string' ||
355
+ derivedInterface.layerPlanIdentity.length === 0)
356
+ ) {
357
+ return invalid(
358
+ 'receipt.derivedInterface.layerPlanIdentity',
359
+ derivedInterface.layerPlanIdentity,
360
+ );
361
+ }
289
362
  for (const field of ['sourceClosure', 'profile', 'compilerVersion']) {
290
363
  const fieldValue = candidate[field];
291
364
  if (
@@ -320,7 +393,12 @@ export function validateMaterialCookReceipt(
320
393
  profile: candidate.profile as string,
321
394
  compilerVersion: candidate.compilerVersion as string,
322
395
  identity,
323
- derivedInterface: { layoutIdentity: derivedInterface.layoutIdentity as string },
396
+ derivedInterface: {
397
+ layoutIdentity: derivedInterface.layoutIdentity as string,
398
+ ...(derivedInterface.layerPlanIdentity === undefined
399
+ ? {}
400
+ : { layerPlanIdentity: derivedInterface.layerPlanIdentity as string }),
401
+ },
324
402
  });
325
403
  }
326
404
 
@@ -341,6 +419,49 @@ export function validateCookedMaterialRecord(
341
419
  return invalid('publicationGeneration', candidate.publicationGeneration);
342
420
  if (candidate.specializationKey !== undefined && typeof candidate.specializationKey !== 'string')
343
421
  return invalid('specializationKey');
422
+ if (candidate.variantContext !== undefined) {
423
+ if (candidate.variantContext === null || typeof candidate.variantContext !== 'object')
424
+ return invalid('variantContext');
425
+ const context = candidate.variantContext as Record<string, unknown>;
426
+ if (
427
+ (context.backend !== 'webgpu' &&
428
+ context.backend !== 'webgl2' &&
429
+ context.backend !== 'wgpu-native') ||
430
+ (context.capability !== 'storage-buffer' && context.capability !== 'uniform-fallback')
431
+ )
432
+ return invalid('variantContext', candidate.variantContext);
433
+ }
434
+ if (candidate.variants !== undefined) {
435
+ if (!Array.isArray(candidate.variants)) return invalid('variants');
436
+ for (const [index, value] of candidate.variants.entries()) {
437
+ if (value === null || typeof value !== 'object') return invalid(`variants[${index}]`);
438
+ const variant = value as Record<string, unknown>;
439
+ const context = variant.context;
440
+ if (context === null || typeof context !== 'object')
441
+ return invalid(`variants[${index}].context`);
442
+ const contextRecord = context as Record<string, unknown>;
443
+ if (
444
+ (contextRecord.backend !== 'webgpu' &&
445
+ contextRecord.backend !== 'webgl2' &&
446
+ contextRecord.backend !== 'wgpu-native') ||
447
+ (contextRecord.capability !== 'storage-buffer' &&
448
+ contextRecord.capability !== 'uniform-fallback')
449
+ )
450
+ return invalid(`variants[${index}].context`, context);
451
+ if (typeof variant.specializationKey !== 'string' || variant.specializationKey.length === 0)
452
+ return invalid(`variants[${index}].specializationKey`);
453
+ if (variant.artifact === null || typeof variant.artifact !== 'object')
454
+ return invalid(`variants[${index}].artifact`);
455
+ const variantArtifact = variant.artifact as Record<string, unknown>;
456
+ if (
457
+ typeof variantArtifact.mediaType !== 'string' ||
458
+ typeof variantArtifact.path !== 'string' ||
459
+ typeof variantArtifact.digest !== 'string' ||
460
+ normalizeArtifactBytes(variantArtifact.bytes) === undefined
461
+ )
462
+ return invalid(`variants[${index}].artifact`);
463
+ }
464
+ }
344
465
  if (candidate.artifactDigest !== undefined && typeof candidate.artifactDigest !== 'string')
345
466
  return invalid('artifactDigest');
346
467
  if (
@@ -380,6 +501,33 @@ export function validateCookedMaterialRecord(
380
501
  artifactDigest: artifact.digest as string,
381
502
  });
382
503
  if (!receiptResult.ok) return receiptResult;
504
+ const resolved = candidate.resolved as Record<string, unknown>;
505
+ if (!Array.isArray(resolved.passes)) return invalid('resolved.passes', resolved.passes);
506
+ if (!Array.isArray(resolved.parameters))
507
+ return invalid('resolved.parameters', resolved.parameters);
508
+ if (
509
+ resolved.values === null ||
510
+ typeof resolved.values !== 'object' ||
511
+ Array.isArray(resolved.values)
512
+ )
513
+ return invalid('resolved.values', resolved.values);
514
+ let expectedLayerPlanIdentity: string | undefined;
515
+ try {
516
+ expectedLayerPlanIdentity = materialLayerPlanIdentity({
517
+ resolved: resolved as unknown as CookedMaterialRecord['resolved'],
518
+ });
519
+ } catch (error) {
520
+ return invalid('resolved.layerPlanIdentity', error instanceof Error ? error.message : error);
521
+ }
522
+ if (
523
+ expectedLayerPlanIdentity !== undefined &&
524
+ receiptResult.value.derivedInterface.layerPlanIdentity !== expectedLayerPlanIdentity
525
+ ) {
526
+ return invalid(
527
+ 'receipt.derivedInterface.layerPlanIdentity',
528
+ receiptResult.value.derivedInterface.layerPlanIdentity,
529
+ );
530
+ }
383
531
  if (candidate.artifactDigest !== undefined && candidate.artifactDigest !== artifact.digest)
384
532
  return invalid('artifactDigest', candidate.artifactDigest);
385
533
  if (
@@ -391,12 +539,25 @@ export function validateCookedMaterialRecord(
391
539
  ...candidate,
392
540
  artifact: {
393
541
  ...artifact,
394
- bytes: ArrayBuffer.isView(artifact.bytes)
395
- ? Uint8Array.from(artifact.bytes as Uint8Array)
396
- : Uint8Array.from(artifact.bytes as number[]),
542
+ bytes: normalizeArtifactBytes(artifact.bytes) as Uint8Array,
397
543
  },
544
+ ...(Array.isArray(candidate.variants)
545
+ ? {
546
+ variants: candidate.variants.map((value) => {
547
+ const variant = value as Record<string, unknown>;
548
+ const variantArtifact = variant.artifact as Record<string, unknown>;
549
+ return {
550
+ ...variant,
551
+ artifact: {
552
+ ...variantArtifact,
553
+ bytes: normalizeArtifactBytes(variantArtifact.bytes) as Uint8Array,
554
+ },
555
+ };
556
+ }),
557
+ }
558
+ : {}),
398
559
  receipt: receiptResult.value,
399
- } as CookedMaterialRecord;
560
+ } as unknown as CookedMaterialRecord;
400
561
  return ok(normalized);
401
562
  }
402
563
 
@@ -407,6 +568,8 @@ export function projectCookedMaterialRecord(
407
568
  resolved: record.resolved,
408
569
  refs: record.refs,
409
570
  artifact: record.artifact,
571
+ ...(record.variantContext === undefined ? {} : { variantContext: record.variantContext }),
572
+ ...(record.variants === undefined ? {} : { variants: record.variants }),
410
573
  receipt: record.receipt,
411
574
  schemaVersion: record.schemaVersion,
412
575
  };
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
2
2
  import { readdir, readFile } from 'node:fs/promises';
3
3
  import { basename, dirname, join, relative, resolve, sep } from 'node:path';
4
4
  import type { SourceDeclarationEvidence } from '@forgeax/engine-types';
5
- import { parseParameterizedPackJson, projectDirectPackJson } from '../parameterized-pack.js';
5
+ import { parsePackSourceJson, projectDirectPackJson } from '../pack-authoring.js';
6
6
  import { SCANNER_BLACKLIST, scan } from '../scanner.js';
7
7
 
8
8
  /** Project root and GUID used to locate an authoritative source declaration. */
@@ -149,7 +149,7 @@ export async function readSourceInventory(
149
149
  let authored: SourceDeclarationEvidence | undefined;
150
150
  for (const path of paths) {
151
151
  if (path.endsWith('.pack.ts')) {
152
- // Parameterized source identity is a build result, not a declaration
152
+ // ScriptablePack source identity is a build result, not a declaration
153
153
  // table. The source index therefore records the source only after the
154
154
  // producer publishes its materialized Pack output.
155
155
  continue;
@@ -166,7 +166,7 @@ export async function readSourceInventory(
166
166
  }
167
167
  if (path.endsWith('.pack.json')) {
168
168
  if (parsed.schemaVersion === '3.0.0') {
169
- const direct = parseParameterizedPackJson(parsed);
169
+ const direct = parsePackSourceJson(parsed);
170
170
  if (direct.ok && direct.value.format === 'direct') {
171
171
  const projected = projectDirectPackJson(direct.value);
172
172
  if (
package/src/index.ts CHANGED
@@ -7,6 +7,8 @@ export {
7
7
  collectMaterialCookRefs,
8
8
  createMaterialArtifactDigest,
9
9
  createMaterialCookIdentity,
10
+ isStandardMaterialRecord,
11
+ isStandardRootModule,
10
12
  type MaterialCookArtifact,
11
13
  type MaterialCookIdentity,
12
14
  type MaterialCookIdentityExpectation,
@@ -14,7 +16,10 @@ export {
14
16
  type MaterialCookReceipt,
15
17
  type MaterialCookRecordError,
16
18
  type MaterialCookRefs,
19
+ type MaterialCookVariant,
20
+ type MaterialCookVariantContext,
17
21
  type MaterialCookWasmProvenance,
22
+ materialLayerPlanIdentity,
18
23
  projectCookedMaterialRecord,
19
24
  serializeCookedMaterialRecord,
20
25
  serializeMaterialCookReceipt,
@@ -40,7 +45,7 @@ export {
40
45
  type MeshBinHeaderV4,
41
46
  writeMeshBinHeader,
42
47
  } from './mesh-bin-contract.js';
43
- export * from './parameterized-pack.js';
48
+ export * from './pack-authoring.js';
44
49
  export { validateProducerContract, validateProducerOutputs } from './producer-contract.js';
45
50
  export {
46
51
  type AssetReader,
@@ -7,7 +7,10 @@ export {
7
7
  type MaterialCookReceipt,
8
8
  type MaterialCookRecordError,
9
9
  type MaterialCookRefs,
10
+ type MaterialCookVariant,
11
+ type MaterialCookVariantContext,
10
12
  type MaterialCookWasmProvenance,
13
+ materialLayerPlanIdentity,
11
14
  projectCookedMaterialRecord,
12
15
  serializeCookedMaterialRecord,
13
16
  serializeMaterialCookReceipt,