build(agent): melter#14fd4b iteration
This commit is contained in:
parent
b6d3f3b9a9
commit
cc39590947
|
|
@ -12,6 +12,8 @@ from .ledger import GovernanceLedger
|
|||
from .adapters import sat_planner, relay_module
|
||||
from .solver import ADMMNode
|
||||
from .delta_synopsis import build_synopsis, build_priority_key, serialize_synopsis, deserialize_synopsis, verify_synopsis
|
||||
from .witness import generate_feasibility_witness
|
||||
from .safety_stub import extract_safety_stub
|
||||
from .mission import MissionTask, ContactWindow, MissionNode, MissionSimulator
|
||||
|
||||
__all__ = [
|
||||
|
|
@ -28,6 +30,8 @@ __all__ = [
|
|||
"serialize_synopsis",
|
||||
"deserialize_synopsis",
|
||||
"verify_synopsis",
|
||||
"generate_feasibility_witness",
|
||||
"extract_safety_stub",
|
||||
"MissionTask",
|
||||
"ContactWindow",
|
||||
"MissionNode",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
"""Safety stub extractor.
|
||||
|
||||
Extracts a tiny, conservative safety stub from a PlanDelta. The stub contains
|
||||
only the minimal actions that are safety-related (e.g., safety_critical
|
||||
commitments) and a provenance hash linking back to the full delta snapshot.
|
||||
|
||||
The stub is intentionally tiny and can be executed in constrained runtimes.
|
||||
"""
|
||||
from typing import Dict, Any, List
|
||||
from .plan_delta import PlanDelta
|
||||
import json
|
||||
import hashlib
|
||||
|
||||
|
||||
def extract_safety_stub(delta: PlanDelta) -> Dict[str, Any]:
|
||||
"""Return a compact stub containing safety-critical commitments and a hash.
|
||||
|
||||
The stub fields:
|
||||
- stub_commitments: list of commitments filtered for safety_critical or
|
||||
those that match a small whitelist (e.g., type == 'safe-hold')
|
||||
- provenance: short hash of the full delta snapshot
|
||||
- origin: delta.origin for traceability
|
||||
"""
|
||||
stub_commitments: List[Dict[str, Any]] = []
|
||||
|
||||
for c in delta.commitments.value():
|
||||
if not isinstance(c, dict):
|
||||
continue
|
||||
# Keep explicit safety-critical commitments
|
||||
if c.get("safety_critical"):
|
||||
stub_commitments.append(_minimalize_commitment(c))
|
||||
continue
|
||||
# Keep very small whitelist of actions that are safe fallbacks
|
||||
if c.get("type") in ("safe-hold", "thruster-off", "throttle-back"):
|
||||
stub_commitments.append(_minimalize_commitment(c))
|
||||
|
||||
prov = _short_hash(delta.snapshot())
|
||||
|
||||
return {
|
||||
"stub_commitments": stub_commitments,
|
||||
"provenance": prov,
|
||||
"origin": getattr(delta, "origin", ""),
|
||||
}
|
||||
|
||||
|
||||
def _minimalize_commitment(c: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Return a tiny projection of a commitment preserving key invariants.
|
||||
|
||||
Keep only fields that are likely necessary to reason about safety.
|
||||
"""
|
||||
keys = ["task_id", "type", "fuel", "power", "deadline_step", "safety_critical"]
|
||||
return {k: c[k] for k in keys if k in c}
|
||||
|
||||
|
||||
def _short_hash(obj: Any) -> str:
|
||||
import hashlib
|
||||
|
||||
raw = json.dumps(obj, sort_keys=True, separators=(",", ":"))
|
||||
return hashlib.sha256(raw.encode("utf-8")).hexdigest()[:16]
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
"""Feasibility witness generator.
|
||||
|
||||
Produces a compact, quickly-verifiable witness for a PlanDelta describing
|
||||
coarse resource bounds (fuel, power, payload size). The witness is intended
|
||||
to be inexpensive to compute and small to attach to custody decisions.
|
||||
"""
|
||||
from typing import Dict, Any
|
||||
from .plan_delta import PlanDelta
|
||||
import json
|
||||
|
||||
|
||||
def generate_feasibility_witness(delta: PlanDelta) -> Dict[str, Any]:
|
||||
"""Produce a compact witness with conservative bounds.
|
||||
|
||||
The witness includes:
|
||||
- total_fuel: sum of declared fuel in commitments
|
||||
- total_power: sum of declared power in commitments
|
||||
- max_payload_bytes: sum of payload_bytes fields (upper bound)
|
||||
- commitment_count: number of commitments
|
||||
- summary_hash: short hash of the snapshot for quick correlation
|
||||
|
||||
These values are intentionally coarse (conservative sums) so a lightweight
|
||||
validator can quickly spot obvious infeasibility (e.g., fuel required > node fuel).
|
||||
"""
|
||||
total_fuel = 0.0
|
||||
total_power = 0.0
|
||||
max_payload = 0
|
||||
count = 0
|
||||
|
||||
for c in delta.commitments.value():
|
||||
if not isinstance(c, dict):
|
||||
continue
|
||||
count += 1
|
||||
try:
|
||||
total_fuel += float(c.get("fuel", 0.0))
|
||||
except Exception:
|
||||
total_fuel += 0.0
|
||||
try:
|
||||
total_power += float(c.get("power", 0.0))
|
||||
except Exception:
|
||||
total_power += 0.0
|
||||
try:
|
||||
max_payload += int(c.get("payload_bytes", 0))
|
||||
except Exception:
|
||||
max_payload += 0
|
||||
|
||||
snapshot = delta.snapshot()
|
||||
summary_hash = _short_hash(snapshot)
|
||||
|
||||
return {
|
||||
"total_fuel": total_fuel,
|
||||
"total_power": total_power,
|
||||
"max_payload_bytes": max_payload,
|
||||
"commitment_count": count,
|
||||
"summary_hash": summary_hash,
|
||||
}
|
||||
|
||||
|
||||
def _short_hash(obj: Any) -> str:
|
||||
"""Return a short hex digest for the JSON of obj."""
|
||||
import hashlib
|
||||
|
||||
raw = json.dumps(obj, sort_keys=True, separators=(",", ":"))
|
||||
return hashlib.sha256(raw.encode("utf-8")).hexdigest()[:16]
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
from gravityweave.plan_delta import PlanDelta
|
||||
from gravityweave.witness import generate_feasibility_witness
|
||||
from gravityweave.safety_stub import extract_safety_stub
|
||||
|
||||
|
||||
def test_generate_feasibility_witness_basic():
|
||||
pd = PlanDelta(origin="node1")
|
||||
pd.commitments.add({"type": "burn", "fuel": 5.0, "power": 1.0, "payload_bytes": 100})
|
||||
pd.commitments.add({"type": "downlink", "fuel": 0.0, "power": 2.0, "payload_bytes": 200})
|
||||
|
||||
w = generate_feasibility_witness(pd)
|
||||
assert w["total_fuel"] == 5.0
|
||||
assert w["total_power"] == 3.0
|
||||
assert w["max_payload_bytes"] == 300
|
||||
assert w["commitment_count"] == 2
|
||||
assert isinstance(w["summary_hash"], str) and len(w["summary_hash"]) == 16
|
||||
|
||||
|
||||
def test_extract_safety_stub_filters():
|
||||
pd = PlanDelta(origin="satA")
|
||||
pd.commitments.add({"task_id": "t1", "type": "science", "safety_critical": True, "fuel": 1.0})
|
||||
pd.commitments.add({"task_id": "t2", "type": "downlink", "fuel": 0.0})
|
||||
pd.commitments.add({"task_id": "t3", "type": "safe-hold", "fuel": 0.0})
|
||||
|
||||
stub = extract_safety_stub(pd)
|
||||
# should include t1 (safety_critical) and t3 (whitelist)
|
||||
ids = {c.get("task_id") for c in stub["stub_commitments"]}
|
||||
assert "t1" in ids
|
||||
assert "t3" in ids
|
||||
assert stub["origin"] == "satA"
|
||||
assert isinstance(stub["provenance"], str) and len(stub["provenance"]) == 16
|
||||
Loading…
Reference in New Issue