fix: reject broken runtime launchers and preserve failed proof evidence
Some checks failed
Governed runtime contract / contract (push) Failing after 16s

Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e387-534d-70e3-ad53-4ea05676db8c
This commit is contained in:
tegwick 2026-09-27 23:19:50 +02:00
parent 4e666d6fa3
commit 43e621439a
26 changed files with 1367 additions and 3 deletions

View file

@ -66,6 +66,16 @@ class GlasExecutionError(RuntimeError):
class GlasSpendError(GlasExecutionError):
"""Spend refusal with bounded, operator-safe reason text."""
def __init__(self, message: str, *, execution_evidence: Any = None) -> None:
super().__init__(message)
evidence = normalise_execution_evidence_for_close(execution_evidence)
# Accounting must remain fail-closed without erasing the gateway stage
# and cleanup facts. Do not transport raw provider error/output here.
self.execution_evidence = {
key: value for key, value in evidence.items()
if key not in {"error", "artifacts"}
}
def normalise_execution_evidence_for_close(raw: Any) -> dict[str, Any]:
"""Retain only bounded Glas evidence fields safe for durable close state."""
@ -85,6 +95,10 @@ def normalise_execution_evidence_for_close(raw: Any) -> dict[str, Any]:
and value >= 0
):
result[key] = value
for key in ("session_cleanup", "sandbox_destroy"):
value = raw.get(key)
if isinstance(value, str) and value in {"succeeded", "failed", "not_attempted"}:
result[key] = value
artifacts = raw.get("artifacts")
if isinstance(artifacts, list):
result["artifacts"] = [
@ -220,7 +234,10 @@ def execute_profiled_run(
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
raise GlasSpendError(
f"spend accounting refused: {exc}",
execution_evidence=raw["evidence"],
) 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":