import { blockedGate, capabilityIssue, readyGate, type CapabilityGateResult } from "./capability-gates"; import type { ErrorCode } from "./error"; import { normalizeProjectAssetPath } from "./asset-path"; export const SEQUENCER_SCHEMA = 1 as const; export const SEQUENCER_BUDGET = { maxStrips: 100_000, maxChannels: 128, maxFrames: 1_000_000, maxDependencies: 64, maxImageElements: 100_000, } as const; export type SequencerStripType = "SCENE" | "MOVIE" | "IMAGE" | "SOUND" | "EFFECT" | "META"; export interface SequencerProxyIR { status: "MISSING" | "AVAILABLE" | "STALE"; assetId?: string; width?: number; height?: number; quality?: number; sha256?: string; } export interface SequencerStripIR { id: string; name: string; type: SequencerStripType; channel: number; frameStart: number; frameEnd: number; sourceStart: number; sourceEnd: number; speed: number; muted: boolean; locked: boolean; sourceId?: string; sourcePath?: string; mimeType?: string; imageAssetIds?: string[]; effectType?: "CROSS" | "GAMMA_CROSS" | "ADD" | "MULTIPLY" | "TRANSFORM" | "COLOR"; inputStripIds?: string[]; childStripIds?: string[]; proxy?: SequencerProxyIR; } export interface SequencerTimelineIR { schemaVersion: typeof SEQUENCER_SCHEMA; id: string; revision: number; frameStart: number; frameEnd: number; fpsNumerator: number; fpsDenominator: number; strips: SequencerStripIR[]; } export type SequencerEditIR = | { type: "MOVE"; revision: number; stripId: string; frameDelta: number; channel?: number } | { type: "TRIM"; revision: number; stripId: string; frameStart?: number; frameEnd?: number } | { type: "SPLIT"; revision: number; stripId: string; frame: number; rightStripId: string }; export interface SequencerRuntimeCapabilityIR { webCodecsVideo: "PROBE_REQUIRED" | "UNAVAILABLE"; webCodecsAudio: "PROBE_REQUIRED" | "UNAVAILABLE"; htmlMedia: "PROBE_REQUIRED" | "UNAVAILABLE"; localEncoding: "BLOCKED"; } export const SEQUENCER_CODEC_PROBE_SCHEMA = 1 as const; export const SEQUENCER_CODEC_PROBE_MAX_BYTES = 512 * 1024 * 1024; export type SequencerCodecStripType = "IMAGE" | "SOUND" | "MOVIE"; export type SequencerCodecProbeBackend = "IMAGE_BITMAP" | "WEB_AUDIO" | "HTML_MEDIA"; export type SequencerCodecProbeBlockReason = | "RUNTIME_UNAVAILABLE" | "MIME_UNSUPPORTED" | "SOURCE_IDENTITY_MISMATCH" | "DECODE_FAILED"; export interface SequencerCodecProbeRequestIR { schemaVersion: typeof SEQUENCER_CODEC_PROBE_SCHEMA; stripType: SequencerCodecStripType; mimeType: string; byteLength: number; sourceSha256: string; } export interface SequencerCodecProbeResultIR extends SequencerCodecProbeRequestIR { status: "READY" | "BLOCKED"; backend: SequencerCodecProbeBackend | null; reason: SequencerCodecProbeBlockReason | null; decoded: { width?: number; height?: number; sampleRate?: number; channels?: number; durationFrames?: number; durationMicros?: number; } | null; } export interface SequencerFrameStripIR { stripId: string; channel: number; sourceFrame: number; dependencyStripIds: string[]; } export interface SequencerTransitionFrameIR { effectStripId: string; effectType: "CROSS" | "GAMMA_CROSS"; factor: number; from: { stripId: string; sourceFrame: number }; to: { stripId: string; sourceFrame: number }; } export class SequencerValidationError extends Error { readonly code: ErrorCode; constructor(code: ErrorCode, message: string) { super(`${code}: ${message}`); this.name = "SequencerValidationError"; this.code = code; } } const SHA256 = /^[a-f0-9]{64}$/; const STRIP_TYPES = new Set(["SCENE", "MOVIE", "IMAGE", "SOUND", "EFFECT", "META"]); const CODEC_STRIP_TYPES = new Set(["IMAGE", "SOUND", "MOVIE"]); const CODEC_BACKENDS: Readonly> = { IMAGE: "IMAGE_BITMAP", SOUND: "WEB_AUDIO", MOVIE: "HTML_MEDIA", }; const CODEC_MIME_PREFIX: Readonly> = { IMAGE: "image/", SOUND: "audio/", MOVIE: "video/", }; const CODEC_BLOCK_REASONS = new Set([ "RUNTIME_UNAVAILABLE", "MIME_UNSUPPORTED", "SOURCE_IDENTITY_MISMATCH", "DECODE_FAILED", ]); function record(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } function text(value: unknown, name: string, maximum = 256): string { if (typeof value !== "string" || value.length === 0 || value.length > maximum) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `${name} is invalid`); return value; } function integer(value: unknown, name: string, minimum: number, maximum: number): number { if (typeof value !== "number" || !Number.isSafeInteger(value) || value < minimum || value > maximum) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `${name} is outside the bounded range`); return value; } function parseProxy(value: unknown, index: number): SequencerProxyIR | undefined { if (value === undefined) return undefined; if (!record(value) || !["MISSING", "AVAILABLE", "STALE"].includes(value.status as string)) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `strips[${index}].proxy is invalid`); const proxy: SequencerProxyIR = { status: value.status as SequencerProxyIR["status"] }; if (value.assetId !== undefined) proxy.assetId = text(value.assetId, `strips[${index}].proxy.assetId`); if (value.width !== undefined) proxy.width = integer(value.width, `strips[${index}].proxy.width`, 1, 16_384); if (value.height !== undefined) proxy.height = integer(value.height, `strips[${index}].proxy.height`, 1, 16_384); if (value.quality !== undefined) proxy.quality = integer(value.quality, `strips[${index}].proxy.quality`, 0, 100); if (value.sha256 !== undefined) { if (typeof value.sha256 !== "string" || !SHA256.test(value.sha256)) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `strips[${index}].proxy.sha256 is invalid`); proxy.sha256 = value.sha256; } if (proxy.status === "AVAILABLE" && (!proxy.assetId || !proxy.sha256)) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `strips[${index}] available proxy requires assetId and sha256`); return proxy; } export function parseSequencerTimeline(value: unknown): SequencerTimelineIR { if (!record(value) || value.schemaVersion !== SEQUENCER_SCHEMA || !Array.isArray(value.strips)) throw new SequencerValidationError("PROTOCOL_MISMATCH", "Unsupported Sequencer timeline schema"); if (value.strips.length > SEQUENCER_BUDGET.maxStrips) throw new SequencerValidationError("SEQUENCER_BUDGET_EXCEEDED", "Sequencer strip count exceeds the budget"); const frameStart = integer(value.frameStart, "frameStart", -SEQUENCER_BUDGET.maxFrames, SEQUENCER_BUDGET.maxFrames); const frameEnd = integer(value.frameEnd, "frameEnd", -SEQUENCER_BUDGET.maxFrames, SEQUENCER_BUDGET.maxFrames); if (frameEnd < frameStart) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", "Timeline frame range is invalid"); const ids = new Set(); const strips = value.strips.map((item, index): SequencerStripIR => { if (!record(item) || !STRIP_TYPES.has(item.type as SequencerStripType)) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `strips[${index}] is invalid`); const id = text(item.id, `strips[${index}].id`); if (ids.has(id)) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `Duplicate strip ${id}`); ids.add(id); const start = integer(item.frameStart, `strips[${index}].frameStart`, -SEQUENCER_BUDGET.maxFrames, SEQUENCER_BUDGET.maxFrames); const end = integer(item.frameEnd, `strips[${index}].frameEnd`, -SEQUENCER_BUDGET.maxFrames, SEQUENCER_BUDGET.maxFrames); const sourceStart = integer(item.sourceStart, `strips[${index}].sourceStart`, -SEQUENCER_BUDGET.maxFrames, SEQUENCER_BUDGET.maxFrames); const sourceEnd = integer(item.sourceEnd, `strips[${index}].sourceEnd`, -SEQUENCER_BUDGET.maxFrames, SEQUENCER_BUDGET.maxFrames); if (end <= start || sourceEnd < sourceStart || end - start > SEQUENCER_BUDGET.maxFrames) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `strips[${index}] frame range is invalid`); const speed = typeof item.speed === "number" && Number.isFinite(item.speed) && item.speed > 0 && item.speed <= 1_000 ? item.speed : NaN; if (!Number.isFinite(speed)) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `strips[${index}].speed is invalid`); const strip: SequencerStripIR = { id, name: text(item.name, `strips[${index}].name`), type: item.type as SequencerStripType, channel: integer(item.channel, `strips[${index}].channel`, 1, SEQUENCER_BUDGET.maxChannels), frameStart: start, frameEnd: end, sourceStart, sourceEnd, speed, muted: typeof item.muted === "boolean" ? item.muted : false, locked: typeof item.locked === "boolean" ? item.locked : false, proxy: parseProxy(item.proxy, index), }; if (item.sourceId !== undefined) strip.sourceId = text(item.sourceId, `strips[${index}].sourceId`); if (item.sourcePath !== undefined) { try { strip.sourcePath = normalizeProjectAssetPath(text(item.sourcePath, `strips[${index}].sourcePath`, 2048)); } catch { throw new SequencerValidationError("SEQUENCER_RESOURCE_OUTSIDE_PROJECT", `strips[${index}].sourcePath is outside the project`); } } if (item.mimeType !== undefined) strip.mimeType = text(item.mimeType, `strips[${index}].mimeType`, 128); if (item.imageAssetIds !== undefined) { if (!Array.isArray(item.imageAssetIds) || item.imageAssetIds.length > SEQUENCER_BUDGET.maxImageElements || item.imageAssetIds.some((asset) => typeof asset !== "string" || asset.length === 0)) throw new SequencerValidationError("SEQUENCER_BUDGET_EXCEEDED", `strips[${index}].imageAssetIds exceeds the budget`); strip.imageAssetIds = [...item.imageAssetIds] as string[]; } for (const field of ["inputStripIds", "childStripIds"] as const) if (item[field] !== undefined) { if (!Array.isArray(item[field]) || item[field].length > SEQUENCER_BUDGET.maxDependencies || item[field].some((dependency) => typeof dependency !== "string" || dependency.length === 0)) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `strips[${index}].${field} is invalid`); strip[field] = [...item[field]] as string[]; } if (strip.type === "EFFECT") { if (!["CROSS", "GAMMA_CROSS", "ADD", "MULTIPLY", "TRANSFORM", "COLOR"].includes(item.effectType as string) || !strip.inputStripIds?.length) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `strips[${index}] effect dependencies are invalid`); strip.effectType = item.effectType as SequencerStripIR["effectType"]; } if (strip.type === "META" && !strip.childStripIds) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `strips[${index}] META requires childStripIds`); if (["MOVIE", "IMAGE", "SOUND"].includes(strip.type) && !strip.sourceId && !strip.sourcePath && !strip.imageAssetIds?.length) throw new SequencerValidationError("SEQUENCER_RESOURCE_MISSING", `strips[${index}] has no source resource`); return strip; }); const byId = new Map(strips.map((strip) => [strip.id, strip])); const active = new Set(); const complete = new Set(); const visit = (id: string): void => { if (active.has(id)) throw new SequencerValidationError("SEQUENCER_DEPENDENCY_CYCLE", `Sequencer dependency cycle includes ${id}`); if (complete.has(id)) return; active.add(id); const strip = byId.get(id); for (const dependency of [...(strip?.inputStripIds ?? []), ...(strip?.childStripIds ?? [])]) { if (!byId.has(dependency)) throw new SequencerValidationError("SEQUENCER_RESOURCE_MISSING", `${id} references missing strip ${dependency}`); visit(dependency); } active.delete(id); complete.add(id); }; strips.forEach((strip) => visit(strip.id)); return { schemaVersion: SEQUENCER_SCHEMA, id: text(value.id, "id"), revision: integer(value.revision, "revision", 0, Number.MAX_SAFE_INTEGER), frameStart, frameEnd, fpsNumerator: integer(value.fpsNumerator, "fpsNumerator", 1, 1_000_000), fpsDenominator: integer(value.fpsDenominator, "fpsDenominator", 1, 1_000_000), strips, }; } export function applySequencerEdit(value: unknown, edit: SequencerEditIR): SequencerTimelineIR { const timeline = parseSequencerTimeline(value); if (edit.revision !== timeline.revision) throw new SequencerValidationError("REVISION_CONFLICT", "Sequencer edit revision is stale"); const strips = timeline.strips.map((strip) => ({ ...strip, inputStripIds: strip.inputStripIds && [...strip.inputStripIds], childStripIds: strip.childStripIds && [...strip.childStripIds] })); const strip = strips.find((candidate) => candidate.id === edit.stripId); if (!strip) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `Unknown strip ${edit.stripId}`); if (strip.locked) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `${edit.stripId} is locked`); if (edit.type === "MOVE") { integer(edit.frameDelta, "frameDelta", -SEQUENCER_BUDGET.maxFrames, SEQUENCER_BUDGET.maxFrames); strip.frameStart += edit.frameDelta; strip.frameEnd += edit.frameDelta; if (edit.channel !== undefined) strip.channel = integer(edit.channel, "channel", 1, SEQUENCER_BUDGET.maxChannels); } else if (edit.type === "TRIM") { if (edit.frameStart === undefined && edit.frameEnd === undefined) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", "TRIM requires a boundary"); const nextStart = edit.frameStart === undefined ? strip.frameStart : integer(edit.frameStart, "frameStart", -SEQUENCER_BUDGET.maxFrames, SEQUENCER_BUDGET.maxFrames); const nextEnd = edit.frameEnd === undefined ? strip.frameEnd : integer(edit.frameEnd, "frameEnd", -SEQUENCER_BUDGET.maxFrames, SEQUENCER_BUDGET.maxFrames); if (nextStart >= nextEnd) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", "TRIM would create an empty strip"); const originalFrameStart = strip.frameStart; const originalSourceStart = strip.sourceStart; strip.sourceStart = originalSourceStart + Math.round((nextStart - originalFrameStart) * strip.speed); strip.sourceEnd = Math.min(strip.sourceEnd, originalSourceStart + Math.round((nextEnd - originalFrameStart) * strip.speed)); strip.frameStart = nextStart; strip.frameEnd = nextEnd; } else { const splitFrame = integer(edit.frame, "frame", strip.frameStart + 1, strip.frameEnd - 1); if (strips.some((candidate) => candidate.id === edit.rightStripId)) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `Duplicate split strip ${edit.rightStripId}`); const originalEnd = strip.frameEnd; const originalSourceEnd = strip.sourceEnd; const rightSourceStart = strip.sourceStart + Math.round((splitFrame - strip.frameStart) * strip.speed); strip.frameEnd = splitFrame; strip.sourceEnd = rightSourceStart; strips.push({ ...strip, id: text(edit.rightStripId, "rightStripId"), name: `${strip.name} Right`, frameStart: splitFrame, frameEnd: originalEnd, sourceStart: rightSourceStart, sourceEnd: originalSourceEnd }); } return parseSequencerTimeline({ ...timeline, revision: timeline.revision + 1, strips }); } export function sequencerSourceFrame(strip: SequencerStripIR, timelineFrame: number): number { if (!Number.isFinite(timelineFrame) || timelineFrame < strip.frameStart || timelineFrame >= strip.frameEnd) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `${strip.id} is inactive at frame ${timelineFrame}`); return Math.min(strip.sourceEnd, Math.max(strip.sourceStart, strip.sourceStart + (timelineFrame - strip.frameStart) * strip.speed)); } export function resolveSequencerFrame(value: unknown, timelineFrame: number): SequencerFrameStripIR[] { const timeline = parseSequencerTimeline(value); if (!Number.isFinite(timelineFrame) || timelineFrame < timeline.frameStart || timelineFrame > timeline.frameEnd) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `Timeline frame ${timelineFrame} is outside the scene range`); const active = timeline.strips.filter((strip) => !strip.muted && timelineFrame >= strip.frameStart && timelineFrame < strip.frameEnd); const activeIds = new Set(active.map((strip) => strip.id)); const hiddenByMeta = new Set(active.filter((strip) => strip.type === "META").flatMap((strip) => strip.childStripIds ?? [])); const result = active.filter((strip) => !hiddenByMeta.has(strip.id)).map((strip): SequencerFrameStripIR => { const dependencies = [...(strip.inputStripIds ?? []), ...(strip.childStripIds ?? [])]; if (dependencies.some((id) => !activeIds.has(id))) throw new SequencerValidationError("SEQUENCER_RESOURCE_MISSING", `${strip.id} has an inactive frame dependency`); return { stripId: strip.id, channel: strip.channel, sourceFrame: sequencerSourceFrame(strip, timelineFrame), dependencyStripIds: [...dependencies] }; }); result.sort((left, right) => left.channel - right.channel || left.stripId.localeCompare(right.stripId)); return result; } /** Resolves the ordered inputs and bounded progress for the verified cross-transition subset. */ export function resolveSequencerTransitionFrame( value: unknown, effectStripId: string, timelineFrame: number, ): SequencerTransitionFrameIR { const timeline = parseSequencerTimeline(value); const effect = timeline.strips.find((strip) => strip.id === effectStripId); if (!effect || effect.type !== "EFFECT" || (effect.effectType !== "CROSS" && effect.effectType !== "GAMMA_CROSS") || effect.inputStripIds?.length !== 2) { throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `${effectStripId} is not a supported two-input cross transition`); } if (!Number.isFinite(timelineFrame) || timelineFrame < effect.frameStart || timelineFrame >= effect.frameEnd) { throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `${effectStripId} is inactive at frame ${timelineFrame}`); } const [fromId, toId] = effect.inputStripIds; const from = timeline.strips.find((strip) => strip.id === fromId); const to = timeline.strips.find((strip) => strip.id === toId); if (!from || !to || from.muted || to.muted || timelineFrame < from.frameStart || timelineFrame >= from.frameEnd || timelineFrame < to.frameStart || timelineFrame >= to.frameEnd) { throw new SequencerValidationError("SEQUENCER_RESOURCE_MISSING", `${effectStripId} has an inactive transition input`); } const factor = (timelineFrame - effect.frameStart) / (effect.frameEnd - effect.frameStart); return { effectStripId, effectType: effect.effectType, factor, from: { stripId: from.id, sourceFrame: sequencerSourceFrame(from, timelineFrame) }, to: { stripId: to.id, sourceFrame: sequencerSourceFrame(to, timelineFrame) }, }; } export function sequencerRuntimeCapabilities(scope: typeof globalThis = globalThis): SequencerRuntimeCapabilityIR { return { webCodecsVideo: "VideoDecoder" in scope ? "PROBE_REQUIRED" : "UNAVAILABLE", webCodecsAudio: "AudioDecoder" in scope ? "PROBE_REQUIRED" : "UNAVAILABLE", htmlMedia: "HTMLMediaElement" in scope ? "PROBE_REQUIRED" : "UNAVAILABLE", localEncoding: "BLOCKED", }; } function exactCodecProbeKeys(value: Record, names: readonly string[], label: string): void { const allowed = new Set(names); const unexpected = Object.keys(value).filter((key) => !allowed.has(key)); if (unexpected.length > 0) throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `${label} contains undeclared fields: ${unexpected.join(", ")}`); } export function parseSequencerCodecProbeRequest(value: unknown): SequencerCodecProbeRequestIR { if (!record(value) || value.schemaVersion !== SEQUENCER_CODEC_PROBE_SCHEMA || !CODEC_STRIP_TYPES.has(value.stripType as SequencerCodecStripType)) { throw new SequencerValidationError("PROTOCOL_MISMATCH", "Unsupported Sequencer codec probe request"); } exactCodecProbeKeys(value, ["schemaVersion", "stripType", "mimeType", "byteLength", "sourceSha256"], "Codec probe request"); const stripType = value.stripType as SequencerCodecStripType; const mimeType = text(value.mimeType, "mimeType", 128); if (mimeType !== mimeType.toLowerCase() || !mimeType.startsWith(CODEC_MIME_PREFIX[stripType]) || !/^[a-z0-9!#$&^_.+-]+\/[a-z0-9!#$&^_.+-]+$/.test(mimeType)) { throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", `Codec MIME ${mimeType} does not match ${stripType}`); } const byteLength = integer(value.byteLength, "byteLength", 1, SEQUENCER_CODEC_PROBE_MAX_BYTES); if (typeof value.sourceSha256 !== "string" || !SHA256.test(value.sourceSha256)) { throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", "Codec probe sourceSha256 is invalid"); } return { schemaVersion: SEQUENCER_CODEC_PROBE_SCHEMA, stripType, mimeType, byteLength, sourceSha256: value.sourceSha256 }; } export function parseSequencerCodecProbeResult(value: unknown): SequencerCodecProbeResultIR { if (!record(value)) throw new SequencerValidationError("PROTOCOL_MISMATCH", "Unsupported Sequencer codec probe result"); exactCodecProbeKeys(value, ["schemaVersion", "stripType", "mimeType", "byteLength", "sourceSha256", "status", "backend", "reason", "decoded"], "Codec probe result"); const request = parseSequencerCodecProbeRequest({ schemaVersion: value.schemaVersion, stripType: value.stripType, mimeType: value.mimeType, byteLength: value.byteLength, sourceSha256: value.sourceSha256, }); if (value.status !== "READY" && value.status !== "BLOCKED") throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", "Codec probe status is invalid"); if (value.status === "BLOCKED") { if ((value.backend !== null && value.backend !== CODEC_BACKENDS[request.stripType]) || !CODEC_BLOCK_REASONS.has(value.reason as SequencerCodecProbeBlockReason) || value.decoded !== null) { throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", "Blocked codec probe result is invalid"); } } else { if (value.backend !== CODEC_BACKENDS[request.stripType] || value.reason !== null || !record(value.decoded)) { throw new SequencerValidationError("SEQUENCER_SCHEMA_INVALID", "Ready codec probe result is invalid"); } const decodedKeys = request.stripType === "IMAGE" ? ["width", "height"] : request.stripType === "SOUND" ? ["sampleRate", "channels", "durationFrames"] : ["width", "height", "durationMicros"]; exactCodecProbeKeys(value.decoded, decodedKeys, "Codec probe decoded result"); for (const key of decodedKeys) integer(value.decoded[key], `decoded.${key}`, 1, Number.MAX_SAFE_INTEGER); } return value as unknown as SequencerCodecProbeResultIR; } export function gateSequencerCodec(requestValue: unknown, resultValue: unknown): CapabilityGateResult { let capability = "CODEC_RUNTIME_PROBE"; try { const request = parseSequencerCodecProbeRequest(requestValue); capability = `CODEC_${request.stripType}_${request.mimeType}`; const result = parseSequencerCodecProbeResult(resultValue); if (result.stripType !== request.stripType || result.mimeType !== request.mimeType || result.byteLength !== request.byteLength || result.sourceSha256 !== request.sourceSha256) { return blockedGate("N-021", capability, [capabilityIssue("SEQUENCER_CODEC_UNSUPPORTED", "Codec probe result does not match the source identity")]); } if (result.status === "READY") return readyGate("N-021", capability); return blockedGate("N-021", capability, [capabilityIssue("SEQUENCER_CODEC_UNSUPPORTED", `Codec runtime probe blocked: ${result.reason}`)]); } catch (error) { return blockedGate("N-021", capability, [capabilityIssue("SEQUENCER_CODEC_UNSUPPORTED", error instanceof Error ? error.message : "Codec probe is invalid")]); } }