Reserve worker spend durably before governed dispatch
Some checks failed
Governed runtime contract / contract (push) Has been cancelled

Assistant: codex
Assistant-Model: gpt-5.6-luna
Assistant-Session: 01a07ff8-19d0-7820-b4d0-1353833cb7fc
This commit is contained in:
tegwick 2026-09-09 17:58:27 +02:00
parent 4ffb8acb19
commit 38b25fbc26
14 changed files with 1378 additions and 9 deletions

View file

@ -14,6 +14,7 @@ from typing import Any
from rein_aharness.execution_cancel import ExecutionCancel, ExecutionCancelled, resolve_cancel
from rein_aharness.ops_run_client import OpsRun, OpsRunConfig, resolve_ops_target
from rein_aharness.spend_admission import SpendAdmissionError, worker_spend
GLAS_APPROACH = "glas-profile"
GLAS_ACTOR = "agt"
@ -61,6 +62,10 @@ class GlasExecutionError(RuntimeError):
"""The authoritative Glas invocation could not produce a GatewayResult."""
class GlasSpendError(GlasExecutionError):
"""Spend refusal with bounded, operator-safe reason text."""
def normalise_execution_evidence_for_close(raw: Any) -> dict[str, Any]:
"""Retain only bounded Glas evidence fields safe for durable close state."""
if not isinstance(raw, dict):
@ -120,7 +125,7 @@ def _request_kwargs(run: OpsRun, config: OpsRunConfig, report_to_hub: bool) -> d
# actor type. Sand-boxer validates governed execution actors as
# adm|agt|atm, so this runtime enters the gateway as an agent.
"actor": GLAS_ACTOR,
"project": "rein-aharness",
"project": config.execution_project,
"request_id": run.id,
"report_to_hub": report_to_hub,
}
@ -168,10 +173,25 @@ def execute_profiled_run(
try:
request = request_factory(**_request_kwargs(run, config, report_to_hub))
result = gateway(request, artifact_capture=transfer.capture) if transfer else gateway(request)
kwargs = {"artifact_capture": transfer.capture} if transfer else {}
spend = worker_spend(config)
if spend is not None:
from glas_harness.profiles import ProfileCatalog
catalog = ProfileCatalog()
profile, descriptor = catalog.resolve(run.harness_profile_ref)
catalog.require_operational(profile)
spend.validate_dispatch(run, config, request, profile, descriptor)
# The same cached catalog supplies the checked profile to Glas.
kwargs["catalog"] = catalog
if guard is not None:
guard.check()
spend.reserve(run)
result = gateway(request, **kwargs)
raw = result.model_dump(mode="json") if hasattr(result, "model_dump") else result
except ExecutionCancelled:
raise
except SpendAdmissionError as exc:
raise GlasSpendError(f"spend admission refused: {exc}") from None
except GlasExecutionError:
raise
except Exception as exc:
@ -185,6 +205,12 @@ def execute_profiled_run(
raise GlasExecutionError("Glas gateway returned an invalid GatewayResult")
if not isinstance(raw.get("evidence"), dict):
raise GlasExecutionError("Glas GatewayResult is missing execution evidence")
if spend is not None:
try:
if not spend.observe(run.id, raw):
raise SpendAdmissionError("execution accounting requires reconciliation")
except SpendAdmissionError as exc:
raise GlasSpendError(f"spend accounting refused: {exc}") from None
if transfer is not None and raw["ok"]:
evidence = raw["evidence"]
if evidence.get("session_cleanup") != "succeeded" or evidence.get("sandbox_destroy") != "succeeded":