Rebuild local Blender WASM environment and recovery evidence
This commit is contained in:
@@ -576,6 +576,126 @@ export interface SceneSnapshotIR {
|
||||
editorWorkflowStatus?: "AVAILABLE" | "BLOCKED";
|
||||
scriptSources?: ScriptSourceInventoryIR;
|
||||
scriptSourceStatus?: "AVAILABLE" | "BLOCKED";
|
||||
renderRoutingStatus?: "AVAILABLE" | "BLOCKED";
|
||||
renderRouting?: {
|
||||
schemaVersion: 1;
|
||||
receiptId: "workflow:render_capability_routing";
|
||||
source: { sha256: string; label?: string };
|
||||
settings: Record<string, unknown> & { sha256: string };
|
||||
build: { version: string; buildSha256: string };
|
||||
routes: Array<{ name: string; target: string; status: "READY" | "BLOCKED"; [key: string]: unknown }>;
|
||||
recovery: { cancellation: "OPEN_CANCELLED"; deviceLoss: "RELEASED"; [key: string]: unknown };
|
||||
[key: string]: unknown;
|
||||
};
|
||||
serverJobBindingStatus?: "AVAILABLE" | "BLOCKED";
|
||||
serverJobBinding?: {
|
||||
schemaVersion: 1;
|
||||
receiptId: "workflow:server_job_result_binding";
|
||||
source: { sha256: string; [key: string]: unknown };
|
||||
settings: { settingsSha256: string; [key: string]: unknown };
|
||||
build: { version: string; buildSha256: string };
|
||||
request: { requestSha256: string; [key: string]: unknown };
|
||||
result: { status: "SUCCEEDED"; resultSha256: string; [key: string]: unknown };
|
||||
lifecycle: { duplicate: "REUSED"; stale: "BLOCKED"; cancel: "CANCELLED"; timeout: "TIMEOUT"; oom: "OOM"; publishedOnFailure: false; [key: string]: unknown };
|
||||
[key: string]: unknown;
|
||||
};
|
||||
scriptingPolicyStatus?: "AVAILABLE" | "BLOCKED";
|
||||
scriptingPolicy?: {
|
||||
schemaVersion: 1;
|
||||
policyId: "workflow:scripting_default_deny_audit";
|
||||
defaults: { autorun: false; network: false; addonInstall: false; driverExpressions: false; module: false };
|
||||
scope: { dom: false; hostWorker: false; opfs: false; indexedDB: false; network: false };
|
||||
sandbox: {
|
||||
execution: "DISABLED";
|
||||
cancellation: "SCRIPT_SANDBOX_CANCELLED";
|
||||
dispose: "RELEASED";
|
||||
mainRevisionUnchanged: true;
|
||||
publishedResults: 0;
|
||||
temporaryBytes: 0;
|
||||
};
|
||||
audit: { decision: "DENY"; approvedKey: false; reason: "SCRIPT_SIGNATURE_INVALID" | "SCRIPT_SANDBOX_UNAVAILABLE"; [key: string]: unknown };
|
||||
boundaries: { secretAccess: "BLOCKED"; filesystemEscape: "BLOCKED"; network: "BLOCKED" };
|
||||
budget: { maxSourceBytes: number; maxScripts: number; maxAuditEntries: number };
|
||||
policyHash: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
performanceFaultMatrixStatus?: "AVAILABLE" | "BLOCKED";
|
||||
performanceFaultMatrix?: {
|
||||
schemaVersion: 1;
|
||||
receiptId: "workflow:performance_fault_recovery_matrix";
|
||||
thresholds: Array<{ id: string; limit: number; status: "PASS"; [key: string]: unknown }>;
|
||||
faults: Record<string, { status: "BLOCKED"; code: string; publishedResults: 0; [key: string]: unknown }>;
|
||||
recovery: { oldRevisionUsable: true; revisionBefore: 1; revisionAfter: 1; resourcesAfter: 0; cache: "QUARANTINED"; workerRestart: "RECOVERED"; [key: string]: unknown };
|
||||
budget: { maxGeometryTriangles: number; maxTextureBytes: number; maxMediaBytes: number; maxCacheBytes: number; [key: string]: unknown };
|
||||
matrixHash: string;
|
||||
[key: string]: unknown;
|
||||
};
|
||||
releaseCandidateStatus?: "AVAILABLE" | "BLOCKED";
|
||||
releaseCandidate?: {
|
||||
schemaVersion: 1;
|
||||
receiptId: "workflow:offline_ci_sbom_and_rollback_release";
|
||||
releaseId: string;
|
||||
ci: { quick: { status: "READY"; reportSha256: string }; [key: string]: unknown };
|
||||
gates: { offlineReproducibility: { status: "READY" }; sbom: { status: "READY" }; rollback: { status: "READY" }; [key: string]: unknown };
|
||||
archives: { binary: { bytes: number; sha256: string }; source: { bytes: number; sha256: string }; [key: string]: unknown };
|
||||
sbom: { sha256: string; [key: string]: unknown };
|
||||
rollback: { runbookSha256: string; [key: string]: unknown };
|
||||
[key: string]: unknown;
|
||||
};
|
||||
gapInventoryStatus?: "AVAILABLE" | "BLOCKED";
|
||||
gapInventory?: {
|
||||
schemaVersion: 1;
|
||||
receiptId: "workflow:cluster_full_blender_gap_inventory";
|
||||
runtime: "BLENDER_5_2_INVENTORY";
|
||||
inventorySource: { path: string; sha256: string; entryCount: 6900; [key: string]: unknown };
|
||||
classificationPolicy: { featureParityRequires: string[]; negativeOnlyClasses: string[]; unprovenClass: "METADATA_ONLY"; parityLevel: "L0"; [key: string]: unknown };
|
||||
clusters: Array<{
|
||||
capabilityId: string;
|
||||
family: string;
|
||||
layer: string;
|
||||
entryCount: number;
|
||||
legacyCompleted: number;
|
||||
legacyPending: number;
|
||||
legacyActive: number;
|
||||
targetParityLevel: string;
|
||||
currentParityLevel: "L0";
|
||||
completionClass: "METADATA_ONLY";
|
||||
evidenceStatus: "NOT_RUN";
|
||||
webStatus: "GAP";
|
||||
riskScore: number;
|
||||
riskBand: string;
|
||||
representativeIds: string[];
|
||||
blockedReasons: string[];
|
||||
[key: string]: unknown;
|
||||
}>;
|
||||
summary: { inventoryEntries: 6900; clusterCount: 15; unknownEntries: 0; webGapEntries: 6900; currentParityClaims: 0; currentParityLevel: "L0"; [key: string]: unknown };
|
||||
riskRanking: string[];
|
||||
nextTask: "WBV2-P7-002";
|
||||
[key: string]: unknown;
|
||||
};
|
||||
atomicGapQueueStatus?: "AVAILABLE" | "BLOCKED";
|
||||
atomicGapQueue?: {
|
||||
schemaVersion: 1;
|
||||
receiptId: "workflow:generate_atomic_family_gap_queue";
|
||||
runtime: "BLENDER_5_2_INVENTORY";
|
||||
parent: { task: "WBV2-P7-001"; manifestPath: string; manifestSha256: string; receiptPath: string; receiptSha256: string; [key: string]: unknown };
|
||||
queue: { activeTaskId: string; activeCount: 1; plannedCount: 44; ordering: string; behaviors: string[]; implementationClasses: string[]; [key: string]: unknown };
|
||||
tasks: Array<{ id: string; parityId: string; capabilityId: string; family: string; behavior: string; implementationClass: "LOCAL_BOUNDED"; parentTask: "WBV2-P7-001"; parentReceiptSha256: string; state: "active" | "pending"; ready: boolean; [key: string]: unknown }>;
|
||||
nextTask: "WBV2-P7-003";
|
||||
[key: string]: unknown;
|
||||
};
|
||||
parityReleaseGateStatus?: "AVAILABLE" | "BLOCKED";
|
||||
parityReleaseGate?: {
|
||||
schemaVersion: 1;
|
||||
receiptId: "workflow:full_parity_candidate_release_gate";
|
||||
runtime: "BLENDER_DESKTOP_WASM_MAIN";
|
||||
inputs: Record<string, { path: string; sha256: string; [key: string]: unknown }>;
|
||||
parityClosure: { status: "BLOCKED"; inventoryEntries: 6900; clusterCount: 15; atomicTaskCount: 45; currentParityLevel: "L0"; featureParityClaims: 0; reasonCodes: string[]; [key: string]: unknown };
|
||||
evidenceHealth: { status: "BLOCKED"; historicalEvidencePreserved: true; m12ProvenanceState: "BLOCKED_SOURCE_LOST"; m12Entries: number; reasonCodes: string[]; [key: string]: unknown };
|
||||
recoveryHealth: { status: "READY"; quickCi: "READY"; inventorySaveReopen: "EXACT"; queueSaveReopen: "EXACT"; malformedBlend: "REJECTED_WITHOUT_MAIN_MUTATION"; [key: string]: unknown };
|
||||
releaseDecision: { status: "BLOCKED"; reasonCodes: string[]; nextTask: null; [key: string]: unknown };
|
||||
[key: string]: unknown;
|
||||
};
|
||||
physicsSimulation?: PhysicsSimulationManifestIR;
|
||||
particleSettings?: ParticleSettingsIR[];
|
||||
sounds?: SoundResourceIR[];
|
||||
@@ -1516,6 +1636,209 @@ export function parseSceneSnapshotIR(value: unknown): SceneSnapshotIR {
|
||||
parseScriptSourceInventory(value.scriptSources);
|
||||
if (value.scriptSourceStatus !== "AVAILABLE") throw new Error("SceneIR.scriptSourceStatus must be AVAILABLE when scriptSources is present");
|
||||
}
|
||||
if (value.renderRoutingStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(value.renderRoutingStatus as string)) {
|
||||
throw new Error("SceneIR.renderRoutingStatus is invalid");
|
||||
}
|
||||
if (value.renderRouting !== undefined) {
|
||||
if (!isRecord(value.renderRouting) || value.renderRouting.schemaVersion !== 1 ||
|
||||
value.renderRouting.receiptId !== "workflow:render_capability_routing" ||
|
||||
!isRecord(value.renderRouting.source) || typeof value.renderRouting.source.sha256 !== "string" ||
|
||||
!isRecord(value.renderRouting.settings) || typeof value.renderRouting.settings.sha256 !== "string" ||
|
||||
!isRecord(value.renderRouting.build) || typeof value.renderRouting.build.version !== "string" ||
|
||||
typeof value.renderRouting.build.buildSha256 !== "string" || !Array.isArray(value.renderRouting.routes) ||
|
||||
!isRecord(value.renderRouting.recovery) || value.renderRouting.recovery.cancellation !== "OPEN_CANCELLED" ||
|
||||
value.renderRouting.recovery.deviceLoss !== "RELEASED") {
|
||||
throw new Error("SceneIR.renderRouting is invalid");
|
||||
}
|
||||
if (value.renderRoutingStatus !== "AVAILABLE") throw new Error("SceneIR.renderRoutingStatus must be AVAILABLE when renderRouting is present");
|
||||
}
|
||||
if (value.serverJobBindingStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(value.serverJobBindingStatus as string)) {
|
||||
throw new Error("SceneIR.serverJobBindingStatus is invalid");
|
||||
}
|
||||
if (value.serverJobBinding !== undefined) {
|
||||
const binding = value.serverJobBinding;
|
||||
if (!isRecord(binding) || binding.schemaVersion !== 1 || binding.receiptId !== "workflow:server_job_result_binding" ||
|
||||
!isRecord(binding.source) || typeof binding.source.sha256 !== "string" ||
|
||||
!isRecord(binding.settings) || typeof binding.settings.settingsSha256 !== "string" ||
|
||||
!isRecord(binding.build) || typeof binding.build.version !== "string" || typeof binding.build.buildSha256 !== "string" ||
|
||||
!isRecord(binding.request) || typeof binding.request.requestSha256 !== "string" ||
|
||||
!isRecord(binding.result) || binding.result.status !== "SUCCEEDED" || typeof binding.result.resultSha256 !== "string" ||
|
||||
!isRecord(binding.lifecycle) || binding.lifecycle.duplicate !== "REUSED" || binding.lifecycle.stale !== "BLOCKED" ||
|
||||
binding.lifecycle.cancel !== "CANCELLED" || binding.lifecycle.timeout !== "TIMEOUT" || binding.lifecycle.oom !== "OOM" ||
|
||||
binding.lifecycle.publishedOnFailure !== false) {
|
||||
throw new Error("SceneIR.serverJobBinding is invalid");
|
||||
}
|
||||
if (value.serverJobBindingStatus !== "AVAILABLE") throw new Error("SceneIR.serverJobBindingStatus must be AVAILABLE when serverJobBinding is present");
|
||||
}
|
||||
if (value.scriptingPolicyStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(value.scriptingPolicyStatus as string)) {
|
||||
throw new Error("SceneIR.scriptingPolicyStatus is invalid");
|
||||
}
|
||||
if (value.scriptingPolicy !== undefined) {
|
||||
const policy = value.scriptingPolicy;
|
||||
const defaults = isRecord(policy) ? policy.defaults : undefined;
|
||||
const scope = isRecord(policy) ? policy.scope : undefined;
|
||||
const sandbox = isRecord(policy) ? policy.sandbox : undefined;
|
||||
const audit = isRecord(policy) ? policy.audit : undefined;
|
||||
const boundaries = isRecord(policy) ? policy.boundaries : undefined;
|
||||
const budget = isRecord(policy) ? policy.budget : undefined;
|
||||
if (!isRecord(policy) || policy.schemaVersion !== 1 || policy.policyId !== "workflow:scripting_default_deny_audit" ||
|
||||
!isRecord(defaults) || defaults.autorun !== false || defaults.network !== false || defaults.addonInstall !== false ||
|
||||
defaults.driverExpressions !== false || defaults.module !== false || !isRecord(scope) || scope.dom !== false ||
|
||||
scope.hostWorker !== false || scope.opfs !== false || scope.indexedDB !== false || scope.network !== false ||
|
||||
!isRecord(sandbox) || sandbox.execution !== "DISABLED" || sandbox.cancellation !== "SCRIPT_SANDBOX_CANCELLED" ||
|
||||
sandbox.dispose !== "RELEASED" || sandbox.mainRevisionUnchanged !== true || sandbox.publishedResults !== 0 ||
|
||||
sandbox.temporaryBytes !== 0 || !isRecord(audit) || audit.decision !== "DENY" || audit.approvedKey !== false ||
|
||||
!["SCRIPT_SIGNATURE_INVALID", "SCRIPT_SANDBOX_UNAVAILABLE"].includes(audit.reason as string) ||
|
||||
!isRecord(boundaries) || boundaries.secretAccess !== "BLOCKED" || boundaries.filesystemEscape !== "BLOCKED" ||
|
||||
boundaries.network !== "BLOCKED" || !isRecord(budget) || !Number.isSafeInteger(budget.maxSourceBytes) ||
|
||||
(budget.maxSourceBytes as number) < 1 || !Number.isSafeInteger(budget.maxScripts) || (budget.maxScripts as number) < 1 ||
|
||||
!Number.isSafeInteger(budget.maxAuditEntries) || (budget.maxAuditEntries as number) < 1 ||
|
||||
typeof policy.policyHash !== "string" || !/^[a-f0-9]{64}$/u.test(policy.policyHash)) {
|
||||
throw new Error("SceneIR.scriptingPolicy is invalid");
|
||||
}
|
||||
if (value.scriptingPolicyStatus !== "AVAILABLE") throw new Error("SceneIR.scriptingPolicyStatus must be AVAILABLE when scriptingPolicy is present");
|
||||
}
|
||||
if (value.performanceFaultMatrixStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(value.performanceFaultMatrixStatus as string)) {
|
||||
throw new Error("SceneIR.performanceFaultMatrixStatus is invalid");
|
||||
}
|
||||
if (value.performanceFaultMatrix !== undefined) {
|
||||
const matrix = value.performanceFaultMatrix;
|
||||
const thresholds = isRecord(matrix) ? matrix.thresholds : undefined;
|
||||
const faults = isRecord(matrix) ? matrix.faults : undefined;
|
||||
const recovery = isRecord(matrix) ? matrix.recovery : undefined;
|
||||
const budget = isRecord(matrix) ? matrix.budget : undefined;
|
||||
const thresholdIds = new Set(Array.isArray(thresholds) ? thresholds.map((entry) => isRecord(entry) ? entry.id : undefined) : []);
|
||||
if (!isRecord(matrix) || matrix.schemaVersion !== 1 || matrix.receiptId !== "workflow:performance_fault_recovery_matrix" ||
|
||||
!Array.isArray(thresholds) || thresholds.length < 7 || thresholds.some((entry) => !isRecord(entry) || typeof entry.id !== "string" || entry.status !== "PASS" || !Number.isSafeInteger(entry.limit) || (entry.limit as number) < 1) ||
|
||||
!thresholdIds.has("geometry-100k") || !thresholdIds.has("geometry-1m") || !thresholdIds.has("geometry-10m") || !thresholdIds.has("texture-4k") || !thresholdIds.has("texture-8k") || !thresholdIds.has("long-media") || !thresholdIds.has("simulation-cache") ||
|
||||
!isRecord(faults) || Object.values(faults).some((fault) => !isRecord(fault) || fault.status !== "BLOCKED" || typeof fault.code !== "string" || fault.publishedResults !== 0) ||
|
||||
!isRecord(recovery) || recovery.oldRevisionUsable !== true || recovery.revisionBefore !== 1 || recovery.revisionAfter !== 1 || recovery.resourcesAfter !== 0 || recovery.cache !== "QUARANTINED" || recovery.workerRestart !== "RECOVERED" ||
|
||||
!isRecord(budget) || Object.values(budget).some((limit) => typeof limit !== "number" || !Number.isSafeInteger(limit) || limit < 1) ||
|
||||
typeof matrix.matrixHash !== "string" || !/^[a-f0-9]{64}$/u.test(matrix.matrixHash)) {
|
||||
throw new Error("SceneIR.performanceFaultMatrix is invalid");
|
||||
}
|
||||
if (value.performanceFaultMatrixStatus !== "AVAILABLE") throw new Error("SceneIR.performanceFaultMatrixStatus must be AVAILABLE when performanceFaultMatrix is present");
|
||||
}
|
||||
if (value.releaseCandidateStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(value.releaseCandidateStatus as string)) {
|
||||
throw new Error("SceneIR.releaseCandidateStatus is invalid");
|
||||
}
|
||||
if (value.releaseCandidate !== undefined) {
|
||||
const receipt = value.releaseCandidate;
|
||||
const ci = isRecord(receipt) ? receipt.ci : undefined;
|
||||
const gates = isRecord(receipt) ? receipt.gates : undefined;
|
||||
const archives = isRecord(receipt) ? receipt.archives : undefined;
|
||||
const binary = isRecord(archives) ? archives.binary : undefined;
|
||||
const source = isRecord(archives) ? archives.source : undefined;
|
||||
const sbom = isRecord(receipt) ? receipt.sbom : undefined;
|
||||
const rollback = isRecord(receipt) ? receipt.rollback : undefined;
|
||||
if (!isRecord(receipt) || receipt.schemaVersion !== 1 || receipt.receiptId !== "workflow:offline_ci_sbom_and_rollback_release" ||
|
||||
typeof receipt.releaseId !== "string" || !isRecord(ci) || !isRecord(ci.quick) || ci.quick.status !== "READY" ||
|
||||
typeof ci.quick.reportSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(ci.quick.reportSha256) || !isRecord(gates) ||
|
||||
!isRecord(gates.offlineReproducibility) || gates.offlineReproducibility.status !== "READY" || !isRecord(gates.sbom) ||
|
||||
gates.sbom.status !== "READY" || !isRecord(gates.rollback) || gates.rollback.status !== "READY" || !isRecord(binary) ||
|
||||
!Number.isSafeInteger(binary.bytes) || (binary.bytes as number) < 1 || typeof binary.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(binary.sha256) ||
|
||||
!isRecord(source) || !Number.isSafeInteger(source.bytes) || (source.bytes as number) < 1 || typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(source.sha256) ||
|
||||
!isRecord(sbom) || typeof sbom.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(sbom.sha256) || !isRecord(rollback) ||
|
||||
typeof rollback.runbookSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(rollback.runbookSha256)) {
|
||||
throw new Error("SceneIR.releaseCandidate is invalid");
|
||||
}
|
||||
if (value.releaseCandidateStatus !== "AVAILABLE") throw new Error("SceneIR.releaseCandidateStatus must be AVAILABLE when releaseCandidate is present");
|
||||
}
|
||||
if (value.gapInventoryStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(value.gapInventoryStatus as string)) {
|
||||
throw new Error("SceneIR.gapInventoryStatus is invalid");
|
||||
}
|
||||
if (value.gapInventory !== undefined) {
|
||||
const inventory = value.gapInventory;
|
||||
const source = isRecord(inventory) ? inventory.inventorySource : undefined;
|
||||
const policy = isRecord(inventory) ? inventory.classificationPolicy : undefined;
|
||||
const summary = isRecord(inventory) ? inventory.summary : undefined;
|
||||
const clusters = isRecord(inventory) ? inventory.clusters : undefined;
|
||||
if (!isRecord(inventory) || inventory.schemaVersion !== 1 || inventory.receiptId !== "workflow:cluster_full_blender_gap_inventory" ||
|
||||
inventory.runtime !== "BLENDER_5_2_INVENTORY" || !isRecord(source) || typeof source.path !== "string" ||
|
||||
typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(source.sha256) || source.entryCount !== 6900 ||
|
||||
!isRecord(policy) || policy.unprovenClass !== "METADATA_ONLY" || policy.parityLevel !== "L0" ||
|
||||
!Array.isArray(policy.featureParityRequires) || policy.featureParityRequires.length !== 3 ||
|
||||
!Array.isArray(policy.negativeOnlyClasses) || !Array.isArray(clusters) || clusters.length !== 15 ||
|
||||
!isRecord(summary) || summary.inventoryEntries !== 6900 || summary.clusterCount !== 15 || summary.unknownEntries !== 0 ||
|
||||
summary.webGapEntries !== 6900 || summary.currentParityClaims !== 0 || summary.currentParityLevel !== "L0" ||
|
||||
!Array.isArray(inventory.riskRanking) || inventory.riskRanking.length !== 15 || inventory.nextTask !== "WBV2-P7-002") {
|
||||
throw new Error("SceneIR.gapInventory is invalid");
|
||||
}
|
||||
const seen = new Set<string>();
|
||||
for (const cluster of clusters) {
|
||||
if (!isRecord(cluster) || typeof cluster.capabilityId !== "string" || seen.has(cluster.capabilityId) ||
|
||||
!Number.isSafeInteger(cluster.entryCount) || (cluster.entryCount as number) < 1 ||
|
||||
cluster.currentParityLevel !== "L0" || cluster.completionClass !== "METADATA_ONLY" ||
|
||||
cluster.evidenceStatus !== "NOT_RUN" || cluster.webStatus !== "GAP" ||
|
||||
!Number.isSafeInteger(cluster.riskScore) || !Array.isArray(cluster.representativeIds) || cluster.representativeIds.length < 1) {
|
||||
throw new Error("SceneIR.gapInventory cluster is invalid");
|
||||
}
|
||||
seen.add(cluster.capabilityId);
|
||||
}
|
||||
if (seen.size !== inventory.riskRanking.length || inventory.riskRanking.some((id) => typeof id !== "string" || !seen.has(id))) {
|
||||
throw new Error("SceneIR.gapInventory risk ranking is invalid");
|
||||
}
|
||||
if (value.gapInventoryStatus !== "AVAILABLE") throw new Error("SceneIR.gapInventoryStatus must be AVAILABLE when gapInventory is present");
|
||||
}
|
||||
if (value.atomicGapQueueStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(value.atomicGapQueueStatus as string)) {
|
||||
throw new Error("SceneIR.atomicGapQueueStatus is invalid");
|
||||
}
|
||||
if (value.atomicGapQueue !== undefined) {
|
||||
const queue = value.atomicGapQueue;
|
||||
const parent = isRecord(queue) ? queue.parent : undefined;
|
||||
const details = isRecord(queue) ? queue.queue : undefined;
|
||||
const tasks = isRecord(queue) ? queue.tasks : undefined;
|
||||
if (!isRecord(queue) || queue.schemaVersion !== 1 || queue.receiptId !== "workflow:generate_atomic_family_gap_queue" ||
|
||||
queue.runtime !== "BLENDER_5_2_INVENTORY" || !isRecord(parent) || parent.task !== "WBV2-P7-001" ||
|
||||
typeof parent.manifestPath !== "string" || typeof parent.receiptPath !== "string" ||
|
||||
typeof parent.manifestSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(parent.manifestSha256) ||
|
||||
typeof parent.receiptSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(parent.receiptSha256) ||
|
||||
!isRecord(details) || details.activeCount !== 1 || details.plannedCount !== 44 ||
|
||||
typeof details.activeTaskId !== "string" || !Array.isArray(details.behaviors) || details.behaviors.length !== 3 ||
|
||||
!Array.isArray(details.implementationClasses) || details.implementationClasses.length !== 1 ||
|
||||
details.implementationClasses[0] !== "LOCAL_BOUNDED" || !Array.isArray(tasks) || tasks.length !== 45 ||
|
||||
queue.nextTask !== "WBV2-P7-003") {
|
||||
throw new Error("SceneIR.atomicGapQueue is invalid");
|
||||
}
|
||||
const ids = new Set<string>();
|
||||
for (const [index, task] of tasks.entries()) {
|
||||
if (!isRecord(task) || typeof task.id !== "string" || ids.has(task.id) ||
|
||||
typeof task.parityId !== "string" || task.parityId !== task.capabilityId ||
|
||||
task.implementationClass !== "LOCAL_BOUNDED" || task.parentTask !== "WBV2-P7-001" ||
|
||||
typeof task.parentReceiptSha256 !== "string" || !/^[a-f0-9]{64}$/u.test(task.parentReceiptSha256) ||
|
||||
task.state !== (index === 0 ? "active" : "pending") || task.ready !== (index === 0)) {
|
||||
throw new Error("SceneIR.atomicGapQueue task is invalid");
|
||||
}
|
||||
ids.add(task.id);
|
||||
}
|
||||
if (details.activeTaskId !== tasks[0].id || value.atomicGapQueueStatus !== "AVAILABLE") {
|
||||
throw new Error("SceneIR.atomicGapQueueStatus must be AVAILABLE for a valid queue");
|
||||
}
|
||||
}
|
||||
if (value.parityReleaseGateStatus !== undefined && !["AVAILABLE", "BLOCKED"].includes(value.parityReleaseGateStatus as string)) {
|
||||
throw new Error("SceneIR.parityReleaseGateStatus is invalid");
|
||||
}
|
||||
if (value.parityReleaseGate !== undefined) {
|
||||
const gate = value.parityReleaseGate;
|
||||
const closure = isRecord(gate) ? gate.parityClosure : undefined;
|
||||
const evidence = isRecord(gate) ? gate.evidenceHealth : undefined;
|
||||
const recovery = isRecord(gate) ? gate.recoveryHealth : undefined;
|
||||
const decision = isRecord(gate) ? gate.releaseDecision : undefined;
|
||||
if (!isRecord(gate) || gate.schemaVersion !== 1 || gate.receiptId !== "workflow:full_parity_candidate_release_gate" ||
|
||||
gate.runtime !== "BLENDER_DESKTOP_WASM_MAIN" || !isRecord(gate.inputs) || Object.keys(gate.inputs).length !== 4 ||
|
||||
Object.values(gate.inputs).some((input) => !isRecord(input) || typeof input.path !== "string" || typeof input.sha256 !== "string" || !/^[a-f0-9]{64}$/u.test(input.sha256)) ||
|
||||
!isRecord(closure) || closure.status !== "BLOCKED" || closure.inventoryEntries !== 6900 || closure.clusterCount !== 15 ||
|
||||
closure.atomicTaskCount !== 45 || closure.currentParityLevel !== "L0" || closure.featureParityClaims !== 0 ||
|
||||
!Array.isArray(closure.reasonCodes) || closure.reasonCodes.length < 1 || !isRecord(evidence) || evidence.status !== "BLOCKED" ||
|
||||
evidence.historicalEvidencePreserved !== true || evidence.m12ProvenanceState !== "BLOCKED_SOURCE_LOST" ||
|
||||
!Number.isSafeInteger(evidence.m12Entries) || (evidence.m12Entries as number) < 1 || !Array.isArray(evidence.reasonCodes) || evidence.reasonCodes.length < 1 ||
|
||||
!isRecord(recovery) || recovery.status !== "READY" || recovery.quickCi !== "READY" || recovery.inventorySaveReopen !== "EXACT" ||
|
||||
recovery.queueSaveReopen !== "EXACT" || recovery.malformedBlend !== "REJECTED_WITHOUT_MAIN_MUTATION" || !isRecord(decision) ||
|
||||
decision.status !== "BLOCKED" || decision.nextTask !== null || !Array.isArray(decision.reasonCodes) || decision.reasonCodes.length < 1) {
|
||||
throw new Error("SceneIR.parityReleaseGate is invalid");
|
||||
}
|
||||
if (value.parityReleaseGateStatus !== "AVAILABLE") throw new Error("SceneIR.parityReleaseGateStatus must be AVAILABLE when parityReleaseGate is present");
|
||||
}
|
||||
if (value.physicsSimulation !== undefined) parsePhysicsSimulationManifest(value.physicsSimulation);
|
||||
if (value.geometryNodeGraphs !== undefined) {
|
||||
const graphs = requireArray(value.geometryNodeGraphs, "geometryNodeGraphs");
|
||||
|
||||
Reference in New Issue
Block a user