feat(observatory): verify exact published result reuse

This commit is contained in:
DCCONSTRUCTIONS
2026-09-03 09:14:54 +03:00
parent 80fc0058cb
commit 1e4ddc2cff
10 changed files with 910 additions and 42 deletions
@@ -1,4 +1,5 @@
import type {
ObservatoryLaboratoryPreservedResult,
ObservatoryLaboratoryRunDefinition,
ObservatoryLaboratorySetup,
ObservatoryLaboratorySetupCatalog,
@@ -23,13 +24,14 @@ export function decodePortableCatalog(value: unknown): ObservatoryLaboratorySetu
);
exact(row.schema_version, PORTABLE_CATALOG_SCHEMA, "schema_version portable-каталога");
observationAuthority(row.authority);
const sourceSessionId = text(row.source_session_id, "portable source_session_id");
return {
sourceSessionId: text(row.source_session_id, "portable source_session_id"),
setups: array(row.setups, "portable setups").map(decodePortableSetup),
sourceSessionId,
setups: array(row.setups, "portable setups").map((item) => decodePortableSetup(item, sourceSessionId)),
};
}
function decodePortableSetup(value: unknown): ObservatoryLaboratorySetup {
function decodePortableSetup(value: unknown, sourceSessionId: string): ObservatoryLaboratorySetup {
const row = record(value, "portable-сетап");
exactKeys(row, [
"authority", "description", "display_name", "executor", "existing_results",
@@ -39,6 +41,8 @@ function decodePortableSetup(value: unknown): ObservatoryLaboratorySetup {
exact(row.origin, "portable-definition", "portable origin");
observationAuthority(row.authority);
decodePortableSourceRequirements(row.source_requirements);
const setupId = text(row.setup_id, "portable setup_id");
const runDefinition = decodePortableRunDefinition(row.run_definition);
const compatibility = record(row.source_compatibility, "portable source_compatibility");
exactKeys(
@@ -96,12 +100,12 @@ function decodePortableSetup(value: unknown): ObservatoryLaboratorySetup {
], "portable preflight");
const preflightOutcome = oneOf(
preflight.outcome,
["ready", "blocked"] as const,
["existing", "ready", "blocked"] as const,
"portable preflight outcome",
);
const preflightAction = oneOf(
preflight.action,
["check", "blocked"] as const,
["open-existing", "check", "blocked"] as const,
"portable preflight action",
);
const submissionAllowed = boolean(
@@ -112,28 +116,37 @@ function decodePortableSetup(value: unknown): ObservatoryLaboratorySetup {
submissionAllowed !== (preflightOutcome === "ready")
|| (preflightOutcome === "ready" && preflightAction !== "check")
|| (preflightOutcome === "blocked" && preflightAction !== "blocked")
|| (preflightOutcome === "existing" && preflightAction !== "open-existing")
|| (submissionAllowed && (!compatible || !executorReady))
) {
throw new ObservatoryPortableSetupDecodeError(
"Portable preflight: состояние запуска противоречиво.",
);
}
const existingResults = array(row.existing_results, "portable existing_results");
const existingResults = array(row.existing_results, "portable existing_results").map(
(item) => decodePortableResult(item, sourceSessionId, setupId, runDefinition),
);
const existingResultIds = array(
preflight.existing_result_ids,
"portable existing_result_ids",
);
if (existingResults.length > 0 || existingResultIds.length > 0) {
).map((item) => text(item, "portable existing result id"));
if (
(existingResults.length > 0) !== (preflightOutcome === "existing")
|| existingResultIds.length !== existingResults.length
|| new Set(existingResultIds).size !== existingResultIds.length
|| existingResults.some((result, index) => result.resultId !== existingResultIds[index])
) {
throw new ObservatoryPortableSetupDecodeError(
"Portable result: проверяемая привязка результата к RunDefinition ещё не поддерживается.",
"Portable result: готовность не соответствует проверенным результатам.",
);
}
return {
setupId: text(row.setup_id, "portable setup_id"),
setupId,
displayName: text(row.display_name, "portable display_name"),
description: text(row.description, "portable description"),
origin: "portable-definition",
runDefinition: decodePortableRunDefinition(row.run_definition),
runDefinition,
compatibility: {
compatible,
reasons: compatible
@@ -146,17 +159,58 @@ function decodePortableSetup(value: unknown): ObservatoryLaboratorySetup {
reasonCode: executorReasonCode,
reason: executorReason,
},
preservedResults: [],
preservedResults: existingResults,
preflight: {
outcome: preflightOutcome,
action: preflightAction,
reason: text(preflight.reason, "portable preflight reason"),
submissionAllowed,
existingResultIds: [],
existingResultIds,
},
};
}
function decodePortableResult(
value: unknown, sourceSessionId: string, setupId: string,
definition: ObservatoryLaboratoryRunDefinition,
): ObservatoryLaboratoryPreservedResult {
const row = record(value, "portable result");
exactKeys(row, [
"result_id", "result_kind", "relation", "access", "created_at_utc",
"observatory_projection_available", "identity",
], "portable result");
exact(row.result_kind, definition.resultKind, "portable result kind");
exact(row.relation, "exact-recorded-computation", "portable result relation");
exact(row.access, "observatory", "portable result access");
exact(row.observatory_projection_available, true, "portable result availability");
const identity = record(row.identity, "portable result identity");
exactKeys(identity, [
"job_id", "source_session_id", "source_catalog_sha256", "source_bundle_sha256",
"source_capability_manifest_sha256", "setup_id", "definition_sha256",
"package_sha256", "artifact_manifest_id",
], "portable result identity");
exact(identity.source_session_id, sourceSessionId, "portable result source");
exact(identity.setup_id, setupId, "portable result setup");
exact(identity.definition_sha256, definition.definitionSha256, "portable result definition");
text(identity.job_id, "portable result job");
for (const key of [
"source_catalog_sha256", "source_bundle_sha256", "source_capability_manifest_sha256",
"definition_sha256", "package_sha256", "artifact_manifest_id",
]) {
if (!SHA256.test(text(identity[key], `portable result ${key}`))) {
throw new ObservatoryPortableSetupDecodeError(`Portable result: некорректный ${key}.`);
}
}
return {
resultId: text(row.result_id, "portable result id"),
resultKind: text(row.result_kind, "portable result kind"),
relation: "exact-recorded-computation",
access: "observatory",
createdAtUtc: text(row.created_at_utc, "portable result created_at_utc"),
observatoryProjectionAvailable: true,
};
}
function decodePortableSourceRequirements(value: unknown): void {
const row = record(value, "portable source_requirements");
exactKeys(row, [