@forgeax/engine-preview 0.1.3 → 0.1.6

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.
@@ -1,4 +1,3 @@
1
- export type PreviewSubjectKind = 'material' | 'mesh' | 'vfx' | 'texture';
2
1
  export type PreviewSubject = {
3
2
  readonly kind: 'material';
4
3
  readonly guid: string;
@@ -16,6 +15,7 @@ export type PreviewSubject = {
16
15
  readonly guid: string;
17
16
  readonly digest: string;
18
17
  };
18
+ export type PreviewSubjectKind = PreviewSubject['kind'];
19
19
  export type PreviewPresentation = {
20
20
  readonly kind: 'lit-asset';
21
21
  readonly geometry: 'handle-sphere' | 'asset-mesh';
package/dist/material.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import { defineToolCapability, defineTool } from '@forgeax/engine-tool-runtime';
2
- import { builtinAssetKind } from '@forgeax/engine-runtime';
3
2
  import { defineToolPlugin } from '@forgeax/engine-plugin';
4
3
 
5
4
  // src/material.ts
@@ -158,7 +157,7 @@ function subjectFailure(code, expected, detail) {
158
157
  error: {
159
158
  code,
160
159
  expected,
161
- hint: "Load the requested GUID through AssetRegistry.load(guid, kind) and repair the owner facts before retrying.",
160
+ hint: "Load the requested GUID through AssetRegistry.loadByGuid and repair the owner facts before retrying.",
162
161
  detail
163
162
  }
164
163
  };
@@ -276,10 +275,10 @@ async function executeMaterialPreview(args, input) {
276
275
  "resource preview host to expose the existing AssetRegistry",
277
276
  { phase: "asset-registry", runId: input.runId }
278
277
  );
279
- const loaded = await input.assets.load(args.guid, builtinAssetKind("material"));
278
+ const loaded = await input.assets.loadByGuid(args.guid);
280
279
  if (!loaded.ok)
281
280
  return assetLoadFailure(
282
- "AssetRegistry.load(guid, materialAssetKind) to resolve the requested material",
281
+ "AssetRegistry.loadByGuid to resolve the requested material",
283
282
  input.runId,
284
283
  loaded.error
285
284
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/evidence/oracle.ts","../src/kit/canonical.ts","../src/host/preview-host.ts","../src/domains/subject.ts","../src/domains/material.ts","../src/host.ts","../src/material.ts"],"names":["defineToolPlugin","isRecord"],"mappings":"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","file":"material.mjs","sourcesContent":["export type PreviewOracleStatus = PreviewOracle['status'];\n\nexport type PreviewOracle =\n | {\n readonly status: 'passed';\n readonly subjectBound: true;\n readonly drawCalls: number;\n readonly dispatches: number;\n readonly rendererHealthy: true;\n readonly detail: Record<string, string | number | boolean>;\n }\n | {\n readonly status: 'failed';\n readonly subjectBound: false;\n readonly drawCalls: number;\n readonly dispatches: number;\n readonly rendererHealthy: boolean;\n readonly detail: Record<string, string | number | boolean>;\n };\n\nexport function passedPreviewOracle(input: {\n readonly drawCalls: number;\n readonly dispatches?: number;\n readonly detail: Record<string, string | number | boolean>;\n}): PreviewOracle {\n return {\n status: 'passed',\n subjectBound: true,\n drawCalls: input.drawCalls,\n dispatches: input.dispatches ?? 0,\n rendererHealthy: true,\n detail: { ...input.detail },\n };\n}\n\nexport function failedPreviewOracle(input: {\n readonly drawCalls?: number;\n readonly dispatches?: number;\n readonly rendererHealthy?: boolean;\n readonly detail: Record<string, string | number | boolean>;\n}): PreviewOracle {\n return {\n status: 'failed',\n subjectBound: false,\n drawCalls: input.drawCalls ?? 0,\n dispatches: input.dispatches ?? 0,\n rendererHealthy: input.rendererHealthy ?? false,\n detail: { ...input.detail },\n };\n}\n\nexport interface MaterialOracleInput {\n readonly requested: {\n readonly subjectDigest: string;\n readonly program: string;\n readonly pass: string;\n readonly bindingsDigest: string;\n readonly closureDigest: string;\n };\n readonly observed: MaterialOracleInput['requested'] & {\n readonly rendererHealthy: boolean;\n readonly drawCalls: number;\n readonly nonBlackPixels: number;\n };\n}\n\nexport interface MeshOracleInput {\n readonly requested: {\n readonly subjectDigest: string;\n readonly vertexDigest: string;\n readonly indexDigest: string;\n readonly submeshDigest: string;\n readonly aabbDigest: string;\n readonly aabb?: readonly [number, number, number, number, number, number];\n readonly submeshCount?: number;\n readonly materialSlotCount?: number;\n };\n readonly observed: MeshOracleInput['requested'] & {\n readonly rendererHealthy: boolean;\n readonly drawCalls: number;\n readonly nonBlackPixels: number;\n };\n}\n\nfunction oracleDetail(\n kind: 'material' | 'mesh',\n requested: Record<string, unknown>,\n observed: Record<string, unknown>,\n mismatch: string | undefined,\n): Record<string, string | number | boolean> {\n return {\n kind,\n mismatch: mismatch ?? 'none',\n requestedSubjectDigest:\n typeof requested.subjectDigest === 'string' ? requested.subjectDigest : 'unknown',\n observedSubjectDigest:\n typeof observed.subjectDigest === 'string' ? observed.subjectDigest : 'unknown',\n requestedOwnerDigest: JSON.stringify(requested),\n observedOwnerDigest: JSON.stringify(observed),\n };\n}\n\nfunction firstMismatch(\n requested: Record<string, unknown>,\n observed: Record<string, unknown>,\n): string | undefined {\n for (const key of Object.keys(requested)) {\n const requestedValue = requested[key];\n const observedValue = observed[key];\n if (\n Array.isArray(requestedValue) ||\n Array.isArray(observedValue) ||\n typeof requestedValue === 'object' ||\n typeof observedValue === 'object'\n ) {\n if (JSON.stringify(requestedValue) !== JSON.stringify(observedValue)) return key;\n } else if (requestedValue !== observedValue) {\n return key;\n }\n }\n return undefined;\n}\n\nexport function evaluateMaterialOracle(input: MaterialOracleInput): PreviewOracle {\n const requested = input.requested as unknown as Record<string, string>;\n const observed = input.observed as unknown as Record<string, string>;\n const mismatch = firstMismatch(requested, observed);\n const healthy = input.observed.rendererHealthy && input.observed.drawCalls > 0;\n const detail = oracleDetail('material', requested, observed, mismatch);\n if (mismatch !== undefined || !healthy) {\n return failedPreviewOracle({\n drawCalls: input.observed.drawCalls,\n rendererHealthy: input.observed.rendererHealthy,\n detail: { ...detail, rendererHealthy: input.observed.rendererHealthy },\n });\n }\n return passedPreviewOracle({\n drawCalls: input.observed.drawCalls,\n detail: { ...detail, rendererHealthy: true },\n });\n}\n\nexport function evaluateMeshOracle(input: MeshOracleInput): PreviewOracle {\n const requested = input.requested as unknown as Record<string, string>;\n const observed = input.observed as unknown as Record<string, string>;\n const mismatch = firstMismatch(requested, observed);\n const healthy = input.observed.rendererHealthy && input.observed.drawCalls > 0;\n const detail = oracleDetail('mesh', requested, observed, mismatch);\n if (mismatch !== undefined || !healthy) {\n return failedPreviewOracle({\n drawCalls: input.observed.drawCalls,\n rendererHealthy: input.observed.rendererHealthy,\n detail: { ...detail, rendererHealthy: input.observed.rendererHealthy },\n });\n }\n return passedPreviewOracle({\n drawCalls: input.observed.drawCalls,\n detail: { ...detail, rendererHealthy: true },\n });\n}\n\nexport interface VfxOracleInput {\n readonly requested: {\n readonly subjectDigest: string;\n readonly programFingerprint: string;\n readonly emitterDigest: string;\n readonly sampleDigest: string;\n readonly boundsDigest: string;\n readonly computeDigest: string;\n readonly indirectDigest: string;\n readonly contactSheetDigest?: string;\n readonly authoredBounds?: readonly [number, number, number, number, number, number];\n readonly seed?: number;\n readonly fixedDelta?: number;\n readonly timelineFrames?: number;\n };\n readonly observed: VfxOracleInput['requested'] & {\n readonly rendererHealthy: boolean;\n readonly dispatches: number;\n readonly indirectDraws: number;\n readonly subjectOutputs: number;\n readonly nonBlackPixels: number;\n };\n}\n\nexport interface TextureOracleInput {\n readonly requested: {\n readonly subjectDigest: string;\n readonly boundDigest: string;\n readonly dimensions: readonly [number, number];\n readonly format: string;\n readonly colorSpace: string;\n readonly mipCount: number;\n readonly uvDigest: string;\n readonly filter: string;\n readonly bindingDigest: string;\n };\n readonly observed: TextureOracleInput['requested'] & {\n readonly rendererHealthy: boolean;\n readonly drawCalls: number;\n readonly nonBlackPixels: number;\n readonly payloadClass: 'black' | 'transparent' | 'single-channel' | 'color';\n };\n}\n\nfunction identityRecord(input: Record<string, unknown>): Record<string, string> {\n return Object.fromEntries(\n Object.entries(input).map(([key, value]) => [\n key,\n Array.isArray(value) ? JSON.stringify(value) : String(value),\n ]),\n );\n}\n\nfunction evaluateIdentityOracle(\n kind: 'vfx' | 'texture',\n requestedInput: Record<string, unknown>,\n observedInput: Record<string, unknown>,\n healthy: boolean,\n drawCalls: number,\n dispatches: number,\n detailOverrides: Record<string, string | number | boolean>,\n): PreviewOracle {\n const requested = identityRecord(requestedInput);\n const observed = identityRecord(observedInput);\n const mismatch = firstMismatch(requested, observed);\n const detail = {\n kind,\n mismatch: mismatch ?? 'none',\n requestedSubjectDigest: requested.subjectDigest ?? 'unknown',\n observedSubjectDigest: observed.subjectDigest ?? 'unknown',\n requestedOwnerDigest: JSON.stringify(requested),\n observedOwnerDigest: JSON.stringify(observed),\n ...detailOverrides,\n };\n if (mismatch !== undefined || !healthy) {\n return failedPreviewOracle({ drawCalls, dispatches, rendererHealthy: healthy, detail });\n }\n return passedPreviewOracle({ drawCalls, dispatches, detail });\n}\n\nexport function evaluateVfxOracle(input: VfxOracleInput): PreviewOracle {\n const observed = input.observed;\n const healthy =\n observed.rendererHealthy &&\n observed.dispatches > 0 &&\n observed.indirectDraws > 0 &&\n observed.subjectOutputs > 0;\n return evaluateIdentityOracle(\n 'vfx',\n input.requested,\n input.observed,\n healthy,\n observed.indirectDraws,\n observed.dispatches,\n {\n rendererHealthy: observed.rendererHealthy,\n indirectDraws: observed.indirectDraws,\n subjectOutputs: observed.subjectOutputs,\n nonBlackPixels: observed.nonBlackPixels,\n },\n );\n}\n\nexport function evaluateTextureOracle(input: TextureOracleInput): PreviewOracle {\n const observed = input.observed;\n return evaluateIdentityOracle(\n 'texture',\n input.requested,\n input.observed,\n observed.rendererHealthy && observed.drawCalls > 0,\n observed.drawCalls,\n 0,\n {\n rendererHealthy: observed.rendererHealthy,\n payloadClass: observed.payloadClass,\n nonBlackPixels: observed.nonBlackPixels,\n },\n );\n}\n","import type { PreviewPresentation, PreviewSubjectKind } from './presentation.js';\n\nexport interface CanonicalPreviewRecipe {\n readonly schemaVersion: '1.0.0';\n readonly rig:\n | Extract<PreviewPresentation, { readonly kind: 'lit-asset' }>['geometry']\n | 'asset-quad';\n readonly environment: 'engine-canonical' | 'black';\n readonly skybox: 'engine-canonical' | 'none';\n readonly skylight: 'engine-canonical' | 'none';\n readonly directionalLight: 'engine-canonical' | 'none';\n readonly stage: 'neutral-material-checker-unlit' | 'texture-unlit-black';\n readonly camera: 'bounds-derived' | 'texture-orthographic';\n readonly recipeDigest: string;\n}\n\nexport function createCanonicalPreviewRecipe(kind: PreviewSubjectKind): CanonicalPreviewRecipe {\n const texture = kind === 'texture';\n return {\n schemaVersion: '1.0.0',\n rig: kind === 'mesh' ? 'asset-mesh' : texture ? 'asset-quad' : 'handle-sphere',\n environment: texture ? 'black' : 'engine-canonical',\n skybox: texture ? 'none' : 'engine-canonical',\n skylight: texture ? 'none' : 'engine-canonical',\n directionalLight: texture ? 'none' : 'engine-canonical',\n stage: texture ? 'texture-unlit-black' : 'neutral-material-checker-unlit',\n camera: texture ? 'texture-orthographic' : 'bounds-derived',\n recipeDigest: `canonical:${kind}:${texture ? 'texture-orthographic' : 'bounds-derived'}`,\n };\n}\n\nexport function canonicalPresentation(kind: PreviewSubjectKind): PreviewPresentation {\n if (kind === 'texture') {\n return {\n kind: 'texture-unlit',\n geometry: 'aspect-quad',\n checkerboard: 'linear-alpha',\n };\n }\n return {\n kind: 'lit-asset',\n geometry: kind === 'mesh' ? 'asset-mesh' : 'handle-sphere',\n skylight: 'engine-canonical',\n directionalLight: 'engine-canonical',\n skybox: 'engine-canonical',\n };\n}\n","import { defineToolPlugin, type Plugin, type ToolPlugin } from '@forgeax/engine-plugin';\nimport {\n type ArtifactRef,\n defineToolCapability,\n type SnapshotRef,\n} from '@forgeax/engine-tool-runtime';\nimport type { AssetKind } from '@forgeax/engine-types';\n\nexport interface PreviewAssetLoadResult<TAsset = unknown> {\n readonly ok: true;\n readonly value: TAsset;\n readonly digest?: string;\n readonly ownerFacts?: Readonly<Record<string, string | number | boolean>>;\n}\n\nexport interface PreviewAssetLoadFailure {\n readonly ok: false;\n readonly error: unknown;\n}\n\nexport interface PreviewAssetRegistry {\n readonly load: <TAsset, TKind extends string>(\n guid: string,\n kind: AssetKind<TAsset, TKind>,\n ) => Promise<PreviewAssetLoadResult<TAsset> | PreviewAssetLoadFailure>;\n}\n\nexport interface PreviewRenderRuntime {\n readonly rendererReady: boolean;\n readonly worldReady: boolean;\n readonly drawCalls: number;\n readonly nonBlackPixels: number;\n /**\n * Facts read back from the real render/asset owner path. Domain executors\n * must not manufacture observed identity from the requested subject.\n */\n readonly observation?: Readonly<Record<string, string | number | boolean | readonly number[]>>;\n readonly vfx?: {\n readonly dispatches: number;\n readonly indirectDraws: number;\n readonly subjectOutputs: number;\n };\n readonly texture?: {\n readonly drawCalls: number;\n };\n}\n\nexport interface PreviewHostMechanisms {\n readonly runId: string;\n readonly snapshot: SnapshotRef;\n readonly projectRoot: string;\n readonly backend: 'webgpu';\n readonly signal: AbortSignal;\n readonly assets?: PreviewAssetRegistry;\n readonly renderer?: PreviewRenderRuntime;\n readonly artifacts?: readonly ArtifactRef[];\n}\n\nexport interface PreviewHost {\n readonly withSession: <T>(\n execute: (mechanisms: PreviewHostMechanisms) => Promise<T>,\n ) => Promise<T>;\n}\n\nexport const previewHostCapability = defineToolCapability<PreviewHost>('preview.host');\n\nexport function previewHostPlugin(host: PreviewHost): Plugin {\n return {\n name: 'forgeax-preview-host',\n provide: previewHostCapability.id,\n apply(ctx) {\n ctx.provide(previewHostCapability.id, host);\n },\n };\n}\n\nexport function bindPreviewHost(plugin: ToolPlugin, host: PreviewHost): ToolPlugin {\n return defineToolPlugin(previewHostPlugin(host), plugin.tools);\n}\n\nexport function createPreviewHost(input: PreviewHostMechanisms): PreviewHost {\n let active = true;\n return {\n async withSession(execute) {\n if (!active || input.signal.aborted) throw new Error('preview-host-session-terminal');\n try {\n return await execute(input);\n } finally {\n active = false;\n }\n },\n };\n}\n","import { defineToolPlugin } from '@forgeax/engine-plugin';\nimport type {\n JsonValue,\n ToolContribution,\n ToolDescriptor,\n ToolExecutionContext,\n ToolSchema,\n} from '@forgeax/engine-tool-runtime';\nimport { previewHostCapability } from '../host/preview-host.js';\nimport type { PreviewSubjectKind } from '../kit/presentation.js';\n\nexport interface ResourcePreviewArgs {\n readonly guid: string;\n /** Square screenshot edge in device pixels. Defaults to 512 and must be a power of two. */\n readonly size?: number;\n}\n\nexport const RESOURCE_PREVIEW_DEFAULT_SIZE = 512;\nexport const RESOURCE_PREVIEW_MIN_SIZE = 64;\nexport const RESOURCE_PREVIEW_MAX_SIZE = 4096;\n\nexport function isResourcePreviewSize(value: unknown): value is number {\n return (\n typeof value === 'number' &&\n Number.isSafeInteger(value) &&\n value >= RESOURCE_PREVIEW_MIN_SIZE &&\n value <= RESOURCE_PREVIEW_MAX_SIZE &&\n (value & (value - 1)) === 0\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\n/** Keep the public result contract concrete at the ToolRuntime boundary. */\nfunction isResourcePreviewResult(value: unknown): boolean {\n if (!isRecord(value)) return false;\n const subject = value.subject;\n if (\n !isRecord(subject) ||\n !isString(subject.kind) ||\n !isString(subject.guid) ||\n !isString(subject.digest)\n )\n return false;\n if (!isRecord(value.presentation) || !isString(value.presentation.kind)) return false;\n if (\n !isRecord(value.recipe) ||\n !isString(value.recipe.schemaVersion) ||\n !isString(value.recipe.recipeDigest)\n )\n return false;\n if (!isRecord(value.oracle) || !isString(value.oracle.status)) return false;\n return Array.isArray(value.artifacts);\n}\n\nexport const resourcePreviewResultSchema: ToolSchema<unknown> = {\n parse(value) {\n return isResourcePreviewResult(value)\n ? { ok: true, value }\n : {\n ok: false,\n error:\n 'resource preview result must include subject, presentation, recipe, oracle, and artifacts',\n };\n },\n describe: '{\"type\":\"object\",\"required\":[\"subject\",\"presentation\",\"recipe\",\"oracle\",\"artifacts\"]}',\n};\n\nexport const resourcePreviewArgsSchema: ToolSchema<ResourcePreviewArgs> = {\n parse(value) {\n if (\n value === null ||\n typeof value !== 'object' ||\n typeof Reflect.get(value, 'guid') !== 'string'\n ) {\n return { ok: false, error: 'expected { guid: string }' };\n }\n const guid = Reflect.get(value, 'guid');\n if (guid.length === 0) return { ok: false, error: 'guid must not be empty' };\n const size = Reflect.get(value, 'size');\n if (size === undefined) return { ok: true, value: { guid } };\n return isResourcePreviewSize(size)\n ? { ok: true, value: { guid, size } }\n : {\n ok: false,\n error: `size must be a power of two between ${RESOURCE_PREVIEW_MIN_SIZE} and ${RESOURCE_PREVIEW_MAX_SIZE}`,\n };\n },\n describe: `{\"type\":\"object\",\"required\":[\"guid\"],\"properties\":{\"guid\":{\"type\":\"string\"},\"size\":{\"type\":\"integer\",\"minimum\":${RESOURCE_PREVIEW_MIN_SIZE},\"maximum\":${RESOURCE_PREVIEW_MAX_SIZE},\"description\":\"square power-of-two screenshot edge; defaults to ${RESOURCE_PREVIEW_DEFAULT_SIZE}\"}}}`,\n};\n\nexport function subjectDescriptor(\n kind: PreviewSubjectKind,\n): ToolDescriptor<ResourcePreviewArgs, unknown> {\n return {\n id: `${kind}.preview`,\n title: `Preview ${kind}`,\n summary: `Preview one ${kind} asset in the Engine-owned resource host.`,\n realm: 'host',\n argsSchema: resourcePreviewArgsSchema,\n resultSchema: resourcePreviewResultSchema,\n evidence: ['rhi-tape', 'profile-capture', 'png'],\n };\n}\n\nexport type SubjectExecutor = (args: ResourcePreviewArgs, context: ToolExecutionContext) => unknown;\n\nexport interface ResourceSubjectFailure {\n readonly ok: false;\n readonly error: {\n readonly code:\n | 'resource-preview-subject-invalid'\n | 'resource-preview-kind-mismatch'\n | 'resource-preview-oracle-failed';\n readonly expected: string;\n readonly hint: string;\n readonly detail: Readonly<Record<string, JsonValue>>;\n };\n}\n\nexport function subjectFailure(\n code: ResourceSubjectFailure['error']['code'],\n expected: string,\n detail: Readonly<Record<string, JsonValue>>,\n): ResourceSubjectFailure {\n return {\n ok: false,\n error: {\n code,\n expected,\n hint: 'Load the requested GUID through AssetRegistry.load(guid, kind) and repair the owner facts before retrying.',\n detail,\n },\n };\n}\n\nexport function assetLoadFailure(\n expected: string,\n runId: string,\n error: unknown,\n): ResourceSubjectFailure {\n const owner = isRecord(error) ? error : undefined;\n const ownerCode = typeof owner?.code === 'string' ? owner.code : undefined;\n const ownerExpected = typeof owner?.expected === 'string' ? owner.expected : undefined;\n const ownerHint = typeof owner?.hint === 'string' ? owner.hint : undefined;\n const ownerDetail = owner?.detail;\n return subjectFailure('resource-preview-subject-invalid', expected, {\n phase: 'asset-load',\n runId,\n ...(ownerCode === undefined ? {} : { ownerCode }),\n ...(ownerExpected === undefined ? {} : { ownerExpected }),\n ...(ownerHint === undefined ? {} : { ownerHint }),\n ...(ownerDetail === undefined ? {} : { ownerDetail: toJsonValue(ownerDetail) }),\n });\n}\n\nfunction toJsonValue(value: unknown): JsonValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return value;\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (Array.isArray(value)) return value.map((entry) => toJsonValue(entry));\n if (isRecord(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, entry]) => [key, toJsonValue(entry)]),\n );\n }\n return String(value);\n}\n\nexport function nativePreviewPlugin(\n kind: PreviewSubjectKind,\n contribution: ToolContribution<ResourcePreviewArgs, unknown>,\n) {\n return defineToolPlugin({ name: `forgeax-preview-${kind}`, apply() {} }, [\n contribution as ToolContribution<unknown, unknown>,\n ]);\n}\n\nexport async function failUnboundSubject(\n kind: PreviewSubjectKind,\n args: ResourcePreviewArgs,\n context: ToolExecutionContext,\n): Promise<unknown> {\n const host = context.require(previewHostCapability);\n if (!host.ok) return host;\n return host.value.withSession(async (mechanisms) => ({\n ...subjectFailure(\n 'resource-preview-subject-invalid',\n `${kind} asset ${args.guid} to be bound by its owner before rendering`,\n { phase: 'subject-binding', runId: mechanisms.runId },\n ),\n }));\n}\n","import { builtinAssetKind } from '@forgeax/engine-runtime';\nimport type { ArtifactRef } from '@forgeax/engine-tool-runtime';\nimport { evaluateMaterialOracle, type MaterialOracleInput } from '../evidence/oracle.js';\nimport type { PreviewAssetRegistry, PreviewRenderRuntime } from '../host/preview-host.js';\nimport { canonicalPresentation, createCanonicalPreviewRecipe } from '../kit/canonical.js';\nimport { assetLoadFailure, type ResourcePreviewArgs, subjectFailure } from './subject.js';\n\nexport interface MaterialSubjectInspection {\n readonly subjectDigest: string;\n readonly program: string;\n readonly pass: string;\n readonly bindingsDigest: string;\n readonly closureDigest: string;\n}\n\ntype InspectionResult =\n | { readonly ok: true; readonly value: MaterialSubjectInspection }\n | ReturnType<typeof subjectFailure>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction digest(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nexport function inspectMaterialSubject(input: {\n readonly guid: string;\n readonly asset: unknown;\n readonly digest?: string;\n readonly ownerFacts?: Readonly<Record<string, string | number | boolean>>;\n}): InspectionResult {\n if (!isRecord(input.asset) || input.asset.kind !== 'material') {\n return subjectFailure('resource-preview-kind-mismatch', 'a MaterialAsset with kind material', {\n phase: 'subject',\n guid: input.guid,\n actualKind:\n isRecord(input.asset) && typeof input.asset.kind === 'string'\n ? input.asset.kind\n : 'unknown',\n });\n }\n const passes = input.asset.passes;\n if (!Array.isArray(passes) || passes.length === 0) {\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'a MaterialAsset with at least one pass',\n {\n phase: 'subject',\n guid: input.guid,\n field: 'passes',\n },\n );\n }\n const first = passes[0];\n if (!isRecord(first) || typeof first.name !== 'string' || !isRecord(first.program)) {\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'every material pass to declare a program',\n {\n phase: 'subject',\n guid: input.guid,\n field: 'passes[0]',\n },\n );\n }\n if (typeof first.program.module !== 'string' || first.program.module.length === 0) {\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'the material program module identity to be present',\n {\n phase: 'subject',\n guid: input.guid,\n field: 'passes[0].program.module',\n },\n );\n }\n const owner = input.asset.ownerFacts;\n const ownerFacts = isRecord(owner) ? owner : input.ownerFacts;\n const subjectDigest = digest(input.asset.digest ?? input.digest ?? ownerFacts?.subjectDigest);\n const bindingsDigest = digest(input.asset.bindingsDigest ?? ownerFacts?.bindingsDigest);\n const closureDigest = digest(input.asset.closureDigest ?? ownerFacts?.closureDigest);\n if (subjectDigest === undefined || bindingsDigest === undefined || closureDigest === undefined) {\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'the MaterialAsset owner to publish subject, bindings, and closure digests',\n { phase: 'subject', guid: input.guid, field: 'ownerFacts' },\n );\n }\n return {\n ok: true,\n value: {\n subjectDigest,\n program: first.program.module,\n pass: first.name,\n bindingsDigest,\n closureDigest,\n },\n };\n}\n\nexport async function executeMaterialPreview(\n args: ResourcePreviewArgs,\n input: {\n readonly assets?: PreviewAssetRegistry;\n readonly renderer?: PreviewRenderRuntime;\n readonly rendererReady: boolean;\n readonly worldReady: boolean;\n readonly runId: string;\n readonly artifacts?: readonly ArtifactRef[];\n },\n) {\n if (input.assets === undefined)\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'resource preview host to expose the existing AssetRegistry',\n { phase: 'asset-registry', runId: input.runId },\n );\n const loaded = await input.assets.load(args.guid, builtinAssetKind('material'));\n if (!loaded.ok)\n return assetLoadFailure(\n 'AssetRegistry.load(guid, materialAssetKind) to resolve the requested material',\n input.runId,\n loaded.error,\n );\n const inspected = inspectMaterialSubject({\n guid: args.guid,\n asset: loaded.value,\n ...(loaded.digest === undefined ? {} : { digest: loaded.digest }),\n ...(loaded.ownerFacts === undefined ? {} : { ownerFacts: loaded.ownerFacts }),\n });\n if (!inspected.ok) return inspected;\n const renderer = input.renderer;\n if (\n !input.rendererReady ||\n !input.worldReady ||\n renderer === undefined ||\n renderer.drawCalls <= 0 ||\n renderer.nonBlackPixels <= 0 ||\n renderer.observation === undefined\n )\n return subjectFailure(\n 'resource-preview-oracle-failed',\n 'shared World and Renderer to be ready',\n { phase: 'renderer', runId: input.runId },\n );\n const observed: MaterialOracleInput['observed'] = {\n subjectDigest: digest(renderer.observation.subjectDigest) ?? '',\n program: digest(renderer.observation.program) ?? '',\n pass: digest(renderer.observation.pass) ?? '',\n bindingsDigest: digest(renderer.observation.bindingsDigest) ?? '',\n closureDigest: digest(renderer.observation.closureDigest) ?? '',\n rendererHealthy: input.rendererReady && input.worldReady,\n drawCalls: renderer.drawCalls,\n nonBlackPixels: renderer.nonBlackPixels,\n };\n const oracle = evaluateMaterialOracle({ requested: inspected.value, observed });\n if (oracle.status !== 'passed') {\n return subjectFailure(\n 'resource-preview-oracle-failed',\n 'the rendered material observation to match the loaded owner facts',\n { phase: 'oracle', runId: input.runId, ...oracle.detail },\n );\n }\n return {\n ok: true as const,\n value: {\n subject: {\n kind: 'material' as const,\n guid: args.guid,\n digest: inspected.value.subjectDigest,\n },\n presentation: canonicalPresentation('material'),\n recipe: createCanonicalPreviewRecipe('material'),\n oracle,\n artifacts: input.artifacts ?? [],\n },\n artifacts: input.artifacts ?? [],\n };\n}\n","import type {\n ArtifactRef,\n JsonValue,\n SnapshotRef,\n ToolDomainFailure,\n ToolEvidenceKind,\n ToolExecutionContext,\n ToolSubjectRef,\n} from '@forgeax/engine-tool-runtime';\nimport {\n createPreviewHost as createNativePreviewHost,\n type PreviewHost as NativePreviewHost,\n type PreviewHostMechanisms,\n} from './host/preview-host.js';\n\nexport interface PreviewHostRequest {\n readonly subject: ToolSubjectRef;\n readonly snapshot: SnapshotRef;\n}\n\nexport interface PreviewAssetBinding {\n readonly guid: string;\n readonly bytes: number;\n}\n\nexport interface PreviewFrameInput {\n readonly frame: number;\n readonly deltaSeconds: number;\n}\n\nexport interface PreviewCapture {\n readonly digest: string;\n readonly bytes: number;\n}\n\nexport interface PreviewResourceCensus {\n readonly worlds: number;\n readonly renderers: number;\n readonly canvases: number;\n readonly leases: number;\n}\n\nexport interface PreviewCleanupReport {\n readonly census: PreviewResourceCensus;\n readonly failures: readonly string[];\n}\n\n/**\n * The only resource surface exposed to a preview contribution. The adapter owns\n * the actual Engine resources; callers receive POD bindings and bounded actions.\n */\nexport interface PreviewHostSession {\n readonly subject: ToolSubjectRef;\n readonly snapshot: SnapshotRef;\n readonly loadAsset: (guid: string) => Promise<PreviewAssetBinding>;\n readonly frame: (input: PreviewFrameInput) => Promise<void>;\n readonly capture: () => Promise<PreviewCapture & { readonly artifact?: ArtifactRef }>;\n readonly census: () => PreviewResourceCensus;\n readonly dispose: () => Promise<void>;\n}\n\nexport interface PreviewHostAdapter {\n readonly open: (request: PreviewHostRequest) => PreviewHostSession | Promise<PreviewHostSession>;\n}\n\nexport interface PreviewHost {\n readonly withSession: <TResult>(\n request: PreviewHostRequest,\n run: (session: PreviewHostSession) => TResult | Promise<TResult>,\n ) => Promise<{ readonly value: TResult; readonly cleanup: PreviewCleanupReport }>;\n}\n\nexport interface PreviewDomainValue<TReport = unknown> {\n readonly subject: ToolSubjectRef;\n readonly snapshot: SnapshotRef;\n readonly report: TReport;\n readonly artifacts: readonly ArtifactRef[];\n}\n\nexport type PreviewDomainResult<TReport = unknown> =\n | { readonly ok: true; readonly value: PreviewDomainValue<TReport> }\n | { readonly ok: false; readonly error: ToolDomainFailure };\n\nexport type PreviewDomainRunner<TRequest, TReport = unknown> = (\n request: TRequest,\n context: ToolExecutionContext,\n) => Promise<PreviewDomainResult<TReport>>;\n\nexport const REQUIRED_PREVIEW_EVIDENCE: readonly ToolEvidenceKind[] = [\n 'rhi-tape',\n 'png',\n 'profile-capture',\n];\n\nexport function domainFailure(\n code: string,\n expected: string,\n hint: string,\n detail: Record<string, JsonValue>,\n): { readonly ok: false; readonly error: ToolDomainFailure } {\n return { ok: false, error: { code, expected, hint, detail } };\n}\n\n/**\n * The default contribution is deliberately fail-closed. A real Project GUID\n * loader must install a PreviewHost/Browser/Dawn runner; a data-only request\n * must never manufacture PNG, RHI, or profile references from its arguments.\n */\nexport function previewRuntimeUnavailable(\n subject: ToolSubjectRef,\n snapshot: SnapshotRef,\n domain: string,\n): { readonly ok: false; readonly error: ToolDomainFailure } {\n return domainFailure(\n 'preview-runtime-unavailable',\n 'a Project GUID cold-load and an active PreviewHost/Browser/Dawn runner',\n 'Install the Project preview provider and retry; no synthetic artifact is published.',\n {\n domain,\n subjectKind: subject.kind,\n subjectGuid: subject.guid,\n snapshotRevision: snapshot.revision,\n snapshotDigest: snapshot.digest,\n requiredEvidence: REQUIRED_PREVIEW_EVIDENCE as unknown as JsonValue,\n },\n );\n}\n\nexport function validateDomainValue<TReport>(\n value: PreviewDomainValue<TReport>,\n request: PreviewHostRequest,\n): PreviewDomainResult<TReport> {\n if (\n value.subject.kind !== request.subject.kind ||\n value.subject.guid !== request.subject.guid ||\n value.snapshot.revision !== request.snapshot.revision ||\n value.snapshot.digest !== request.snapshot.digest\n ) {\n return domainFailure(\n 'preview-subject-identity-mismatch',\n 'the terminal subject and snapshot to match the request',\n 'Repair the domain producer so evidence remains bound to the requested subject.',\n {\n requestGuid: request.subject.guid,\n resultGuid: value.subject.guid,\n requestSnapshot: request.snapshot.digest,\n resultSnapshot: value.snapshot.digest,\n },\n );\n }\n const kinds = new Set(value.artifacts.map((artifact) => artifact.kind));\n const missing = REQUIRED_PREVIEW_EVIDENCE.filter((kind) => !kinds.has(kind));\n if (missing.length > 0) {\n return domainFailure(\n 'preview-evidence-incomplete',\n 'one subject-bound artifact for each required evidence kind',\n 'Repair the RHI, PNG, and profile producers before retrying.',\n { missing: missing as unknown as JsonValue },\n );\n }\n return { ok: true, value };\n}\n\nexport class PreviewCleanupError extends Error {\n readonly code = 'preview-cleanup-live-resources';\n readonly census: PreviewResourceCensus;\n\n constructor(census: PreviewResourceCensus, failures: readonly string[] = []) {\n super(\n failures.length === 0\n ? 'preview session left live resources after disposal'\n : `preview session cleanup failed: ${failures.join('; ')}`,\n );\n this.name = 'PreviewCleanupError';\n this.census = census;\n }\n}\n\nfunction hasLiveResources(census: PreviewResourceCensus): boolean {\n return Object.values(census).some((count) => count !== 0);\n}\n\nexport function createPreviewHost(adapter: PreviewHostAdapter): PreviewHost;\nexport function createPreviewHost(input: PreviewHostMechanisms): NativePreviewHost;\nexport function createPreviewHost(\n adapterOrInput: PreviewHostAdapter | PreviewHostMechanisms,\n): PreviewHost | NativePreviewHost {\n if ('runId' in adapterOrInput) return createNativePreviewHost(adapterOrInput);\n const adapter = adapterOrInput;\n const withSession = async <TResult>(\n request: PreviewHostRequest,\n run: (session: PreviewHostSession) => TResult | Promise<TResult>,\n ): Promise<{ readonly value: TResult; readonly cleanup: PreviewCleanupReport }> => {\n const session = await adapter.open(request);\n let result: TResult;\n try {\n result = await run(session);\n } finally {\n await session.dispose();\n }\n const cleanup: PreviewCleanupReport = { census: session.census(), failures: [] };\n if (hasLiveResources(cleanup.census)) {\n throw new PreviewCleanupError(cleanup.census, cleanup.failures);\n }\n return { value: result, cleanup };\n };\n\n return {\n withSession,\n };\n}\n","import {\n defineTool,\n type SnapshotRef,\n type ToolContribution,\n type ToolPreviewContract,\n type ToolSchema,\n type ToolSubjectRef,\n} from '@forgeax/engine-tool-runtime';\nimport { executeMaterialPreview } from './domains/material.js';\nimport { nativePreviewPlugin, subjectDescriptor } from './domains/subject.js';\nimport { previewHostCapability } from './host/preview-host.js';\nimport {\n domainFailure,\n type PreviewDomainResult,\n type PreviewDomainRunner,\n previewRuntimeUnavailable,\n validateDomainValue,\n} from './host.js';\n\nexport interface MaterialBinding {\n readonly guid: string;\n readonly programDigest: string;\n readonly bindings: readonly string[];\n}\n\nexport interface MaterialPreviewRequest {\n readonly subject: ToolSubjectRef;\n readonly snapshot: SnapshotRef;\n readonly binding: MaterialBinding;\n}\n\nexport interface MaterialPreviewReport {\n readonly kind: 'material';\n readonly bindingGuid: string;\n readonly programDigest: string;\n readonly backgroundNonBlackPixels: number;\n readonly subjectNonBlackPixels: number;\n readonly presentation: 'sphere-studio';\n}\n\nconst materialPreviewArgsSchema: ToolSchema<MaterialPreviewRequest> = {\n parse(value) {\n if (value === null || typeof value !== 'object')\n return { ok: false, error: 'expected a material preview request object' };\n const request = value as Partial<MaterialPreviewRequest>;\n if (request.subject?.kind !== 'MaterialAsset' || typeof request.subject.guid !== 'string')\n return { ok: false, error: 'expected a MaterialAsset subject' };\n if (\n request.snapshot === undefined ||\n !Number.isSafeInteger(request.snapshot.revision) ||\n typeof request.snapshot.digest !== 'string'\n )\n return { ok: false, error: 'expected a revisioned snapshot' };\n const binding = request.binding;\n if (\n binding === undefined ||\n binding.guid !== request.subject.guid ||\n binding.programDigest.length === 0 ||\n binding.bindings.length === 0\n )\n return { ok: false, error: 'expected a bound MaterialAsset program and bindings' };\n return { ok: true, value: request as MaterialPreviewRequest };\n },\n describe:\n '{\"type\":\"object\",\"required\":[\"subject\",\"snapshot\",\"binding\"],\"properties\":{\"subject\":{\"type\":\"object\",\"required\":[\"kind\",\"guid\"],\"properties\":{\"kind\":{\"const\":\"MaterialAsset\"},\"guid\":{\"type\":\"string\"}}},\"snapshot\":{\"type\":\"object\",\"required\":[\"revision\",\"digest\"]},\"binding\":{\"type\":\"object\",\"required\":[\"guid\",\"programDigest\",\"bindings\"]}}}',\n};\n\nconst materialPreviewResultSchema: ToolSchema<unknown> = {\n parse: (value) => ({ ok: true, value }),\n describe: '{\"type\":\"object\",\"required\":[\"subject\",\"snapshot\",\"report\",\"artifacts\"]}',\n};\n\nexport const materialPreviewDescriptor = {\n id: 'material.preview',\n title: 'Preview material asset',\n summary: 'Renders one bound MaterialAsset on the fixed studio sphere presentation.',\n realm: 'engine' as const,\n argsSchema: materialPreviewArgsSchema,\n resultSchema: materialPreviewResultSchema,\n evidence: ['rhi-tape', 'png', 'profile-capture'] as const,\n preview: {\n realm: 'engine' as const,\n subject: { kind: 'MaterialAsset', guid: '<request>' },\n snapshot: { revision: 0, digest: '<request>' },\n requiredEvidence: ['rhi-tape', 'png', 'profile-capture'] as const,\n } satisfies ToolPreviewContract,\n};\n\nfunction defaultMaterialRunner(\n request: MaterialPreviewRequest,\n): Promise<PreviewDomainResult<MaterialPreviewReport>> {\n return Promise.resolve(previewRuntimeUnavailable(request.subject, request.snapshot, 'material'));\n}\n\nexport function createMaterialPreviewContribution(\n runner: PreviewDomainRunner<MaterialPreviewRequest, MaterialPreviewReport> = async (request) =>\n defaultMaterialRunner(request),\n): ToolContribution<MaterialPreviewRequest, unknown> {\n return defineTool(materialPreviewDescriptor, async (request, context) => {\n const result = await runner(request, context);\n if (!result.ok) return result;\n if (\n result.value.report.bindingGuid !== request.subject.guid ||\n result.value.report.subjectNonBlackPixels <= 0 ||\n result.value.report.backgroundNonBlackPixels <= 0 ||\n result.value.report.presentation !== 'sphere-studio'\n ) {\n return domainFailure(\n 'preview-subject-falsified',\n 'the requested material subject to render with a non-background studio presentation',\n 'Reject fallback geometry, disconnected bindings, and background-only captures.',\n {\n requestGuid: request.subject.guid,\n reportBindingGuid: result.value.report.bindingGuid,\n subjectNonBlackPixels: result.value.report.subjectNonBlackPixels,\n backgroundNonBlackPixels: result.value.report.backgroundNonBlackPixels,\n },\n );\n }\n const validated = validateDomainValue(result.value, request);\n if (!validated.ok) return validated;\n return { ok: true, value: validated.value };\n });\n}\n\nexport const materialPreview = defineTool(subjectDescriptor('material'), (args, context) =>\n (async () => {\n const host = context.require(previewHostCapability);\n if (!host.ok) return host;\n return host.value.withSession(async (mechanisms) =>\n executeMaterialPreview(args, {\n ...(mechanisms.assets === undefined ? {} : { assets: mechanisms.assets }),\n ...(mechanisms.renderer === undefined ? {} : { renderer: mechanisms.renderer }),\n rendererReady: mechanisms.renderer?.rendererReady === true,\n worldReady: mechanisms.renderer?.worldReady === true,\n runId: mechanisms.runId,\n ...(mechanisms.artifacts === undefined ? {} : { artifacts: mechanisms.artifacts }),\n }),\n );\n })(),\n);\nexport const materialPreviewPlugin = nativePreviewPlugin('material', materialPreview);\nexport default materialPreviewPlugin;\n"]}
1
+ {"version":3,"sources":["../src/evidence/oracle.ts","../src/kit/canonical.ts","../src/host/preview-host.ts","../src/domains/subject.ts","../src/domains/material.ts","../src/host.ts","../src/material.ts"],"names":["defineToolPlugin","isRecord"],"mappings":"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","file":"material.mjs","sourcesContent":["export type PreviewOracleStatus = PreviewOracle['status'];\n\nexport type PreviewOracle =\n | {\n readonly status: 'passed';\n readonly subjectBound: true;\n readonly drawCalls: number;\n readonly dispatches: number;\n readonly rendererHealthy: true;\n readonly detail: Record<string, string | number | boolean>;\n }\n | {\n readonly status: 'failed';\n readonly subjectBound: false;\n readonly drawCalls: number;\n readonly dispatches: number;\n readonly rendererHealthy: boolean;\n readonly detail: Record<string, string | number | boolean>;\n };\n\nexport function passedPreviewOracle(input: {\n readonly drawCalls: number;\n readonly dispatches?: number;\n readonly detail: Record<string, string | number | boolean>;\n}): PreviewOracle {\n return {\n status: 'passed',\n subjectBound: true,\n drawCalls: input.drawCalls,\n dispatches: input.dispatches ?? 0,\n rendererHealthy: true,\n detail: { ...input.detail },\n };\n}\n\nexport function failedPreviewOracle(input: {\n readonly drawCalls?: number;\n readonly dispatches?: number;\n readonly rendererHealthy?: boolean;\n readonly detail: Record<string, string | number | boolean>;\n}): PreviewOracle {\n return {\n status: 'failed',\n subjectBound: false,\n drawCalls: input.drawCalls ?? 0,\n dispatches: input.dispatches ?? 0,\n rendererHealthy: input.rendererHealthy ?? false,\n detail: { ...input.detail },\n };\n}\n\nexport interface MaterialOracleInput {\n readonly requested: {\n readonly subjectDigest: string;\n readonly program: string;\n readonly pass: string;\n readonly bindingsDigest: string;\n readonly closureDigest: string;\n };\n readonly observed: MaterialOracleInput['requested'] & {\n readonly rendererHealthy: boolean;\n readonly drawCalls: number;\n readonly nonBlackPixels: number;\n };\n}\n\nexport interface MeshOracleInput {\n readonly requested: {\n readonly subjectDigest: string;\n readonly vertexDigest: string;\n readonly indexDigest: string;\n readonly submeshDigest: string;\n readonly aabbDigest: string;\n readonly aabb?: readonly [number, number, number, number, number, number];\n readonly submeshCount?: number;\n readonly materialSlotCount?: number;\n };\n readonly observed: MeshOracleInput['requested'] & {\n readonly rendererHealthy: boolean;\n readonly drawCalls: number;\n readonly nonBlackPixels: number;\n };\n}\n\nfunction oracleDetail(\n kind: 'material' | 'mesh',\n requested: Record<string, unknown>,\n observed: Record<string, unknown>,\n mismatch: string | undefined,\n): Record<string, string | number | boolean> {\n return {\n kind,\n mismatch: mismatch ?? 'none',\n requestedSubjectDigest:\n typeof requested.subjectDigest === 'string' ? requested.subjectDigest : 'unknown',\n observedSubjectDigest:\n typeof observed.subjectDigest === 'string' ? observed.subjectDigest : 'unknown',\n requestedOwnerDigest: JSON.stringify(requested),\n observedOwnerDigest: JSON.stringify(observed),\n };\n}\n\nfunction firstMismatch(\n requested: Record<string, unknown>,\n observed: Record<string, unknown>,\n): string | undefined {\n for (const key of Object.keys(requested)) {\n const requestedValue = requested[key];\n const observedValue = observed[key];\n if (\n Array.isArray(requestedValue) ||\n Array.isArray(observedValue) ||\n typeof requestedValue === 'object' ||\n typeof observedValue === 'object'\n ) {\n if (JSON.stringify(requestedValue) !== JSON.stringify(observedValue)) return key;\n } else if (requestedValue !== observedValue) {\n return key;\n }\n }\n return undefined;\n}\n\nexport function evaluateMaterialOracle(input: MaterialOracleInput): PreviewOracle {\n const requested = input.requested as unknown as Record<string, string>;\n const observed = input.observed as unknown as Record<string, string>;\n const mismatch = firstMismatch(requested, observed);\n const healthy = input.observed.rendererHealthy && input.observed.drawCalls > 0;\n const detail = oracleDetail('material', requested, observed, mismatch);\n if (mismatch !== undefined || !healthy) {\n return failedPreviewOracle({\n drawCalls: input.observed.drawCalls,\n rendererHealthy: input.observed.rendererHealthy,\n detail: { ...detail, rendererHealthy: input.observed.rendererHealthy },\n });\n }\n return passedPreviewOracle({\n drawCalls: input.observed.drawCalls,\n detail: { ...detail, rendererHealthy: true },\n });\n}\n\nexport function evaluateMeshOracle(input: MeshOracleInput): PreviewOracle {\n const requested = input.requested as unknown as Record<string, string>;\n const observed = input.observed as unknown as Record<string, string>;\n const mismatch = firstMismatch(requested, observed);\n const healthy = input.observed.rendererHealthy && input.observed.drawCalls > 0;\n const detail = oracleDetail('mesh', requested, observed, mismatch);\n if (mismatch !== undefined || !healthy) {\n return failedPreviewOracle({\n drawCalls: input.observed.drawCalls,\n rendererHealthy: input.observed.rendererHealthy,\n detail: { ...detail, rendererHealthy: input.observed.rendererHealthy },\n });\n }\n return passedPreviewOracle({\n drawCalls: input.observed.drawCalls,\n detail: { ...detail, rendererHealthy: true },\n });\n}\n\nexport interface VfxOracleInput {\n readonly requested: {\n readonly subjectDigest: string;\n readonly programFingerprint: string;\n readonly emitterDigest: string;\n readonly sampleDigest: string;\n readonly boundsDigest: string;\n readonly computeDigest: string;\n readonly indirectDigest: string;\n readonly contactSheetDigest?: string;\n readonly authoredBounds?: readonly [number, number, number, number, number, number];\n readonly seed?: number;\n readonly fixedDelta?: number;\n readonly timelineFrames?: number;\n };\n readonly observed: VfxOracleInput['requested'] & {\n readonly rendererHealthy: boolean;\n readonly dispatches: number;\n readonly indirectDraws: number;\n readonly subjectOutputs: number;\n readonly nonBlackPixels: number;\n };\n}\n\nexport interface TextureOracleInput {\n readonly requested: {\n readonly subjectDigest: string;\n readonly boundDigest: string;\n readonly dimensions: readonly [number, number];\n readonly format: string;\n readonly colorSpace: string;\n readonly mipCount: number;\n readonly uvDigest: string;\n readonly filter: string;\n readonly bindingDigest: string;\n };\n readonly observed: TextureOracleInput['requested'] & {\n readonly rendererHealthy: boolean;\n readonly drawCalls: number;\n readonly nonBlackPixels: number;\n readonly payloadClass: 'black' | 'transparent' | 'single-channel' | 'color';\n };\n}\n\nfunction identityRecord(input: Record<string, unknown>): Record<string, string> {\n return Object.fromEntries(\n Object.entries(input).map(([key, value]) => [\n key,\n Array.isArray(value) ? JSON.stringify(value) : String(value),\n ]),\n );\n}\n\nfunction evaluateIdentityOracle(\n kind: 'vfx' | 'texture',\n requestedInput: Record<string, unknown>,\n observedInput: Record<string, unknown>,\n healthy: boolean,\n drawCalls: number,\n dispatches: number,\n detailOverrides: Record<string, string | number | boolean>,\n): PreviewOracle {\n const requested = identityRecord(requestedInput);\n const observed = identityRecord(observedInput);\n const mismatch = firstMismatch(requested, observed);\n const detail = {\n kind,\n mismatch: mismatch ?? 'none',\n requestedSubjectDigest: requested.subjectDigest ?? 'unknown',\n observedSubjectDigest: observed.subjectDigest ?? 'unknown',\n requestedOwnerDigest: JSON.stringify(requested),\n observedOwnerDigest: JSON.stringify(observed),\n ...detailOverrides,\n };\n if (mismatch !== undefined || !healthy) {\n return failedPreviewOracle({ drawCalls, dispatches, rendererHealthy: healthy, detail });\n }\n return passedPreviewOracle({ drawCalls, dispatches, detail });\n}\n\nexport function evaluateVfxOracle(input: VfxOracleInput): PreviewOracle {\n const observed = input.observed;\n const healthy =\n observed.rendererHealthy &&\n observed.dispatches > 0 &&\n observed.indirectDraws > 0 &&\n observed.subjectOutputs > 0;\n return evaluateIdentityOracle(\n 'vfx',\n input.requested,\n input.observed,\n healthy,\n observed.indirectDraws,\n observed.dispatches,\n {\n rendererHealthy: observed.rendererHealthy,\n indirectDraws: observed.indirectDraws,\n subjectOutputs: observed.subjectOutputs,\n nonBlackPixels: observed.nonBlackPixels,\n },\n );\n}\n\nexport function evaluateTextureOracle(input: TextureOracleInput): PreviewOracle {\n const observed = input.observed;\n return evaluateIdentityOracle(\n 'texture',\n input.requested,\n input.observed,\n observed.rendererHealthy && observed.drawCalls > 0,\n observed.drawCalls,\n 0,\n {\n rendererHealthy: observed.rendererHealthy,\n payloadClass: observed.payloadClass,\n nonBlackPixels: observed.nonBlackPixels,\n },\n );\n}\n","import type { PreviewPresentation, PreviewSubjectKind } from './presentation.js';\n\nexport interface CanonicalPreviewRecipe {\n readonly schemaVersion: '1.0.0';\n readonly rig:\n | Extract<PreviewPresentation, { readonly kind: 'lit-asset' }>['geometry']\n | 'asset-quad';\n readonly environment: 'engine-canonical' | 'black';\n readonly skybox: 'engine-canonical' | 'none';\n readonly skylight: 'engine-canonical' | 'none';\n readonly directionalLight: 'engine-canonical' | 'none';\n readonly stage: 'neutral-material-checker-unlit' | 'texture-unlit-black';\n readonly camera: 'bounds-derived' | 'texture-orthographic';\n readonly recipeDigest: string;\n}\n\nexport function createCanonicalPreviewRecipe(kind: PreviewSubjectKind): CanonicalPreviewRecipe {\n const texture = kind === 'texture';\n return {\n schemaVersion: '1.0.0',\n rig: kind === 'mesh' ? 'asset-mesh' : texture ? 'asset-quad' : 'handle-sphere',\n environment: texture ? 'black' : 'engine-canonical',\n skybox: texture ? 'none' : 'engine-canonical',\n skylight: texture ? 'none' : 'engine-canonical',\n directionalLight: texture ? 'none' : 'engine-canonical',\n stage: texture ? 'texture-unlit-black' : 'neutral-material-checker-unlit',\n camera: texture ? 'texture-orthographic' : 'bounds-derived',\n recipeDigest: `canonical:${kind}:${texture ? 'texture-orthographic' : 'bounds-derived'}`,\n };\n}\n\nexport function canonicalPresentation(kind: PreviewSubjectKind): PreviewPresentation {\n if (kind === 'texture') {\n return {\n kind: 'texture-unlit',\n geometry: 'aspect-quad',\n checkerboard: 'linear-alpha',\n };\n }\n return {\n kind: 'lit-asset',\n geometry: kind === 'mesh' ? 'asset-mesh' : 'handle-sphere',\n skylight: 'engine-canonical',\n directionalLight: 'engine-canonical',\n skybox: 'engine-canonical',\n };\n}\n","import { defineToolPlugin, type Plugin, type ToolPlugin } from '@forgeax/engine-plugin';\nimport {\n type ArtifactRef,\n defineToolCapability,\n type SnapshotRef,\n} from '@forgeax/engine-tool-runtime';\n\nexport interface PreviewAssetLoadResult<TAsset = unknown> {\n readonly ok: true;\n readonly value: TAsset;\n readonly digest?: string;\n readonly ownerFacts?: Readonly<Record<string, string | number | boolean>>;\n}\n\nexport interface PreviewAssetLoadFailure {\n readonly ok: false;\n readonly error: unknown;\n}\n\nexport interface PreviewAssetRegistry {\n readonly loadByGuid: <TAsset = unknown>(\n guid: string,\n ) => Promise<PreviewAssetLoadResult<TAsset> | PreviewAssetLoadFailure>;\n}\n\nexport interface PreviewRenderRuntime {\n readonly rendererReady: boolean;\n readonly worldReady: boolean;\n readonly drawCalls: number;\n readonly nonBlackPixels: number;\n /**\n * Facts read back from the real render/asset owner path. Domain executors\n * must not manufacture observed identity from the requested subject.\n */\n readonly observation?: Readonly<Record<string, string | number | boolean | readonly number[]>>;\n readonly vfx?: {\n readonly dispatches: number;\n readonly indirectDraws: number;\n readonly subjectOutputs: number;\n };\n readonly texture?: {\n readonly drawCalls: number;\n };\n}\n\nexport interface PreviewHostMechanisms {\n readonly runId: string;\n readonly snapshot: SnapshotRef;\n readonly projectRoot: string;\n readonly backend: 'webgpu';\n readonly signal: AbortSignal;\n readonly assets?: PreviewAssetRegistry;\n readonly renderer?: PreviewRenderRuntime;\n readonly artifacts?: readonly ArtifactRef[];\n}\n\nexport interface PreviewHost {\n readonly withSession: <T>(\n execute: (mechanisms: PreviewHostMechanisms) => Promise<T>,\n ) => Promise<T>;\n}\n\nexport const previewHostCapability = defineToolCapability<PreviewHost>('preview.host');\n\nexport function previewHostPlugin(host: PreviewHost): Plugin {\n return {\n name: 'forgeax-preview-host',\n provide: previewHostCapability.id,\n apply(ctx) {\n ctx.provide(previewHostCapability.id, host);\n },\n };\n}\n\nexport function bindPreviewHost(plugin: ToolPlugin, host: PreviewHost): ToolPlugin {\n return defineToolPlugin(previewHostPlugin(host), plugin.tools);\n}\n\nexport function createPreviewHost(input: PreviewHostMechanisms): PreviewHost {\n let active = true;\n return {\n async withSession(execute) {\n if (!active || input.signal.aborted) throw new Error('preview-host-session-terminal');\n try {\n return await execute(input);\n } finally {\n active = false;\n }\n },\n };\n}\n","import { defineToolPlugin } from '@forgeax/engine-plugin';\nimport type {\n JsonValue,\n ToolContribution,\n ToolDescriptor,\n ToolExecutionContext,\n ToolSchema,\n} from '@forgeax/engine-tool-runtime';\nimport { previewHostCapability } from '../host/preview-host.js';\nimport type { PreviewSubjectKind } from '../kit/presentation.js';\n\nexport interface ResourcePreviewArgs {\n readonly guid: string;\n /** Square screenshot edge in device pixels. Defaults to 512 and must be a power of two. */\n readonly size?: number;\n}\n\nexport const RESOURCE_PREVIEW_DEFAULT_SIZE = 512;\nexport const RESOURCE_PREVIEW_MIN_SIZE = 64;\nexport const RESOURCE_PREVIEW_MAX_SIZE = 4096;\n\nexport function isResourcePreviewSize(value: unknown): value is number {\n return (\n typeof value === 'number' &&\n Number.isSafeInteger(value) &&\n value >= RESOURCE_PREVIEW_MIN_SIZE &&\n value <= RESOURCE_PREVIEW_MAX_SIZE &&\n (value & (value - 1)) === 0\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0;\n}\n\n/** Keep the public result contract concrete at the ToolRuntime boundary. */\nfunction isResourcePreviewResult(value: unknown): boolean {\n if (!isRecord(value)) return false;\n const subject = value.subject;\n if (\n !isRecord(subject) ||\n !isString(subject.kind) ||\n !isString(subject.guid) ||\n !isString(subject.digest)\n )\n return false;\n if (!isRecord(value.presentation) || !isString(value.presentation.kind)) return false;\n if (\n !isRecord(value.recipe) ||\n !isString(value.recipe.schemaVersion) ||\n !isString(value.recipe.recipeDigest)\n )\n return false;\n if (!isRecord(value.oracle) || !isString(value.oracle.status)) return false;\n return Array.isArray(value.artifacts);\n}\n\nexport const resourcePreviewResultSchema: ToolSchema<unknown> = {\n parse(value) {\n return isResourcePreviewResult(value)\n ? { ok: true, value }\n : {\n ok: false,\n error:\n 'resource preview result must include subject, presentation, recipe, oracle, and artifacts',\n };\n },\n describe: '{\"type\":\"object\",\"required\":[\"subject\",\"presentation\",\"recipe\",\"oracle\",\"artifacts\"]}',\n};\n\nexport const resourcePreviewArgsSchema: ToolSchema<ResourcePreviewArgs> = {\n parse(value) {\n if (\n value === null ||\n typeof value !== 'object' ||\n typeof Reflect.get(value, 'guid') !== 'string'\n ) {\n return { ok: false, error: 'expected { guid: string }' };\n }\n const guid = Reflect.get(value, 'guid');\n if (guid.length === 0) return { ok: false, error: 'guid must not be empty' };\n const size = Reflect.get(value, 'size');\n if (size === undefined) return { ok: true, value: { guid } };\n return isResourcePreviewSize(size)\n ? { ok: true, value: { guid, size } }\n : {\n ok: false,\n error: `size must be a power of two between ${RESOURCE_PREVIEW_MIN_SIZE} and ${RESOURCE_PREVIEW_MAX_SIZE}`,\n };\n },\n describe: `{\"type\":\"object\",\"required\":[\"guid\"],\"properties\":{\"guid\":{\"type\":\"string\"},\"size\":{\"type\":\"integer\",\"minimum\":${RESOURCE_PREVIEW_MIN_SIZE},\"maximum\":${RESOURCE_PREVIEW_MAX_SIZE},\"description\":\"square power-of-two screenshot edge; defaults to ${RESOURCE_PREVIEW_DEFAULT_SIZE}\"}}}`,\n};\n\nexport function subjectDescriptor(\n kind: PreviewSubjectKind,\n): ToolDescriptor<ResourcePreviewArgs, unknown> {\n return {\n id: `${kind}.preview`,\n title: `Preview ${kind}`,\n summary: `Preview one ${kind} asset in the Engine-owned resource host.`,\n realm: 'host',\n argsSchema: resourcePreviewArgsSchema,\n resultSchema: resourcePreviewResultSchema,\n evidence: ['rhi-tape', 'profile-capture', 'png'],\n };\n}\n\nexport type SubjectExecutor = (args: ResourcePreviewArgs, context: ToolExecutionContext) => unknown;\n\nexport interface ResourceSubjectFailure {\n readonly ok: false;\n readonly error: {\n readonly code:\n | 'resource-preview-subject-invalid'\n | 'resource-preview-kind-mismatch'\n | 'resource-preview-oracle-failed';\n readonly expected: string;\n readonly hint: string;\n readonly detail: Readonly<Record<string, JsonValue>>;\n };\n}\n\nexport function subjectFailure(\n code: ResourceSubjectFailure['error']['code'],\n expected: string,\n detail: Readonly<Record<string, JsonValue>>,\n): ResourceSubjectFailure {\n return {\n ok: false,\n error: {\n code,\n expected,\n hint: 'Load the requested GUID through AssetRegistry.loadByGuid and repair the owner facts before retrying.',\n detail,\n },\n };\n}\n\nexport function assetLoadFailure(\n expected: string,\n runId: string,\n error: unknown,\n): ResourceSubjectFailure {\n const owner = isRecord(error) ? error : undefined;\n const ownerCode = typeof owner?.code === 'string' ? owner.code : undefined;\n const ownerExpected = typeof owner?.expected === 'string' ? owner.expected : undefined;\n const ownerHint = typeof owner?.hint === 'string' ? owner.hint : undefined;\n const ownerDetail = owner?.detail;\n return subjectFailure('resource-preview-subject-invalid', expected, {\n phase: 'asset-load',\n runId,\n ...(ownerCode === undefined ? {} : { ownerCode }),\n ...(ownerExpected === undefined ? {} : { ownerExpected }),\n ...(ownerHint === undefined ? {} : { ownerHint }),\n ...(ownerDetail === undefined ? {} : { ownerDetail: toJsonValue(ownerDetail) }),\n });\n}\n\nfunction toJsonValue(value: unknown): JsonValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean') return value;\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (Array.isArray(value)) return value.map((entry) => toJsonValue(entry));\n if (isRecord(value)) {\n return Object.fromEntries(\n Object.entries(value).map(([key, entry]) => [key, toJsonValue(entry)]),\n );\n }\n return String(value);\n}\n\nexport function nativePreviewPlugin(\n kind: PreviewSubjectKind,\n contribution: ToolContribution<ResourcePreviewArgs, unknown>,\n) {\n return defineToolPlugin({ name: `forgeax-preview-${kind}`, apply() {} }, [\n contribution as ToolContribution<unknown, unknown>,\n ]);\n}\n\nexport async function failUnboundSubject(\n kind: PreviewSubjectKind,\n args: ResourcePreviewArgs,\n context: ToolExecutionContext,\n): Promise<unknown> {\n const host = context.require(previewHostCapability);\n if (!host.ok) return host;\n return host.value.withSession(async (mechanisms) => ({\n ...subjectFailure(\n 'resource-preview-subject-invalid',\n `${kind} asset ${args.guid} to be bound by its owner before rendering`,\n { phase: 'subject-binding', runId: mechanisms.runId },\n ),\n }));\n}\n","import type { ArtifactRef } from '@forgeax/engine-tool-runtime';\nimport { evaluateMaterialOracle, type MaterialOracleInput } from '../evidence/oracle.js';\nimport type { PreviewAssetRegistry, PreviewRenderRuntime } from '../host/preview-host.js';\nimport { canonicalPresentation, createCanonicalPreviewRecipe } from '../kit/canonical.js';\nimport { assetLoadFailure, type ResourcePreviewArgs, subjectFailure } from './subject.js';\n\nexport interface MaterialSubjectInspection {\n readonly subjectDigest: string;\n readonly program: string;\n readonly pass: string;\n readonly bindingsDigest: string;\n readonly closureDigest: string;\n}\n\ntype InspectionResult =\n | { readonly ok: true; readonly value: MaterialSubjectInspection }\n | ReturnType<typeof subjectFailure>;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction digest(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nexport function inspectMaterialSubject(input: {\n readonly guid: string;\n readonly asset: unknown;\n readonly digest?: string;\n readonly ownerFacts?: Readonly<Record<string, string | number | boolean>>;\n}): InspectionResult {\n if (!isRecord(input.asset) || input.asset.kind !== 'material') {\n return subjectFailure('resource-preview-kind-mismatch', 'a MaterialAsset with kind material', {\n phase: 'subject',\n guid: input.guid,\n actualKind:\n isRecord(input.asset) && typeof input.asset.kind === 'string'\n ? input.asset.kind\n : 'unknown',\n });\n }\n const passes = input.asset.passes;\n if (!Array.isArray(passes) || passes.length === 0) {\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'a MaterialAsset with at least one pass',\n {\n phase: 'subject',\n guid: input.guid,\n field: 'passes',\n },\n );\n }\n const first = passes[0];\n if (!isRecord(first) || typeof first.name !== 'string' || !isRecord(first.program)) {\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'every material pass to declare a program',\n {\n phase: 'subject',\n guid: input.guid,\n field: 'passes[0]',\n },\n );\n }\n if (typeof first.program.module !== 'string' || first.program.module.length === 0) {\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'the material program module identity to be present',\n {\n phase: 'subject',\n guid: input.guid,\n field: 'passes[0].program.module',\n },\n );\n }\n const owner = input.asset.ownerFacts;\n const ownerFacts = isRecord(owner) ? owner : input.ownerFacts;\n const subjectDigest = digest(input.asset.digest ?? input.digest ?? ownerFacts?.subjectDigest);\n const bindingsDigest = digest(input.asset.bindingsDigest ?? ownerFacts?.bindingsDigest);\n const closureDigest = digest(input.asset.closureDigest ?? ownerFacts?.closureDigest);\n if (subjectDigest === undefined || bindingsDigest === undefined || closureDigest === undefined) {\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'the MaterialAsset owner to publish subject, bindings, and closure digests',\n { phase: 'subject', guid: input.guid, field: 'ownerFacts' },\n );\n }\n return {\n ok: true,\n value: {\n subjectDigest,\n program: first.program.module,\n pass: first.name,\n bindingsDigest,\n closureDigest,\n },\n };\n}\n\nexport async function executeMaterialPreview(\n args: ResourcePreviewArgs,\n input: {\n readonly assets?: PreviewAssetRegistry;\n readonly renderer?: PreviewRenderRuntime;\n readonly rendererReady: boolean;\n readonly worldReady: boolean;\n readonly runId: string;\n readonly artifacts?: readonly ArtifactRef[];\n },\n) {\n if (input.assets === undefined)\n return subjectFailure(\n 'resource-preview-subject-invalid',\n 'resource preview host to expose the existing AssetRegistry',\n { phase: 'asset-registry', runId: input.runId },\n );\n const loaded = await input.assets.loadByGuid<Record<string, unknown>>(args.guid);\n if (!loaded.ok)\n return assetLoadFailure(\n 'AssetRegistry.loadByGuid to resolve the requested material',\n input.runId,\n loaded.error,\n );\n const inspected = inspectMaterialSubject({\n guid: args.guid,\n asset: loaded.value,\n ...(loaded.digest === undefined ? {} : { digest: loaded.digest }),\n ...(loaded.ownerFacts === undefined ? {} : { ownerFacts: loaded.ownerFacts }),\n });\n if (!inspected.ok) return inspected;\n const renderer = input.renderer;\n if (\n !input.rendererReady ||\n !input.worldReady ||\n renderer === undefined ||\n renderer.drawCalls <= 0 ||\n renderer.nonBlackPixels <= 0 ||\n renderer.observation === undefined\n )\n return subjectFailure(\n 'resource-preview-oracle-failed',\n 'shared World and Renderer to be ready',\n { phase: 'renderer', runId: input.runId },\n );\n const observed: MaterialOracleInput['observed'] = {\n subjectDigest: digest(renderer.observation.subjectDigest) ?? '',\n program: digest(renderer.observation.program) ?? '',\n pass: digest(renderer.observation.pass) ?? '',\n bindingsDigest: digest(renderer.observation.bindingsDigest) ?? '',\n closureDigest: digest(renderer.observation.closureDigest) ?? '',\n rendererHealthy: input.rendererReady && input.worldReady,\n drawCalls: renderer.drawCalls,\n nonBlackPixels: renderer.nonBlackPixels,\n };\n const oracle = evaluateMaterialOracle({ requested: inspected.value, observed });\n if (oracle.status !== 'passed') {\n return subjectFailure(\n 'resource-preview-oracle-failed',\n 'the rendered material observation to match the loaded owner facts',\n { phase: 'oracle', runId: input.runId, ...oracle.detail },\n );\n }\n return {\n ok: true as const,\n value: {\n subject: {\n kind: 'material' as const,\n guid: args.guid,\n digest: inspected.value.subjectDigest,\n },\n presentation: canonicalPresentation('material'),\n recipe: createCanonicalPreviewRecipe('material'),\n oracle,\n artifacts: input.artifacts ?? [],\n },\n artifacts: input.artifacts ?? [],\n };\n}\n","import type {\n ArtifactRef,\n JsonValue,\n SnapshotRef,\n ToolDomainFailure,\n ToolEvidenceKind,\n ToolExecutionContext,\n ToolSubjectRef,\n} from '@forgeax/engine-tool-runtime';\nimport {\n createPreviewHost as createNativePreviewHost,\n type PreviewHost as NativePreviewHost,\n type PreviewHostMechanisms,\n} from './host/preview-host.js';\n\nexport interface PreviewHostRequest {\n readonly subject: ToolSubjectRef;\n readonly snapshot: SnapshotRef;\n}\n\nexport interface PreviewAssetBinding {\n readonly guid: string;\n readonly bytes: number;\n}\n\nexport interface PreviewFrameInput {\n readonly frame: number;\n readonly deltaSeconds: number;\n}\n\nexport interface PreviewCapture {\n readonly digest: string;\n readonly bytes: number;\n}\n\nexport interface PreviewResourceCensus {\n readonly worlds: number;\n readonly renderers: number;\n readonly canvases: number;\n readonly leases: number;\n}\n\nexport interface PreviewCleanupReport {\n readonly census: PreviewResourceCensus;\n readonly failures: readonly string[];\n}\n\n/**\n * The only resource surface exposed to a preview contribution. The adapter owns\n * the actual Engine resources; callers receive POD bindings and bounded actions.\n */\nexport interface PreviewHostSession {\n readonly subject: ToolSubjectRef;\n readonly snapshot: SnapshotRef;\n readonly loadAsset: (guid: string) => Promise<PreviewAssetBinding>;\n readonly frame: (input: PreviewFrameInput) => Promise<void>;\n readonly capture: () => Promise<PreviewCapture & { readonly artifact?: ArtifactRef }>;\n readonly census: () => PreviewResourceCensus;\n readonly dispose: () => Promise<void>;\n}\n\nexport interface PreviewHostAdapter {\n readonly open: (request: PreviewHostRequest) => PreviewHostSession | Promise<PreviewHostSession>;\n}\n\nexport interface PreviewHost {\n readonly withSession: <TResult>(\n request: PreviewHostRequest,\n run: (session: PreviewHostSession) => TResult | Promise<TResult>,\n ) => Promise<{ readonly value: TResult; readonly cleanup: PreviewCleanupReport }>;\n}\n\nexport interface PreviewDomainValue<TReport = unknown> {\n readonly subject: ToolSubjectRef;\n readonly snapshot: SnapshotRef;\n readonly report: TReport;\n readonly artifacts: readonly ArtifactRef[];\n}\n\nexport type PreviewDomainResult<TReport = unknown> =\n | { readonly ok: true; readonly value: PreviewDomainValue<TReport> }\n | { readonly ok: false; readonly error: ToolDomainFailure };\n\nexport type PreviewDomainRunner<TRequest, TReport = unknown> = (\n request: TRequest,\n context: ToolExecutionContext,\n) => Promise<PreviewDomainResult<TReport>>;\n\nexport const REQUIRED_PREVIEW_EVIDENCE: readonly ToolEvidenceKind[] = [\n 'rhi-tape',\n 'png',\n 'profile-capture',\n];\n\nexport function domainFailure(\n code: string,\n expected: string,\n hint: string,\n detail: Record<string, JsonValue>,\n): { readonly ok: false; readonly error: ToolDomainFailure } {\n return { ok: false, error: { code, expected, hint, detail } };\n}\n\n/**\n * The default contribution is deliberately fail-closed. A real Project GUID\n * loader must install a PreviewHost/Browser/Dawn runner; a data-only request\n * must never manufacture PNG, RHI, or profile references from its arguments.\n */\nexport function previewRuntimeUnavailable(\n subject: ToolSubjectRef,\n snapshot: SnapshotRef,\n domain: string,\n): { readonly ok: false; readonly error: ToolDomainFailure } {\n return domainFailure(\n 'preview-runtime-unavailable',\n 'a Project GUID cold-load and an active PreviewHost/Browser/Dawn runner',\n 'Install the Project preview provider and retry; no synthetic artifact is published.',\n {\n domain,\n subjectKind: subject.kind,\n subjectGuid: subject.guid,\n snapshotRevision: snapshot.revision,\n snapshotDigest: snapshot.digest,\n requiredEvidence: REQUIRED_PREVIEW_EVIDENCE as unknown as JsonValue,\n },\n );\n}\n\nexport function validateDomainValue<TReport>(\n value: PreviewDomainValue<TReport>,\n request: PreviewHostRequest,\n): PreviewDomainResult<TReport> {\n if (\n value.subject.kind !== request.subject.kind ||\n value.subject.guid !== request.subject.guid ||\n value.snapshot.revision !== request.snapshot.revision ||\n value.snapshot.digest !== request.snapshot.digest\n ) {\n return domainFailure(\n 'preview-subject-identity-mismatch',\n 'the terminal subject and snapshot to match the request',\n 'Repair the domain producer so evidence remains bound to the requested subject.',\n {\n requestGuid: request.subject.guid,\n resultGuid: value.subject.guid,\n requestSnapshot: request.snapshot.digest,\n resultSnapshot: value.snapshot.digest,\n },\n );\n }\n const kinds = new Set(value.artifacts.map((artifact) => artifact.kind));\n const missing = REQUIRED_PREVIEW_EVIDENCE.filter((kind) => !kinds.has(kind));\n if (missing.length > 0) {\n return domainFailure(\n 'preview-evidence-incomplete',\n 'one subject-bound artifact for each required evidence kind',\n 'Repair the RHI, PNG, and profile producers before retrying.',\n { missing: missing as unknown as JsonValue },\n );\n }\n return { ok: true, value };\n}\n\nexport class PreviewCleanupError extends Error {\n readonly code = 'preview-cleanup-live-resources';\n readonly census: PreviewResourceCensus;\n\n constructor(census: PreviewResourceCensus, failures: readonly string[] = []) {\n super(\n failures.length === 0\n ? 'preview session left live resources after disposal'\n : `preview session cleanup failed: ${failures.join('; ')}`,\n );\n this.name = 'PreviewCleanupError';\n this.census = census;\n }\n}\n\nfunction hasLiveResources(census: PreviewResourceCensus): boolean {\n return Object.values(census).some((count) => count !== 0);\n}\n\nexport function createPreviewHost(adapter: PreviewHostAdapter): PreviewHost;\nexport function createPreviewHost(input: PreviewHostMechanisms): NativePreviewHost;\nexport function createPreviewHost(\n adapterOrInput: PreviewHostAdapter | PreviewHostMechanisms,\n): PreviewHost | NativePreviewHost {\n if ('runId' in adapterOrInput) return createNativePreviewHost(adapterOrInput);\n const adapter = adapterOrInput;\n const withSession = async <TResult>(\n request: PreviewHostRequest,\n run: (session: PreviewHostSession) => TResult | Promise<TResult>,\n ): Promise<{ readonly value: TResult; readonly cleanup: PreviewCleanupReport }> => {\n const session = await adapter.open(request);\n let result: TResult;\n try {\n result = await run(session);\n } finally {\n await session.dispose();\n }\n const cleanup: PreviewCleanupReport = { census: session.census(), failures: [] };\n if (hasLiveResources(cleanup.census)) {\n throw new PreviewCleanupError(cleanup.census, cleanup.failures);\n }\n return { value: result, cleanup };\n };\n\n return {\n withSession,\n };\n}\n","import {\n defineTool,\n type SnapshotRef,\n type ToolContribution,\n type ToolPreviewContract,\n type ToolSchema,\n type ToolSubjectRef,\n} from '@forgeax/engine-tool-runtime';\nimport { executeMaterialPreview } from './domains/material.js';\nimport { nativePreviewPlugin, subjectDescriptor } from './domains/subject.js';\nimport { previewHostCapability } from './host/preview-host.js';\nimport {\n domainFailure,\n type PreviewDomainResult,\n type PreviewDomainRunner,\n previewRuntimeUnavailable,\n validateDomainValue,\n} from './host.js';\n\nexport interface MaterialBinding {\n readonly guid: string;\n readonly programDigest: string;\n readonly bindings: readonly string[];\n}\n\nexport interface MaterialPreviewRequest {\n readonly subject: ToolSubjectRef;\n readonly snapshot: SnapshotRef;\n readonly binding: MaterialBinding;\n}\n\nexport interface MaterialPreviewReport {\n readonly kind: 'material';\n readonly bindingGuid: string;\n readonly programDigest: string;\n readonly backgroundNonBlackPixels: number;\n readonly subjectNonBlackPixels: number;\n readonly presentation: 'sphere-studio';\n}\n\nconst materialPreviewArgsSchema: ToolSchema<MaterialPreviewRequest> = {\n parse(value) {\n if (value === null || typeof value !== 'object')\n return { ok: false, error: 'expected a material preview request object' };\n const request = value as Partial<MaterialPreviewRequest>;\n if (request.subject?.kind !== 'MaterialAsset' || typeof request.subject.guid !== 'string')\n return { ok: false, error: 'expected a MaterialAsset subject' };\n if (\n request.snapshot === undefined ||\n !Number.isSafeInteger(request.snapshot.revision) ||\n typeof request.snapshot.digest !== 'string'\n )\n return { ok: false, error: 'expected a revisioned snapshot' };\n const binding = request.binding;\n if (\n binding === undefined ||\n binding.guid !== request.subject.guid ||\n binding.programDigest.length === 0 ||\n binding.bindings.length === 0\n )\n return { ok: false, error: 'expected a bound MaterialAsset program and bindings' };\n return { ok: true, value: request as MaterialPreviewRequest };\n },\n describe:\n '{\"type\":\"object\",\"required\":[\"subject\",\"snapshot\",\"binding\"],\"properties\":{\"subject\":{\"type\":\"object\",\"required\":[\"kind\",\"guid\"],\"properties\":{\"kind\":{\"const\":\"MaterialAsset\"},\"guid\":{\"type\":\"string\"}}},\"snapshot\":{\"type\":\"object\",\"required\":[\"revision\",\"digest\"]},\"binding\":{\"type\":\"object\",\"required\":[\"guid\",\"programDigest\",\"bindings\"]}}}',\n};\n\nconst materialPreviewResultSchema: ToolSchema<unknown> = {\n parse: (value) => ({ ok: true, value }),\n describe: '{\"type\":\"object\",\"required\":[\"subject\",\"snapshot\",\"report\",\"artifacts\"]}',\n};\n\nexport const materialPreviewDescriptor = {\n id: 'material.preview',\n title: 'Preview material asset',\n summary: 'Renders one bound MaterialAsset on the fixed studio sphere presentation.',\n realm: 'engine' as const,\n argsSchema: materialPreviewArgsSchema,\n resultSchema: materialPreviewResultSchema,\n evidence: ['rhi-tape', 'png', 'profile-capture'] as const,\n preview: {\n realm: 'engine' as const,\n subject: { kind: 'MaterialAsset', guid: '<request>' },\n snapshot: { revision: 0, digest: '<request>' },\n requiredEvidence: ['rhi-tape', 'png', 'profile-capture'] as const,\n } satisfies ToolPreviewContract,\n};\n\nfunction defaultMaterialRunner(\n request: MaterialPreviewRequest,\n): Promise<PreviewDomainResult<MaterialPreviewReport>> {\n return Promise.resolve(previewRuntimeUnavailable(request.subject, request.snapshot, 'material'));\n}\n\nexport function createMaterialPreviewContribution(\n runner: PreviewDomainRunner<MaterialPreviewRequest, MaterialPreviewReport> = async (request) =>\n defaultMaterialRunner(request),\n): ToolContribution<MaterialPreviewRequest, unknown> {\n return defineTool(materialPreviewDescriptor, async (request, context) => {\n const result = await runner(request, context);\n if (!result.ok) return result;\n if (\n result.value.report.bindingGuid !== request.subject.guid ||\n result.value.report.subjectNonBlackPixels <= 0 ||\n result.value.report.backgroundNonBlackPixels <= 0 ||\n result.value.report.presentation !== 'sphere-studio'\n ) {\n return domainFailure(\n 'preview-subject-falsified',\n 'the requested material subject to render with a non-background studio presentation',\n 'Reject fallback geometry, disconnected bindings, and background-only captures.',\n {\n requestGuid: request.subject.guid,\n reportBindingGuid: result.value.report.bindingGuid,\n subjectNonBlackPixels: result.value.report.subjectNonBlackPixels,\n backgroundNonBlackPixels: result.value.report.backgroundNonBlackPixels,\n },\n );\n }\n const validated = validateDomainValue(result.value, request);\n if (!validated.ok) return validated;\n return { ok: true, value: validated.value };\n });\n}\n\nexport const materialPreview = defineTool(subjectDescriptor('material'), (args, context) =>\n (async () => {\n const host = context.require(previewHostCapability);\n if (!host.ok) return host;\n return host.value.withSession(async (mechanisms) =>\n executeMaterialPreview(args, {\n ...(mechanisms.assets === undefined ? {} : { assets: mechanisms.assets }),\n ...(mechanisms.renderer === undefined ? {} : { renderer: mechanisms.renderer }),\n rendererReady: mechanisms.renderer?.rendererReady === true,\n worldReady: mechanisms.renderer?.worldReady === true,\n runId: mechanisms.runId,\n ...(mechanisms.artifacts === undefined ? {} : { artifacts: mechanisms.artifacts }),\n }),\n );\n })(),\n);\nexport const materialPreviewPlugin = nativePreviewPlugin('material', materialPreview);\nexport default materialPreviewPlugin;\n"]}
package/dist/mesh.mjs CHANGED
@@ -1,5 +1,4 @@
1
1
  import { defineToolCapability, defineTool } from '@forgeax/engine-tool-runtime';
