feat(observatory): add portable calculation profiles

This commit is contained in:
DCCONSTRUCTIONS
2026-08-31 15:42:56 +03:00
parent d1b75efcea
commit 9beb534108
75 changed files with 24419 additions and 348 deletions
@@ -101,6 +101,19 @@ function canonicalLab(overrides = {}) {
};
}
function legacyCalculationProfile(overrides = {}) {
return {
schema_version: "missioncore.observatory-calculation-profile/v1",
setup_id: "lab-v1-ravnoves004tree-final",
display_name: "LAB V1 · EoMT Cityscapes Large 1024 + DDRNet-39",
origin: "existing-result",
definition_id: null,
definition_version: null,
definition_sha256: null,
...overrides,
};
}
function canonicalProjectionProvenance(resultId, replayCapability) {
return {
schema_version: "missioncore.canonical-recorded-lab-projection/v1",
@@ -260,6 +273,69 @@ test("session catalog strictly decodes the explicit recorded LAB replay capabili
);
});
test("session catalog decodes a typed calculation profile without inferring unknown results", () => {
const resultId = `lab-v1-vegetation-shadow-${"8".repeat(64)}`;
const decoded = decodeObservationSessionCatalog({
items: [session({
id: resultId,
lab: canonicalLab({ calculation_profile: legacyCalculationProfile() }),
})],
}).items[0].lab;
assert.deepEqual(decoded.calculationProfile, {
schemaVersion: "missioncore.observatory-calculation-profile/v1",
setupId: "lab-v1-ravnoves004tree-final",
displayName: "LAB V1 · EoMT Cityscapes Large 1024 + DDRNet-39",
origin: "existing-result",
definitionId: null,
definitionVersion: null,
definitionSha256: null,
});
assert.equal(
decodeObservationSessionCatalog({
items: [session({ id: resultId, lab: canonicalLab() })],
}).items[0].lab.calculationProfile,
null,
);
assert.equal(
decodeObservationSessionCatalog({
items: [session({
id: resultId,
lab: canonicalLab({ calculation_profile: null }),
})],
}).items[0].lab.calculationProfile,
null,
);
assert.throws(
() => decodeObservationSessionCatalog({
items: [session({
id: resultId,
lab: canonicalLab({
calculation_profile: legacyCalculationProfile({
origin: "archived-definition",
definition_id: "lab-v1-portable",
}),
}),
})],
}),
ObservationSessionContractError,
);
assert.throws(
() => decodeObservationSessionCatalog({
items: [session({
id: resultId,
lab: canonicalLab({
calculation_profile: {
...legacyCalculationProfile(),
guessed_from_provenance: true,
},
}),
})],
}),
ObservationSessionContractError,
);
});
test("opened archive is named in the scene header and trash hover has no pill", async () => {
const appSource = await readFile(new URL("../src/App.tsx", import.meta.url), "utf8");
const styles = await readFile(
@@ -365,7 +441,7 @@ test("source and laboratory catalogs are requested as disjoint backend projectio
assert.deepEqual(calls, [
"/api/v1/observation-sessions?limit=100&scope=source",
"/api/v1/observation-sessions?limit=100&scope=laboratory&lab_contract=v2",
"/api/v1/observation-sessions?limit=100&scope=laboratory&lab_contract=v3",
]);
});
@@ -69,6 +69,7 @@ function evidence(id, sourceSessionId, publishedAtUtc) {
runCreatedAtUtc: publishedAtUtc,
publishedAtUtc,
replayCapability: null,
calculationProfile: null,
provenance: { verdict: "must-not-be-inferred" },
},
};
@@ -174,7 +175,7 @@ test("Observatory fetches disjoint read-only source and laboratory projections",
assert.deepEqual(
calls.map(({ input }) => input).sort(),
[
"/api/v1/observation-sessions?limit=50&scope=laboratory&lab_contract=v2",
"/api/v1/observation-sessions?limit=50&scope=laboratory&lab_contract=v3",
"/api/v1/observation-sessions?limit=50&scope=source",
],
);
@@ -122,6 +122,7 @@ function portableSetup() {
contour_id: "worker-006",
state: "not-installed",
ready: false,
reason_code: "eomt-executor-release-unsealed",
reason: "Immutable executor release не установлен.",
},
existing_results: [],
@@ -136,6 +137,26 @@ function portableSetup() {
};
}
function portableM49Setup() {
const profile = portableSetup();
profile.setup_id = "m49-tgs-portable-v2";
profile.display_name = "M4.9T5 · TRAVEL TGS · CPU-only, без ML";
profile.description = "Динамический TGS-разбор записанной K1-сессии без ML; только наблюдение.";
profile.run_definition = {
definition_id: "m49-tgs-portable",
version: 2,
definition_sha256: "4".repeat(64),
result_schema: "missioncore.recorded-travel-tgs-review/v2",
result_kind: "recorded-source-paced-tgs-shadow",
models: [],
};
profile.source_compatibility.reason = "Запись соответствует требованиям TRAVEL TGS.";
profile.executor.reason_code = "m49-executor-release-unsealed";
profile.executor.reason = "Immutable executor release не установлен.";
profile.preflight.reason = "Переносимый вычислительный контур M4.9T5 пока недоступен.";
return profile;
}
before(async () => {
server = await createServer({
appType: "custom",
@@ -178,7 +199,7 @@ test("Observatory setup catalog keeps definition identity separate from executor
assert.equal(calls[0].init.method, "GET");
});
test("portable LAB V1 reports compatible source separately from unavailable Worker", async () => {
test("portable profiles report compatible source separately from unavailable Worker", async () => {
const calls = [];
const selected = (await fetchObservatoryPortableLaboratorySetups("source-a", {
fetcher: async (input, init) => {
@@ -186,7 +207,7 @@ test("portable LAB V1 reports compatible source separately from unavailable Work
return new Response(JSON.stringify({
schema_version: "missioncore.observatory-portable-setup-catalog/v2",
source_session_id: "source-a",
setups: [portableSetup()],
setups: [portableSetup(), portableM49Setup()],
authority,
}), { status: 200 });
},
@@ -200,52 +221,81 @@ test("portable LAB V1 reports compatible source separately from unavailable Work
"EoMT Cityscapes Large 1024",
"DDRNet-39",
]);
const m49 = (await fetchObservatoryPortableLaboratorySetups("source-a", {
fetcher: async () => new Response(JSON.stringify({
schema_version: "missioncore.observatory-portable-setup-catalog/v2",
source_session_id: "source-a",
setups: [portableSetup(), portableM49Setup()],
authority,
}), { status: 200 }),
})).setups[1];
assert.equal(m49.displayName, "M4.9T5 · TRAVEL TGS · CPU-only, без ML");
assert.deepEqual(m49.runDefinition.models, []);
assert.equal(
calls[0].input,
"/api/v1/observatory/portable-laboratory-setups?source_session_id=source-a",
);
let unexpectedNetworkCall = false;
let preflightRequest;
const preflight = await preflightObservatoryLaboratorySetup("source-a", selected, {
fetcher: async () => {
unexpectedNetworkCall = true;
throw new Error("portable preflight must use its server projection");
fetcher: async (input, init) => {
preflightRequest = { input: String(input), init };
return new Response(JSON.stringify({
schema_version: "missioncore.observatory-run-preflight/v1",
source_session_id: "source-a",
setup_id: selected.setupId,
definition_sha256: "3".repeat(64),
check_sha256: null,
outcome: "blocked",
submission_allowed: false,
checks: [{
check_id: "executor",
outcome: "fail",
reason_code: "eomt-executor-release-unsealed",
message: "Immutable executor release не установлен.",
}],
existing_result_ids: [],
executor: portableSetup().executor,
authority,
}), { status: 200 });
},
});
assert.equal(unexpectedNetworkCall, false);
assert.equal(preflightRequest.input, "/api/v1/observatory/run-preflights");
assert.equal(preflightRequest.init.method, "POST");
assert.equal(preflight.outcome, "blocked");
assert.equal(preflight.submissionAllowed, false);
assert.equal(preflight.checks[0].outcome, "pass");
assert.equal(preflight.checks[1].outcome, "fail");
assert.equal(preflight.checkSha256, null);
assert.equal(preflight.checks[0].outcome, "fail");
});
test("portable LAB V1 rejects a premature enqueue projection", async () => {
const premature = portableSetup();
premature.executor = {
test("portable profile accepts a consistent ready projection", async () => {
const ready = portableSetup();
ready.executor = {
contour_id: "worker-006",
state: "ready",
ready: true,
reason_code: null,
reason: null,
};
premature.preflight = {
ready.preflight = {
outcome: "ready",
action: "enqueue",
action: "check",
reason: "Запись готова к постановке в очередь.",
submission_allowed: true,
existing_result_ids: [],
};
await assert.rejects(
fetchObservatoryPortableLaboratorySetups("source-a", {
fetcher: async () => new Response(JSON.stringify({
schema_version: "missioncore.observatory-portable-setup-catalog/v2",
source_session_id: "source-a",
setups: [premature],
authority,
}), { status: 200 }),
}),
/значение изменилось|значение не поддерживается|постановка в очередь ещё не поддерживается/,
);
const catalog = await fetchObservatoryPortableLaboratorySetups("source-a", {
fetcher: async () => new Response(JSON.stringify({
schema_version: "missioncore.observatory-portable-setup-catalog/v2",
source_session_id: "source-a",
setups: [ready],
authority,
}), { status: 200 }),
});
assert.equal(catalog.setups[0].executor.state, "ready");
assert.equal(catalog.setups[0].preflight.outcome, "ready");
assert.equal(catalog.setups[0].preflight.submissionAllowed, true);
});
test("portable LAB V1 rejects an unbound existing result projection", async () => {
@@ -272,7 +322,7 @@ test("portable LAB V1 rejects an unbound existing result projection", async () =
authority,
}), { status: 200 }),
}),
/значение изменилось|проверяемая привязка результата/,
/значение изменилось|значение не поддерживается|проверяемая привязка результата/,
);
});
@@ -315,6 +365,7 @@ test("Observatory preflight sends the exact selected definition and never submit
source_session_id: "source-a",
setup_id: selected.setupId,
definition_sha256: "b".repeat(64),
check_sha256: null,
outcome: "blocked",
submission_allowed: false,
checks: [{
@@ -340,6 +391,7 @@ test("Observatory preflight sends the exact selected definition and never submit
});
assert.equal(preflight.outcome, "blocked");
assert.equal(preflight.submissionAllowed, false);
assert.equal(preflight.checkSha256, null);
});
test("Observatory dynamic preflight admits only an explicit queueable response", async () => {
@@ -374,6 +426,7 @@ test("Observatory dynamic preflight admits only an explicit queueable response",
assert.equal(preflight.outcome, "queueable");
assert.equal(preflight.submissionAllowed, true);
assert.equal(preflight.checkSha256, null);
});
test("Observatory setup contract rejects authority escalation and response drift", async () => {
@@ -61,6 +61,7 @@ function job(state = "queued") {
restart_from_zero: state === "paused",
preemption_receipt_sha256: null,
claim_generation: 0,
claim_lease: null,
result: state === "succeeded"
? { result_id: "m49-result", sha256: "d".repeat(64) }
: null,
@@ -132,6 +133,7 @@ test("Observatory submits only public identities and accepts every durable state
"source-a",
"m49-tgs",
"observatory-ui:source-a:m49-tgs:request-a",
null,
{
fetcher: async (input, init) => {
request = { input: String(input), init };
@@ -172,8 +174,41 @@ test("Observatory queue contract rejects authority escalation and response drift
"source-a",
"m49-tgs",
"observatory-ui:source-a:m49-tgs:request-a",
null,
{ fetcher: async () => new Response(JSON.stringify(drifted), { status: 200 }) },
),
ObservatoryRecordedJobContractError,
);
});
test("portable submission carries the exact definition/check fence", async () => {
let request;
await submitObservatoryRecordedJob(
"source-a",
"lab-v1-eomt-ddrnet-portable-v1",
"observatory-ui:source-a:lab-v1:request-a",
{
definitionSha256: "e".repeat(64),
checkSha256: "f".repeat(64),
},
{
fetcher: async (input, init) => {
request = { input: String(input), init };
const response = job("queued");
response.setup.setup_id = "lab-v1-eomt-ddrnet-portable-v1";
response.setup.definition_sha256 = "e".repeat(64);
response.source.session_id = "source-a";
return new Response(JSON.stringify(response), { status: 202 });
},
},
);
assert.deepEqual(JSON.parse(request.init.body), {
schema_version: "missioncore.observatory-recorded-run-submit/v1",
idempotency_key: "observatory-ui:source-a:lab-v1:request-a",
source_session_id: "source-a",
setup_id: "lab-v1-eomt-ddrnet-portable-v1",
definition_sha256: "e".repeat(64),
check_sha256: "f".repeat(64),
});
});
@@ -84,6 +84,14 @@ test("Observatory mounts the one shared canonical replay only after explicit adm
assert.match(workspace, /observatory-session-stack/);
assert.match(workspace, /observatory-session-summary__facts/);
assert.match(workspace, /observatory-evidence-card__copy/);
assert.match(
workspace,
/function evidenceResultSubtitle[\s\S]*calculationProfile\?\.displayName[\s\S]*`\$\{evidence\.label\} · \$\{profileName\}`[\s\S]*: evidence\.label/,
);
assert.match(
workspace,
/<span>\{evidenceResultSubtitle\(evidence\)\}<\/span>/,
);
assert.match(
workspace,
/evidence\.recordedRun \? \([\s\S]*name="trash"[\s\S]*name="edit"[\s\S]*Открыть визуальный разбор:[\s\S]*name="eye"/,
@@ -242,8 +250,12 @@ test("Observatory keeps one compact selector axis without the obsolete setup det
assert.doesNotMatch(setupHook, /Promise\.allSettled/);
assert.match(setupHook, /publishSetupCatalog\(\s*legacyCatalog/);
assert.match(setupHook, /preserveUnknownSelection: true/);
assert.match(
setupHook,
/portableProfileNames[\s\S]*legacy\.setups\.filter\([\s\S]*!portableProfileNames\.has\(setup\.displayName\)[\s\S]*\.\.\.portable\.setups/,
);
assert.match(setupHook, /selectedSetupId, sourceSessionId/);
assert.match(workspace, /Worker установлен, запуск закрыт/);
assert.match(workspace, /Worker готов к проверке/);
assert.match(
workspace,
/preflightCandidate\.definitionSha256[\s\S]*selectedSetup\?\.runDefinition\?\.definitionSha256/,