AISA v2.0 / Technical documentation / validate_runtime_contracts.py
validate_runtime_contracts.py
Python · 216 lines · 9,411 bytes · wiki path 10 Architecture/contracts/validate_runtime_contracts.py · download the raw file · cited from Contracts
Same folder: Connectors.Abstractions.cs · configuration-change.schema.json · configuration-input.schema.json · connector-capability.schema.json · eval-set.schema.json · execution-obligations.schema.json · ledger-record.schema.json · message-envelope.schema.json · model-turn.schema.json · module-manifest.schema.json · openapi.yaml · realtime-events.schema.json · runtime-state.schema.json · tool-package.schema.json · validate_case_journeys.py · validate_contracts.py · validate_tool_packages.py · write-shape.schema.json
#!/usr/bin/env python3
"""Offline contract/conformance checks. No model, estate, database or network calls.
These validate the specification and its examples, not a platform implementation.
Run: python validate_runtime_contracts.py
"""
from __future__ import annotations
import copy
import json
from pathlib import Path
from jsonschema import Draft202012Validator
HERE = Path(__file__).parent
def load(name):
return json.loads((HERE / name).read_text(encoding="utf-8"))
def schema_errors(name, document):
schema = load(name + ".schema.json")
Draft202012Validator.check_schema(schema)
return [e.message for e in Draft202012Validator(schema).iter_errors(document)]
def manifest_errors(doc):
errors = schema_errors("module-manifest", doc)
if errors:
return errors
profiles = {p["key"] for p in doc["profiles"]}
stages = {s["id"] for s in doc["stages"]}
if len(profiles) != len(doc["profiles"]):
errors.append("duplicate profile key")
if len(stages) != len(doc["stages"]):
errors.append("duplicate stage id")
if doc["root_profile"] not in profiles or doc["entry_stage"] not in stages:
errors.append("entry or root does not resolve")
if doc["kind"] == "embedded" and (doc["case_module"] != "support" or doc["root_profile"] != "support.root"):
errors.append("the embedded data graph retains the Support case and root")
for stage in doc["stages"]:
selected = {stage["profile"]} | set(stage.get("profile_variants", {}).values())
if not selected <= profiles:
errors.append("stage profile does not resolve")
for contract in stage["consumes"] + stage["produces"]:
if contract.startswith("paper:"):
continue
candidates = [HERE / (contract + ".schema.json"), HERE / "drafts" / (contract + ".schema.json")]
if contract == "product":
candidates.append(HERE.parent / "20 Configuration/contracts/product.schema.json")
if not any(p.exists() for p in candidates):
errors.append("unresolved stage contract: " + contract)
graph = {key: [] for key in stages}
for edge in doc["edges"]:
if edge["from"] not in stages or edge["to"] not in stages:
errors.append("edge endpoint does not resolve")
elif edge["kind"] == "dependency":
graph[edge["from"]].append(edge["to"])
visiting, seen = set(), set()
def visit(node):
if node in visiting:
errors.append("dependency cycle must be an explicit rework edge")
return
if node in seen:
return
visiting.add(node)
for child in graph[node]:
visit(child)
visiting.remove(node)
seen.add(node)
for node in graph:
visit(node)
return errors
def model_errors(doc):
errors = schema_errors("model-turn", doc)
if errors:
return errors
if doc["kind"] == "tool_calls":
if not doc["tool_calls"] or doc["message"] is not None:
errors.append("tool_calls needs calls and no message")
for call in doc["tool_calls"]:
try:
args = json.loads(call["arguments_json"])
if not isinstance(args, dict):
errors.append("tool arguments must be an object")
except ValueError:
errors.append("tool arguments are malformed JSON")
else:
if doc["tool_calls"] or doc["message"] is None:
return errors + ["message needs a message and no calls"]
msg = doc["message"]
try:
payload = json.loads(msg["payload_json"])
definitions = load("message-envelope.schema.json")["$defs"]
schema = {"$ref": "#/$defs/" + msg["type"], "$defs": definitions}
errors += [e.message for e in Draft202012Validator(schema).iter_errors(payload)]
except ValueError:
errors.append("message payload is malformed JSON")
if msg["type"] in ("Plan", "Result") and not msg["paper_ref"]:
errors.append("Plan and Result require a stored paper")
return errors
def state_errors(doc):
errors = schema_errors("runtime-state", doc)
if errors:
return errors
pending = doc["pending_call_ids"] + doc["pending_gate_ids"] + doc["pending_message_ids"]
if doc["phase"] == "complete" and pending:
errors.append("completed task cannot retain pending work")
if doc["phase"] == "waiting" and not pending:
errors.append("waiting state must name its wake-up dependency")
for key in ("manifest_policy_id", "manifest_hash", "case_type_id", "profile_id", "framework_version", "runtime_version"):
if not doc["pins"][key]:
errors.append("missing pin: " + key)
return errors
def required_effect_gates(effect, traits):
"""Reference truth table for Gating 3.1; not production authorisation code."""
known_effects = {"transactional", "compensable", "irreversible", "ddl"}
known_traits = {"working", "shared", "customer_facing", "external", "customer_visible"}
if effect not in known_effects or not traits or not set(traits) <= known_traits:
raise ValueError("unclassified effect/target")
if effect in ("transactional", "compensable") and set(traits) == {"external"}:
raise ValueError("external alone does not establish a bounded target")
gates = set()
if effect == "ddl":
gates.add("HW-ddl")
if effect == "irreversible":
gates.add("HW-irreversible")
for trait, gate in (("shared", "HW-shared"), ("customer_facing", "H5"), ("customer_visible", "H5-send")):
if trait in traits:
gates.add(gate)
if not gates:
gates.add("HW-instance")
return sorted(gates)
def recovery_action(state, landed=None):
"""Agent Runtime 7: a lost checkpoint never implies a repeat of an effect."""
if state == "succeeded":
return "reuse_result"
if state == "prepared":
return "recheck_then_dispatch"
if state == "refused":
return "return_refusal"
if state in ("dispatched", "unknown", "failed"):
return {"applied": "record_and_reuse", "not_applied": "capability_retry_rule"}.get(landed, "reconcile_or_park")
raise ValueError("unknown journal state")
def main():
checked, failed = 0, []
def check(name, passed):
nonlocal checked
checked += 1
if not passed:
failed.append(name)
manifests = [load("manifests/" + n + ".json") for n in ("support", "data", "configuration", "source")]
owners = {}
for doc in manifests:
errors = manifest_errors(doc)
check("manifest " + doc["module_id"] + ": " + "; ".join(errors), not errors)
for profile in doc["profiles"]:
for node in profile["owns"]:
check("one owner for " + node, owners.get(node, profile["key"]) == profile["key"])
owners[node] = profile["key"]
broken = copy.deepcopy(manifests[0])
broken["edges"].append({"from": "closure", "to": "S1", "on": "ready", "kind": "dependency"})
check("reject implicit cycle", any("cycle" in e for e in manifest_errors(broken)))
broken = copy.deepcopy(manifests[0])
broken["stages"][0]["profile"] = "unregistered.profile"
check("reject missing profile", any("profile" in e for e in manifest_errors(broken)))
for family, validator in (("model-turn", model_errors), ("runtime-state", state_errors)):
paths = sorted((HERE / "fixtures").glob(family + ".*.json"))
check(family + " has valid and broken examples", len(paths) >= 2 and any(".valid." in p.name for p in paths) and any(".broken." in p.name for p in paths))
for path in paths:
errors = validator(json.loads(path.read_text(encoding="utf-8")))
check(path.name, bool(errors) == (".broken." in path.name))
check("shared PROD DDL composes all decisions", required_effect_gates("ddl", ["shared", "customer_facing"]) == ["H5", "HW-ddl", "HW-shared"])
check("irreversible customer send composes", required_effect_gates("irreversible", ["customer_visible"]) == ["H5-send", "HW-irreversible"])
check("working write has instance decision", required_effect_gates("transactional", ["working"]) == ["HW-instance"])
for bad in (("read", ["working"]), ("ddl", ["guessed_target"]), ("compensable", ["external"])):
try:
required_effect_gates(*bad)
check("unknown classification refused", False)
except ValueError:
check("unknown classification refused", True)
for state, landed, expected in [
("succeeded", None, "reuse_result"),
("dispatched", "applied", "record_and_reuse"),
("dispatched", "not_applied", "capability_retry_rule"),
("unknown", "partly_applied", "reconcile_or_park"),
("unknown", "unknown", "reconcile_or_park"),
("failed", None, "reconcile_or_park"),
("prepared", None, "recheck_then_dispatch"),
]:
check("recovery " + state + "/" + str(landed), recovery_action(state, landed) == expected)
print(str(checked) + " runtime contract/conformance checks; " + str(len(failed)) + " failures")
for name in failed:
print(" FAIL " + name)
return bool(failed)
if __name__ == "__main__":
raise SystemExit(main())