2
- import { builtinAssetKind } from '@forgeax/engine-runtime';
3
2
  import { defineToolPlugin } from '@forgeax/engine-plugin';
4
3
 
5
4
  // src/mesh.ts
@@ -158,7 +157,7 @@ function subjectFailure(code, expected, detail) {
158
157
  error: {
159
158
  code,
160
159
  expected,
161
- hint: "Load the requested GUID through AssetRegistry.load(guid, kind) and repair the owner facts before retrying.",
160
+ hint: "Load the requested GUID through AssetRegistry.loadByGuid and repair the owner facts before retrying.",
162
161
  detail
163
162
  }
164
163
  };
@@ -322,10 +321,10 @@ async function executeMeshPreview(args, input) {
322
321
  "resource preview host to expose the existing AssetRegistry",
323
322
  { phase: "asset-registry", runId: input.runId }
324
323
  );
325
- const loaded = await input.assets.load(args.guid, builtinAssetKind("mesh"));
324
+ const loaded = await input.assets.loadByGuid(args.guid);
326
325
  if (!loaded.ok)
327
326
  return assetLoadFailure(
328
- "AssetRegistry.load(guid, meshAssetKind) to resolve the requested mesh",
327
+ "AssetRegistry.loadByGuid to resolve the requested mesh",
329
328
  input.runId,
330
329
  loaded.error
331
330
  );