refactor(lab): separate release contract identity
This commit is contained in:
@@ -65,13 +65,13 @@ PORTABLE_LAB_V1_RESULT_IDENTITY_SCHEMA: Final = (
|
||||
"missioncore.recorded-eomt-ddrnet-review-identity/v2"
|
||||
)
|
||||
PORTABLE_LAB_V1_RELEASE_SCHEMA: Final = (
|
||||
"missioncore.observatory-portable-lab-v1-executor-candidate/v1"
|
||||
"missioncore.observatory-portable-lab-v1-executor-candidate/v2"
|
||||
)
|
||||
PORTABLE_LAB_V1_RELEASE_IDENTITY_SCHEMA: Final = (
|
||||
"missioncore.observatory-portable-lab-v1-executor-candidate-identity/v1"
|
||||
"missioncore.observatory-portable-lab-v1-executor-candidate-identity/v2"
|
||||
)
|
||||
PORTABLE_LAB_V1_EXECUTOR_SEAL_SCHEMA: Final = (
|
||||
"missioncore.observatory-portable-lab-v1-executor-seal/v1"
|
||||
"missioncore.observatory-portable-lab-v1-executor-seal/v2"
|
||||
)
|
||||
PORTABLE_LAB_V1_DDRNET_PROFILE_SCHEMA: Final = (
|
||||
"missioncore.lab-v1-eomt-ddrnet-portable-profile/v2"
|
||||
@@ -452,7 +452,7 @@ class PortableLabV1ReleaseCandidate:
|
||||
setup_id: str
|
||||
definition_id: str
|
||||
definition_version: int
|
||||
definition_sha256: str
|
||||
definition_contract_sha256: str
|
||||
result_contract_sha256: str
|
||||
executor_image_sha256: str | None
|
||||
assets: tuple[PortableLabV1ReleaseAsset, ...]
|
||||
@@ -474,7 +474,10 @@ class PortableLabV1ReleaseCandidate:
|
||||
or self.definition_version < 1
|
||||
):
|
||||
raise PortableLabV1ReleaseError("release definition version is invalid")
|
||||
_digest(self.definition_sha256, "release definition sha256")
|
||||
_digest(
|
||||
self.definition_contract_sha256,
|
||||
"release definition contract sha256",
|
||||
)
|
||||
_digest(self.result_contract_sha256, "release result contract sha256")
|
||||
if self.executor_image_sha256 is not None:
|
||||
_digest(self.executor_image_sha256, "release executor image sha256")
|
||||
@@ -523,7 +526,7 @@ class PortableLabV1ReleaseCandidate:
|
||||
"setup_id",
|
||||
"definition_id",
|
||||
"definition_version",
|
||||
"definition_sha256",
|
||||
"definition_contract_sha256",
|
||||
"result_contract_sha256",
|
||||
"executor_image_sha256",
|
||||
"assets",
|
||||
@@ -563,8 +566,9 @@ class PortableLabV1ReleaseCandidate:
|
||||
definition_version=_positive_int(
|
||||
document["definition_version"], "release definition version"
|
||||
),
|
||||
definition_sha256=_string(
|
||||
document["definition_sha256"], "release definition sha256"
|
||||
definition_contract_sha256=_string(
|
||||
document["definition_contract_sha256"],
|
||||
"release definition contract sha256",
|
||||
),
|
||||
result_contract_sha256=_string(
|
||||
document["result_contract_sha256"],
|
||||
@@ -587,7 +591,7 @@ class PortableLabV1ReleaseCandidate:
|
||||
"setup_id": self.setup_id,
|
||||
"definition_id": self.definition_id,
|
||||
"definition_version": self.definition_version,
|
||||
"definition_sha256": self.definition_sha256,
|
||||
"definition_contract_sha256": self.definition_contract_sha256,
|
||||
"result_contract_sha256": self.result_contract_sha256,
|
||||
"executor_image_sha256": self.executor_image_sha256,
|
||||
"assets": [asset.as_dict() for asset in self.assets],
|
||||
@@ -601,7 +605,8 @@ class PortableLabV1ReleaseCandidate:
|
||||
definition.setup_id != self.setup_id
|
||||
or definition.definition_id != self.definition_id
|
||||
or definition.version != self.definition_version
|
||||
or definition.definition_sha256 != self.definition_sha256
|
||||
or definition.executable_contract_sha256
|
||||
!= self.definition_contract_sha256
|
||||
or definition.result_contract.contract_sha256
|
||||
!= self.result_contract_sha256
|
||||
):
|
||||
@@ -661,7 +666,7 @@ class PortableLabV1ReleaseCandidate:
|
||||
"schema_version": PORTABLE_LAB_V1_EXECUTOR_SEAL_SCHEMA,
|
||||
"release_id": self.release_id,
|
||||
"candidate_sha256": self.candidate_sha256,
|
||||
"definition_sha256": self.definition_sha256,
|
||||
"definition_contract_sha256": self.definition_contract_sha256,
|
||||
"executor_image_sha256": self.executor_image_sha256,
|
||||
"asset_sha256s": [asset.sha256 for asset in self.assets],
|
||||
"authority": dict(OBSERVATION_ONLY_AUTHORITY),
|
||||
@@ -669,7 +674,7 @@ class PortableLabV1ReleaseCandidate:
|
||||
return PortableLabV1ExecutorSeal(
|
||||
release_id=self.release_id,
|
||||
candidate_sha256=self.candidate_sha256,
|
||||
definition_sha256=self.definition_sha256,
|
||||
definition_contract_sha256=self.definition_contract_sha256,
|
||||
executor_image_sha256=self.executor_image_sha256,
|
||||
release_sha256=canonical_sha256(identity),
|
||||
)
|
||||
@@ -681,7 +686,7 @@ class PortableLabV1ExecutorSeal:
|
||||
|
||||
release_id: str
|
||||
candidate_sha256: str
|
||||
definition_sha256: str
|
||||
definition_contract_sha256: str
|
||||
executor_image_sha256: str
|
||||
release_sha256: str
|
||||
|
||||
@@ -689,7 +694,10 @@ class PortableLabV1ExecutorSeal:
|
||||
_pattern(self.release_id, _IDENTIFIER, "executor seal release id")
|
||||
for value, label in (
|
||||
(self.candidate_sha256, "executor seal candidate sha256"),
|
||||
(self.definition_sha256, "executor seal definition sha256"),
|
||||
(
|
||||
self.definition_contract_sha256,
|
||||
"executor seal definition contract sha256",
|
||||
),
|
||||
(self.executor_image_sha256, "executor seal image sha256"),
|
||||
(self.release_sha256, "executor seal release sha256"),
|
||||
):
|
||||
@@ -700,7 +708,7 @@ class PortableLabV1ExecutorSeal:
|
||||
"schema_version": PORTABLE_LAB_V1_EXECUTOR_SEAL_SCHEMA,
|
||||
"release_id": self.release_id,
|
||||
"candidate_sha256": self.candidate_sha256,
|
||||
"definition_sha256": self.definition_sha256,
|
||||
"definition_contract_sha256": self.definition_contract_sha256,
|
||||
"executor_image_sha256": self.executor_image_sha256,
|
||||
"release_sha256": self.release_sha256,
|
||||
"authority": dict(OBSERVATION_ONLY_AUTHORITY),
|
||||
|
||||
@@ -505,7 +505,7 @@ def compose_lab_v1_portable_executor_adapter(
|
||||
) -> PortableWorkerExecutorAdapter:
|
||||
"""Compose the shared Worker ports without enabling or registering them."""
|
||||
|
||||
_verify_candidate_release(candidate, installation)
|
||||
_verify_candidate_release(candidate, installation, definition)
|
||||
return PortableWorkerExecutorAdapter(
|
||||
candidate=candidate,
|
||||
definition=definition,
|
||||
@@ -560,6 +560,7 @@ def _verify_runtime_plan(
|
||||
def _verify_candidate_release(
|
||||
candidate: PortableWorkerRuntimeCandidate,
|
||||
installation: PortableLabV1RunnerInstallation,
|
||||
definition: PortableRunDefinition,
|
||||
) -> None:
|
||||
release = installation.release
|
||||
release_assets = {asset.asset_id: asset for asset in release.assets}
|
||||
@@ -569,7 +570,9 @@ def _verify_candidate_release(
|
||||
candidate.setup_id != release.setup_id
|
||||
or candidate.definition_id != release.definition_id
|
||||
or candidate.definition_version != release.definition_version
|
||||
or candidate.definition_sha256 != release.definition_sha256
|
||||
or candidate.definition_sha256 != definition.definition_sha256
|
||||
or release.definition_contract_sha256
|
||||
!= definition.executable_contract_sha256
|
||||
or candidate.result_contract_sha256 != release.result_contract_sha256
|
||||
or tuple(phase.phase_id for phase in candidate.phases) != PORTABLE_LAB_V1_RUNTIME_PHASES
|
||||
or executor is None
|
||||
|
||||
@@ -32,6 +32,9 @@ PORTABLE_RUN_DEFINITION_REGISTRY_SCHEMA: Final = (
|
||||
PORTABLE_RUN_DEFINITION_IDENTITY_SCHEMA: Final = (
|
||||
"missioncore.observatory-portable-run-definition-identity/v2"
|
||||
)
|
||||
PORTABLE_RUN_DEFINITION_EXECUTABLE_CONTRACT_SCHEMA: Final = (
|
||||
"missioncore.observatory-portable-run-definition-executable-contract/v1"
|
||||
)
|
||||
PORTABLE_SOURCE_ADAPTER_IDENTITY_SCHEMA: Final = "missioncore.portable-source-adapter/v1"
|
||||
PORTABLE_MODEL_MANIFEST_SCHEMA: Final = "missioncore.observatory-portable-model-manifest/v2"
|
||||
PORTABLE_RESOURCE_PROFILE_SCHEMA: Final = "missioncore.observatory-portable-resource-profile/v2"
|
||||
@@ -571,6 +574,35 @@ class PortableRunDefinition:
|
||||
def learned_models(self) -> tuple[str, ...]:
|
||||
return tuple(model.release_id for model in self.models)
|
||||
|
||||
@property
|
||||
def executable_contract_sha256(self) -> str:
|
||||
"""Return the stable executable contract, independent of installation state.
|
||||
|
||||
Executor availability is deliberately excluded. An executor release may
|
||||
bind this digest before the resulting release identity is written back to
|
||||
the full RunDefinition without creating a definition/release digest cycle.
|
||||
"""
|
||||
|
||||
return canonical_sha256(self.executable_contract_document())
|
||||
|
||||
def executable_contract_document(self) -> dict[str, object]:
|
||||
"""Return the canonical computation contract without executor availability."""
|
||||
|
||||
return {
|
||||
"schema_version": PORTABLE_RUN_DEFINITION_EXECUTABLE_CONTRACT_SCHEMA,
|
||||
"setup_id": self.setup_id,
|
||||
"definition_id": self.definition_id,
|
||||
"version": self.version,
|
||||
"source_requirements": self.source_requirements.as_dict(),
|
||||
"source_adapter": self.source_adapter.as_dict(),
|
||||
"components": [component.as_dict() for component in self.components],
|
||||
"models": [model.as_dict() for model in self.models],
|
||||
"model_manifest_sha256": self.model_manifest_sha256,
|
||||
"resource_profile": self.resource_profile.as_dict(),
|
||||
"result_contract": self.result_contract.as_dict(),
|
||||
"authority": self.authority.as_dict(),
|
||||
}
|
||||
|
||||
def identity_document(self) -> dict[str, object]:
|
||||
"""Return the complete canonical executable identity."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user