Declare SCUM Run data targets

This commit is contained in:
npc0-hue
2026-08-12 17:44:53 +08:00
parent d854d6fda3
commit 2246859984
17 changed files with 235 additions and 10 deletions
+14 -1
View File
@@ -1064,6 +1064,7 @@ export function validateSCUMLiveDataManifest(manifest: unknown, manifestDir?: st
type Gate = { capability?: string; gate?: string; adapterVersion?: string; requiredSchemaFingerprint?: string; requiredAssetDigests?: string[]; evidenceStatus?: string; safeReason?: string };
type Probe = { capability?: string; targetKey?: string; bounds?: { maxSampleRows?: number; timeoutMs?: number; maxResultBytes?: number } };
type Transport = { key?: string; kind?: string; targetKey?: string; capabilities?: string[] };
type DataTarget = { key?: string; kind?: string; transportKey?: string; sourceRootKey?: string; sourcePath?: string; workspaceKey?: string; refreshPolicy?: string; maxBytes?: number; platforms?: string[] };
type RuntimeLogSource = { key?: string };
type AssetFile = { path?: string };
type Asset = { key?: string; adapterVersion?: string; assetPath?: string; digest?: string };
@@ -1075,7 +1076,7 @@ export function validateSCUMLiveDataManifest(manifest: unknown, manifestDir?: st
type MapAsset = Asset & { requiredSchemaFingerprint?: string; metadataSchemaRef?: string; transformAssetPath?: string; transformDigest?: string; worldBounds?: { minX?: number; minY?: number; maxX?: number; maxY?: number }; image?: { width?: number; height?: number } };
type GiftCatalog = Asset & { catalogVersion?: string; itemSchemaRef?: string; transportTemplateKeys?: string[] };
type LiveData = { schemaVersion?: string; probe?: Probe; capabilityGates?: Gate[]; logParsers?: LogParser[]; sqliteQueries?: SQLiteQuery[]; syncCadences?: SyncCadence[]; typedRconTemplates?: TypedRCON[]; guardedMutations?: GuardedMutation[]; mapAssets?: MapAsset[]; giftCatalogs?: GiftCatalog[] };
const declaration = manifest as { id?: string; capabilities?: string[]; permissions?: string[]; assetFiles?: AssetFile[]; remoteAccess?: { runCapabilities?: string[]; databaseEngines?: string[] }; runtimeProfiles?: { transportProfiles?: Transport[]; logSources?: RuntimeLogSource[] }; scumLiveData?: LiveData };
const declaration = manifest as { id?: string; capabilities?: string[]; permissions?: string[]; assetFiles?: AssetFile[]; remoteAccess?: { runCapabilities?: string[]; databaseEngines?: string[] }; runtimeProfiles?: { transportProfiles?: Transport[]; dataTargets?: DataTarget[]; logSources?: RuntimeLogSource[] }; scumLiveData?: LiveData };
const liveData = declaration.scumLiveData;
if (!liveData) return [];
@@ -1085,6 +1086,7 @@ export function validateSCUMLiveDataManifest(manifest: unknown, manifestDir?: st
const remoteCapabilities = new Set(declaration.remoteAccess?.runCapabilities ?? []);
const remoteDatabaseEngines = new Set(declaration.remoteAccess?.databaseEngines ?? []);
const transportProfiles = declaration.runtimeProfiles?.transportProfiles ?? [];
const dataTargets = declaration.runtimeProfiles?.dataTargets ?? [];
const logSources = new Set((declaration.runtimeProfiles?.logSources ?? []).map((source) => source.key ?? ""));
const assetFiles = new Set((declaration.assetFiles ?? []).map((asset) => asset.path ?? ""));
const probe = liveData.probe;
@@ -1157,6 +1159,17 @@ export function validateSCUMLiveDataManifest(manifest: unknown, manifestDir?: st
}
};
const transportByKey = (key?: string): Transport | undefined => transportProfiles.find((candidate) => candidate.key === key);
const probeDataTarget = dataTargets.find((candidate) => candidate.key === probe?.targetKey);
const expectedProbeWorkspaceKey = `databases/${String(probe?.targetKey ?? "").replace(/^databases\//, "")}`;
if (!probeDataTarget) {
errors.push(`${location}.probe.targetKey: must reference a declared runtime data target`);
} else {
const probeDataTargetTransport = transportByKey(probeDataTarget.transportKey);
if (probeDataTarget.kind !== "sqlite.snapshot" || probeDataTarget.workspaceKey !== expectedProbeWorkspaceKey || probeDataTarget.refreshPolicy !== "on-demand-snapshot" || !probeDataTargetTransport || probeDataTargetTransport.kind !== "sqlite" || !probeDataTargetTransport.capabilities?.includes("remote.run.db.sqlite.probe")) {
errors.push(`${location}.probe.targetKey: must reference a sqlite snapshot data target for the generated Run workspace`);
}
if (!Number.isInteger(probeDataTarget.maxBytes) || (probeDataTarget.maxBytes ?? 0) < 1 || (probeDataTarget.maxBytes ?? 0) > 1073741824) errors.push(`${location}.probe.targetKey.maxBytes: must be between 1 and 1073741824`);
}
const requireRefs = (entry: Record<string, unknown>, entryLocation: string, refs: string[]): void => {
for (const field of refs) {
const ref = entry[field];