Files
govoplan/tools/devkit/govoplan_devkit/checkpoints.py
T
zemion 2ffdb23f69
Dependency Audit / dependency-audit (push) Successful in 1m45s
Deployment Installer / deployment-installer (push) Successful in 6s
Security Audit / security-audit (push) Successful in 11m30s
feat(devkit): add resumable workspace automation and UI review tooling
Verified with the coordinated workspace changes by devkit full run
2026-09-08T225814-186389-0000-3e3ed7cd (all seven phases passed).
This shared UI pass does not mark the individual module reviews complete.
2026-09-09 02:03:17 +02:00

245 lines
9.0 KiB
Python
Executable File

"""Independently verified check results; never an artifact/build-output cache."""
from __future__ import annotations
from copy import deepcopy
import threading
import re
from .common import digest, now
from .inputs import InputSnapshotter, FINGERPRINT_VERSION
CHECKPOINT_VERSION = 1
def validate_checkpoint_receipt(receipt):
"""New checkpoints are explicit; legacy status alone never certifies a phase."""
version = receipt.get("fingerprint_version")
if version is None:
return
if version != FINGERPRINT_VERSION:
raise ValueError("Unsupported check fingerprint version")
for stage in receipt["stages"]:
verified = stage.get("checkpoint_verified")
if type(verified) is not bool:
raise ValueError("Stage checkpoint verification must be boolean")
if stage["status"] == "passed" and not verified:
raise ValueError(
"Passing stage requires an independently verified checkpoint"
)
if not verified:
continue
if (
stage["status"] != "passed"
or stage.get("checkpoint_version") != CHECKPOINT_VERSION
):
raise ValueError("Invalid verified checkpoint state or version")
for field in (
"cache_key",
"input_fingerprint",
"stage_plan_fingerprint",
"log_sha256",
):
if not isinstance(stage.get(field), str) or not re.fullmatch(
r"[a-f0-9]{64}", stage[field]
):
raise ValueError(
"Verified checkpoint requires bounded content identities"
)
if (
not isinstance(stage.get("checkpoint_at"), str)
or not stage["checkpoint_at"]
):
raise ValueError("Verified checkpoint requires its recording time")
scope = stage.get("input_scope")
if (
not isinstance(scope, dict)
or scope.get("version") != 1
or scope.get("kind") not in {"workspace", "repositories"}
or type(scope.get("declared")) is not bool
):
raise ValueError("Verified checkpoint requires a versioned input scope")
names = scope.get("repos")
if (
not isinstance(names, list)
or not 1 <= len(names) <= 256
or any(not isinstance(name, str) for name in names)
or len(set(names)) != len(names)
):
raise ValueError(
"Verified checkpoint requires bounded repository identities"
)
class Checkpoints:
def __init__(self, project, workspace, plan, environment_probe, cancelled):
self.scanner = InputSnapshotter(project, workspace_root=workspace)
self.plan = {stage["id"]: stage for stage in plan}
self.environment_probe = environment_probe
self.cancelled = cancelled
self.lock = threading.RLock()
self.initial = None
self.environment = None
def source(self, stages=None):
with self.lock:
return self.scanner.snapshot(
list(self.plan.values()) if stages is None else stages
)
def probe_environment(self):
value = self.environment_probe()
self.check_cancelled()
return value
def check_cancelled(self):
if self.cancelled.is_set():
raise InterruptedError("Check cancelled during input verification")
def initialize(self):
self.initial = self.source()
self.check_cancelled()
self.environment = self.probe_environment()
return self.initial, self.environment
def closure(self, stage):
selected = {}
def include(item):
if item["id"] in selected:
return
selected[item["id"]] = item
for identity in item["deps"]:
include(self.plan[identity])
include(self.plan[stage["id"]])
return [selected[key] for key in sorted(selected)]
def identity(self, stage):
with self.lock:
closure = self.closure(stage)
snapshot = self.source(closure)
self.check_cancelled()
environment = self.probe_environment()
own = snapshot["stages"][stage["id"]]
key = digest(
{
"checkpoint_version": CHECKPOINT_VERSION,
"inputs": {
identity: value["fingerprint"]
for identity, value in snapshot["stages"].items()
},
"environment": environment,
}
)
return {
"checkpoint_version": CHECKPOINT_VERSION,
"cache_key": key,
"input_fingerprint": own["fingerprint"],
"input_scope": own["scope"],
"stage_plan_fingerprint": own["plan_fingerprint"],
"stage_environment_fingerprint": environment,
"dependency_input_fingerprints": {
item["id"]: snapshot["stages"][item["id"]]["fingerprint"]
for item in closure
if item["id"] != stage["id"]
},
}
def prepare(self, stage, prior, allow_reuse, verify_log):
before = self.identity(stage)
reason = "No previous verified checkpoint"
if stage.get("reuse", "verified") == "never":
reason = (
"This stage explicitly disables reuse (outputs/setup must be recreated)"
)
elif not allow_reuse:
reason = "A data dependency ran again; its consumers must run again"
elif (
prior
and prior.get("status") == "passed"
and prior.get("checkpoint_verified") is True
and prior.get("checkpoint_version") == CHECKPOINT_VERSION
):
if prior.get("cache_key") == before["cache_key"]:
# Receipt command text is never executed. Only the freshly planned
# stage runs; a cached log must independently match its content hash.
verify_log(prior)
result = {
**before,
**{
key: deepcopy(prior[key])
for key in (
"status",
"exit_code",
"duration_seconds",
"log_path",
"log_sha256",
"output_truncated",
"omitted_output_bytes",
"checkpoint_at",
)
if key in prior
},
}
result.update(
checkpoint_verified=True,
reuse_reason="Verified checkpoint matches current inputs, command, dependencies and environment",
)
return before, result
reason = (
"Declared inputs, command, dependency inputs or environment changed"
)
before["reuse_reason"] = reason
return before, None
def finish(self, stage, before, result):
result = {**result, **before, "checkpoint_verified": False}
if result["status"] != "passed" or result.get("exit_code") != 0:
return result
after = self.identity(stage)
if before["cache_key"] != after["cache_key"]:
result.update(
status="stale",
error="Stage inputs or environment changed during execution; no reusable checkpoint was recorded",
)
else:
result.update(checkpoint_verified=True, checkpoint_at=now())
return result
def finalize(self, stages):
final = self.source()
self.check_cancelled()
environment = self.probe_environment()
valid = (
final["observed_source_fingerprint"]
== self.initial["observed_source_fingerprint"]
and environment == self.environment
)
for stage in stages:
if stage["status"] != "passed":
valid = valid and stage["status"] != "stale"
continue
closure = self.closure(self.plan[stage["id"]])
key = digest(
{
"checkpoint_version": CHECKPOINT_VERSION,
"inputs": {
item["id"]: final["stages"][item["id"]]["fingerprint"]
for item in closure
},
"environment": environment,
}
)
if (
stage.get("checkpoint_verified") is not True
or stage.get("cache_key") != key
):
stage.update(
status="stale",
checkpoint_verified=False,
error="Final inputs no longer match this checkpoint",
)
valid = False
return valid, final, environment