Spaces:
Running
Running
chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)
Browse filesAutomated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): Dockerfile, szl_cheapest_watt.py
Deleted (gone from the repo + Dockerfile COPY set): (none)
Keeps the Space-built backend (serve.py + the Dockerfile-COPY'd .py
modules) identical to GitHub main so the Space never rebuilds from a
stale backend, new endpoints don't 404 there, and orphaned modules
removed from the repo don't linger in the Space tree.
- Dockerfile +1 -1
- szl_cheapest_watt.py +528 -0
Dockerfile
CHANGED
|
@@ -150,7 +150,7 @@ COPY szl_formula_wiring.py a11oy_code_engine.py a11oy_code.py a11oy_seismic.py s
|
|
| 150 |
COPY szl_energy_budget.py szl_energy_sovereign.py szl_energy_provenance.py szl_heart_blood.py szl_engine_status.py szl_backend_hardening.py revenue_endpoints.py a11oy_harvest_endpoints.py ./
|
| 151 |
# energy operator/ledger/projection modules — imported by serve.py (guarded);
|
| 152 |
# MUST be per-file COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back to a STUB.
|
| 153 |
-
COPY joule_billing.py szl_energy_ledger.py szl_energy_operator.py szl_energy_projection.py ./
|
| 154 |
# K-Verify governed-inference benchmark — imported by serve.py (guarded). MUST be
|
| 155 |
# per-file COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back and
|
| 156 |
# /api/a11oy/v1/kverify/* 404s. Reuses szl_energy_operator (inference + NVML joules)
|
|
|
|
| 150 |
COPY szl_energy_budget.py szl_energy_sovereign.py szl_energy_provenance.py szl_heart_blood.py szl_engine_status.py szl_backend_hardening.py revenue_endpoints.py a11oy_harvest_endpoints.py ./
|
| 151 |
# energy operator/ledger/projection modules — imported by serve.py (guarded);
|
| 152 |
# MUST be per-file COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back to a STUB.
|
| 153 |
+
COPY joule_billing.py szl_energy_ledger.py szl_energy_operator.py szl_energy_projection.py szl_cheapest_watt.py ./
|
| 154 |
# K-Verify governed-inference benchmark — imported by serve.py (guarded). MUST be
|
| 155 |
# per-file COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back and
|
| 156 |
# /api/a11oy/v1/kverify/* 404s. Reuses szl_energy_operator (inference + NVML joules)
|
szl_cheapest_watt.py
ADDED
|
@@ -0,0 +1,528 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""szl_cheapest_watt.py — SZL Energy: carbon/cost-aware "cheapest-watt" placement policy.
|
| 2 |
+
|
| 3 |
+
WHAT THIS IS (and is NOT)
|
| 4 |
+
-------------------------
|
| 5 |
+
This is PLACEMENT + ACCOUNTING, NOT fused VRAM. Given the reachable sovereign nodes,
|
| 6 |
+
their MEASURED per-node energy intensity (joules-per-token), and the LIVE grid price
|
| 7 |
+
(€/MWh) at decision time, it picks the ONE node that minimizes energy-cost-per-token
|
| 8 |
+
and records the placement decision into a signed, hash-chained receipt. Each separate
|
| 9 |
+
worker keeps its own metered joules — nothing is ever merged/fused across the network.
|
| 10 |
+
|
| 11 |
+
It does NOT execute inference; it reads what the live energy operator already MEASURED
|
| 12 |
+
(per-node joules + tokens + power_w + live grid price) and turns that into an honest,
|
| 13 |
+
re-hashable placement decision plus a cumulative MEASURED-savings tally. The mesh
|
| 14 |
+
coordinator's least-connections balancer still does the actual proxying; this is the
|
| 15 |
+
cost/carbon lens that, when wired in, can re-order candidates by cheapest watt.
|
| 16 |
+
|
| 17 |
+
HONESTY GATES (Doctrine v11 — never weakened here)
|
| 18 |
+
--------------------------------------------------
|
| 19 |
+
* NEVER fabricate a grid price or a saving. A node only has an energy-intensity
|
| 20 |
+
(J/token) when its OWN per-node MEASURED joules and tokens are both > 0 this read.
|
| 21 |
+
A node whose joules are PENDING_EXPORTER / 0 has UNKNOWN intensity and is NOT
|
| 22 |
+
ranked on cost (it is reported, honestly, as "intensity unknown — pending exporter").
|
| 23 |
+
* If fewer than TWO nodes have a comparable MEASURED intensity, there is NO real
|
| 24 |
+
placement choice: we report decision="no_choice" with reason "no placement choice
|
| 25 |
+
this tick" — we never invent an alternative to claim a saving against.
|
| 26 |
+
* The grid price is passed through from the live meter verbatim (€/MWh). If it is
|
| 27 |
+
missing, the per-token COST is UNKNOWN (intensity is still MEASURED) and the cost
|
| 28 |
+
delta is labeled accordingly — we never assume a price.
|
| 29 |
+
* SAVINGS LABELLING: a saving is the cost delta between the CHOSEN node and a NAMED
|
| 30 |
+
baseline. It is MEASURED only when BOTH legs are MEASURED (both nodes' J/token from
|
| 31 |
+
real per-node NVML deltas AND a live grid price). The default baseline is the
|
| 32 |
+
*most-expensive comparable node this tick* (a real alternative we declined) — that
|
| 33 |
+
leg is MEASURED, so the delta is MEASURED. Any baseline that is itself MODELED or
|
| 34 |
+
assumed (e.g. a cloud-grid reference intensity) yields an ESTIMATE saving, never
|
| 35 |
+
MEASURED. We label every saving with exactly one of {MEASURED, ESTIMATE}.
|
| 36 |
+
* Receipts are re-hashable offline (sha256_canon over the canonical decision) and
|
| 37 |
+
hash-chained (prev_digest; genesis = 64 zeros). DSSE signing is layered on by the
|
| 38 |
+
caller when a real cosign key is present; absent a key the receipt is honest-but-
|
| 39 |
+
UNSIGNED, never faked.
|
| 40 |
+
* sovereign=false on this accounting path; Λ = Conjecture 1; trust never 100%.
|
| 41 |
+
|
| 42 |
+
Pure stdlib (hashlib + json). No third-party deps, no network — the caller hands in
|
| 43 |
+
the operator-status dict it already fetched. Offline self-test at the bottom.
|
| 44 |
+
"""
|
| 45 |
+
|
| 46 |
+
from __future__ import annotations
|
| 47 |
+
|
| 48 |
+
import hashlib
|
| 49 |
+
import json
|
| 50 |
+
import threading
|
| 51 |
+
import time
|
| 52 |
+
from dataclasses import dataclass, field
|
| 53 |
+
from typing import Any, Dict, List, Optional, Tuple
|
| 54 |
+
|
| 55 |
+
# ---------------------------------------------------------------------------
|
| 56 |
+
# Constants. We mirror joule_billing's canonical hashing when that module is
|
| 57 |
+
# importable (single source of the receipt-hash math); otherwise a byte-identical
|
| 58 |
+
# local fallback so this module also runs fully standalone / offline in tests.
|
| 59 |
+
# ---------------------------------------------------------------------------
|
| 60 |
+
JOULES_PER_KWH = 3_600_000.0
|
| 61 |
+
GENESIS_PREV = "0" * 64
|
| 62 |
+
|
| 63 |
+
LABEL_MEASURED = "MEASURED"
|
| 64 |
+
LABEL_ESTIMATE = "ESTIMATE"
|
| 65 |
+
LABEL_UNKNOWN = "UNKNOWN"
|
| 66 |
+
|
| 67 |
+
DOCTRINE = (
|
| 68 |
+
"Doctrine v11: cheapest-watt PLACEMENT + accounting, NOT fused VRAM. Each node keeps "
|
| 69 |
+
"its own MEASURED joules; nothing merged. Energy-intensity (J/token) is MEASURED only "
|
| 70 |
+
"from a node's own per-node NVML joule delta and tokens (both >0); else intensity is "
|
| 71 |
+
"UNKNOWN and the node is never ranked on cost. Grid price (€/MWh) is the live meter "
|
| 72 |
+
"value passed through verbatim, never assumed. A saving is MEASURED only when BOTH the "
|
| 73 |
+
"chosen leg and the named baseline leg are MEASURED (real per-node J/token + live price); "
|
| 74 |
+
"any modeled/assumed baseline => ESTIMATE. With <2 comparable MEASURED nodes there is no "
|
| 75 |
+
"placement choice this tick (decision=no_choice) — we never invent an alternative. Never "
|
| 76 |
+
"fabricate a price or a saving. Receipts re-hashable offline + hash-chained "
|
| 77 |
+
"(prev_digest). sovereign=false; Λ=Conjecture 1; trust never 100%."
|
| 78 |
+
)
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def sha256_canon(obj: dict) -> str:
|
| 82 |
+
"""Canonical sha256 over a dict (sorted keys, tight separators). Prefers
|
| 83 |
+
joule_billing.sha256_canon so the hash math is the SAME single source the
|
| 84 |
+
JouleCharge receipts use; falls back to a byte-identical local impl."""
|
| 85 |
+
try:
|
| 86 |
+
from joule_billing import sha256_canon as _sc # type: ignore
|
| 87 |
+
return _sc(obj)
|
| 88 |
+
except Exception:
|
| 89 |
+
return "sha256:" + hashlib.sha256(
|
| 90 |
+
json.dumps(obj, sort_keys=True, separators=(",", ":")).encode()
|
| 91 |
+
).hexdigest()
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
# ---------------------------------------------------------------------------
|
| 95 |
+
# Candidate model. One candidate = one reachable, COMPUTING sovereign node with
|
| 96 |
+
# its own metered energy this read. We read per-node joules + tokens from the
|
| 97 |
+
# operator's by_node block (MEASURED-only) and power_w from status when present.
|
| 98 |
+
# ---------------------------------------------------------------------------
|
| 99 |
+
@dataclass
|
| 100 |
+
class Candidate:
|
| 101 |
+
name: str
|
| 102 |
+
sovereign: bool
|
| 103 |
+
joules_label: str # MEASURED | PENDING_EXPORTER | NONE (from operator by_node)
|
| 104 |
+
joules_measured: float # node's own cumulative MEASURED joules (billable)
|
| 105 |
+
tokens: int # node's own cumulative tokens
|
| 106 |
+
power_w: Optional[float] = None # latest live exporter power_w for this node, if known
|
| 107 |
+
|
| 108 |
+
# derived (filled by the policy)
|
| 109 |
+
joules_per_token: Optional[float] = None # MEASURED intensity, or None if UNKNOWN
|
| 110 |
+
intensity_label: str = LABEL_UNKNOWN
|
| 111 |
+
eur_per_token: Optional[float] = None # cost = J/token /3.6e9 *kWh * €/MWh, or None
|
| 112 |
+
note: str = ""
|
| 113 |
+
|
| 114 |
+
def to_dict(self) -> dict:
|
| 115 |
+
return {
|
| 116 |
+
"node": self.name,
|
| 117 |
+
"sovereign": self.sovereign,
|
| 118 |
+
"joules_label": self.joules_label,
|
| 119 |
+
"joules_measured": round(self.joules_measured, 6),
|
| 120 |
+
"tokens": self.tokens,
|
| 121 |
+
"power_w": self.power_w,
|
| 122 |
+
"joules_per_token": (round(self.joules_per_token, 9)
|
| 123 |
+
if self.joules_per_token is not None else None),
|
| 124 |
+
"intensity_label": self.intensity_label,
|
| 125 |
+
"eur_per_token": (None if self.eur_per_token is None
|
| 126 |
+
else float(f"{self.eur_per_token:.6e}")),
|
| 127 |
+
"note": self.note,
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
|
| 131 |
+
def _candidates_from_status(status: Dict[str, Any]) -> List[Candidate]:
|
| 132 |
+
"""Build candidates from a live energy-operator status dict (the SAME shape
|
| 133 |
+
/api/a11oy/v1/energy/operator/status returns). Only nodes that are COMPUTING
|
| 134 |
+
this read are candidates (a standby/DEGRADED node never serves, so it is never
|
| 135 |
+
a placement target). Per-node energy comes from status['by_node'] verbatim —
|
| 136 |
+
MEASURED only; PENDING/NONE => intensity UNKNOWN, never fabricated."""
|
| 137 |
+
by_node = status.get("by_node") or {}
|
| 138 |
+
computing = set(status.get("nodes_computing") or [])
|
| 139 |
+
# power_w_sample is the most-recent live exporter watt reading (single source in
|
| 140 |
+
# this status shape). We attach it to the MEASURED node it belongs to (the one
|
| 141 |
+
# whose joules are MEASURED) — never spread to a node we have no reading for.
|
| 142 |
+
power_w = status.get("power_w_sample")
|
| 143 |
+
exporter_measured_node = None
|
| 144 |
+
for name, b in by_node.items():
|
| 145 |
+
if (b or {}).get("joules_label") == LABEL_MEASURED:
|
| 146 |
+
exporter_measured_node = name
|
| 147 |
+
break
|
| 148 |
+
cands: List[Candidate] = []
|
| 149 |
+
for name, b in by_node.items():
|
| 150 |
+
if name not in computing:
|
| 151 |
+
continue # only nodes actually computing this read can be chosen
|
| 152 |
+
b = b or {}
|
| 153 |
+
cands.append(Candidate(
|
| 154 |
+
name=name,
|
| 155 |
+
sovereign=True, # only owned-metal sovereign workers reach by_node compute
|
| 156 |
+
joules_label=str(b.get("joules_label") or "NONE"),
|
| 157 |
+
joules_measured=float(b.get("joules_measured") or 0.0),
|
| 158 |
+
tokens=int(b.get("tokens") or 0),
|
| 159 |
+
power_w=(float(power_w) if (power_w is not None
|
| 160 |
+
and name == exporter_measured_node) else None),
|
| 161 |
+
))
|
| 162 |
+
return cands
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
# ---------------------------------------------------------------------------
|
| 166 |
+
# The policy. Compute MEASURED J/token per candidate, then €/token from the live
|
| 167 |
+
# grid price, then pick the cheapest. Build an honest decision + receipt.
|
| 168 |
+
# ---------------------------------------------------------------------------
|
| 169 |
+
def _eur_per_token(joules_per_token: Optional[float],
|
| 170 |
+
grid_price_eur_mwh: Optional[float]) -> Optional[float]:
|
| 171 |
+
"""€/token = (J/token / 3.6e9 J/kWh) * (€/MWh / 1000 kWh/MWh).
|
| 172 |
+
Returns None (UNKNOWN) when intensity or price is missing — never assumed."""
|
| 173 |
+
if joules_per_token is None or grid_price_eur_mwh is None:
|
| 174 |
+
return None
|
| 175 |
+
kwh_per_token = joules_per_token / JOULES_PER_KWH
|
| 176 |
+
eur_per_kwh = float(grid_price_eur_mwh) / 1000.0
|
| 177 |
+
return kwh_per_token * eur_per_kwh
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
def evaluate(status: Dict[str, Any],
|
| 181 |
+
baseline: str = "most_expensive_comparable",
|
| 182 |
+
prev_digest: str = GENESIS_PREV,
|
| 183 |
+
now_ts: Optional[float] = None) -> Dict[str, Any]:
|
| 184 |
+
"""Run ONE cheapest-watt placement evaluation against a live operator status.
|
| 185 |
+
|
| 186 |
+
Returns an honest decision dict carrying a re-hashable receipt. NEVER fabricates
|
| 187 |
+
a price or a saving. With <2 comparable MEASURED-intensity nodes it returns
|
| 188 |
+
decision='no_choice' (reason 'no placement choice this tick').
|
| 189 |
+
"""
|
| 190 |
+
now_ts = time.time() if now_ts is None else now_ts
|
| 191 |
+
ts_iso = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime(now_ts))
|
| 192 |
+
grid = status.get("grid_price_eur_mwh")
|
| 193 |
+
grid = float(grid) if isinstance(grid, (int, float)) else None
|
| 194 |
+
|
| 195 |
+
cands = _candidates_from_status(status)
|
| 196 |
+
# Derive MEASURED intensity + cost for each candidate.
|
| 197 |
+
for c in cands:
|
| 198 |
+
if c.joules_label == LABEL_MEASURED and c.joules_measured > 0 and c.tokens > 0:
|
| 199 |
+
c.joules_per_token = c.joules_measured / c.tokens
|
| 200 |
+
c.intensity_label = LABEL_MEASURED
|
| 201 |
+
c.eur_per_token = _eur_per_token(c.joules_per_token, grid)
|
| 202 |
+
c.note = "MEASURED J/token from this node's own NVML joule delta / its tokens"
|
| 203 |
+
else:
|
| 204 |
+
c.joules_per_token = None
|
| 205 |
+
c.intensity_label = LABEL_UNKNOWN
|
| 206 |
+
c.eur_per_token = None
|
| 207 |
+
c.note = ("intensity unknown — node computed but per-node MEASURED joules "
|
| 208 |
+
"are pending (%s); never ranked on cost, never fabricated"
|
| 209 |
+
% (c.joules_label,))
|
| 210 |
+
|
| 211 |
+
comparable = [c for c in cands if c.intensity_label == LABEL_MEASURED]
|
| 212 |
+
|
| 213 |
+
base_decision: Dict[str, Any] = {
|
| 214 |
+
"receipt_type": "SZL.Energy.CheapestWattPlacement.v1",
|
| 215 |
+
"ts": ts_iso,
|
| 216 |
+
"grid_price_eur_mwh": grid,
|
| 217 |
+
"grid_price_label": (LABEL_MEASURED if grid is not None else LABEL_UNKNOWN),
|
| 218 |
+
"grid_price_note": ("live meter value at decision time, passed through verbatim"
|
| 219 |
+
if grid is not None else
|
| 220 |
+
"no live grid price this read — cost is UNKNOWN, never assumed"),
|
| 221 |
+
"baseline_policy": baseline,
|
| 222 |
+
"candidates": [c.to_dict() for c in cands],
|
| 223 |
+
"reachable_computing_count": len(cands),
|
| 224 |
+
"comparable_measured_count": len(comparable),
|
| 225 |
+
"honesty": {
|
| 226 |
+
"sovereign": False,
|
| 227 |
+
"lambda": "Conjecture 1",
|
| 228 |
+
"trust": "never 100%",
|
| 229 |
+
"placement": "horizontal cost/carbon-aware placement; VRAM NOT fused",
|
| 230 |
+
"fabrication": "no price or saving is ever fabricated",
|
| 231 |
+
},
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
if len(comparable) < 2:
|
| 235 |
+
decision = dict(base_decision)
|
| 236 |
+
decision.update({
|
| 237 |
+
"decision": "no_choice",
|
| 238 |
+
"chosen_node": None,
|
| 239 |
+
"reason": "no placement choice this tick",
|
| 240 |
+
"detail": (
|
| 241 |
+
"fewer than two nodes have a comparable MEASURED energy-intensity "
|
| 242 |
+
"this read (%d computing, %d MEASURED-intensity); with no real "
|
| 243 |
+
"alternative we decline to claim a saving — never fabricated."
|
| 244 |
+
% (len(cands), len(comparable))
|
| 245 |
+
),
|
| 246 |
+
"saving": None,
|
| 247 |
+
"saving_label": None,
|
| 248 |
+
})
|
| 249 |
+
return _finalize(decision, prev_digest)
|
| 250 |
+
|
| 251 |
+
# Rank comparable nodes by €/token when a price exists; else by J/token (still a
|
| 252 |
+
# real, MEASURED energy ranking — labeled as energy-only, no monetary claim).
|
| 253 |
+
if grid is not None:
|
| 254 |
+
ranked = sorted(comparable, key=lambda c: c.eur_per_token) # type: ignore[arg-type]
|
| 255 |
+
metric = "eur_per_token"
|
| 256 |
+
else:
|
| 257 |
+
ranked = sorted(comparable, key=lambda c: c.joules_per_token) # type: ignore[arg-type]
|
| 258 |
+
metric = "joules_per_token"
|
| 259 |
+
|
| 260 |
+
chosen = ranked[0]
|
| 261 |
+
# Named baseline = the most-expensive comparable node we DECLINED this tick.
|
| 262 |
+
# That is a REAL alternative leg with MEASURED intensity -> the delta is MEASURED
|
| 263 |
+
# (when a live price also exists; otherwise it is a MEASURED energy delta, and any
|
| 264 |
+
# monetary framing would be ESTIMATE).
|
| 265 |
+
baseline_node = ranked[-1]
|
| 266 |
+
|
| 267 |
+
if metric == "eur_per_token":
|
| 268 |
+
chosen_cost = chosen.eur_per_token
|
| 269 |
+
base_cost = baseline_node.eur_per_token
|
| 270 |
+
delta = base_cost - chosen_cost # €/token saved vs the declined alternative
|
| 271 |
+
# BOTH legs MEASURED (real per-node J/token) AND a live price => MEASURED saving.
|
| 272 |
+
saving_label = LABEL_MEASURED
|
| 273 |
+
saving = {
|
| 274 |
+
"metric": "eur_per_token",
|
| 275 |
+
"chosen_eur_per_token": float(f"{chosen_cost:.6e}"),
|
| 276 |
+
"baseline_eur_per_token": float(f"{base_cost:.6e}"),
|
| 277 |
+
"delta_eur_per_token": float(f"{delta:.6e}"),
|
| 278 |
+
"delta_pct": (round(100.0 * delta / base_cost, 4) if base_cost else None),
|
| 279 |
+
"baseline_node": baseline_node.name,
|
| 280 |
+
"note": (
|
| 281 |
+
"MEASURED: both legs are real per-node NVML J/token AND the grid price "
|
| 282 |
+
"is the live meter value; delta is vs the most-expensive comparable node "
|
| 283 |
+
"we declined this tick (a real alternative), not a hypothetical baseline."
|
| 284 |
+
),
|
| 285 |
+
}
|
| 286 |
+
else:
|
| 287 |
+
# No live price: we can only state the MEASURED energy delta; any euro figure
|
| 288 |
+
# would require a price we do not have, so we DO NOT emit one (ESTIMATE-or-none).
|
| 289 |
+
chosen_j = chosen.joules_per_token
|
| 290 |
+
base_j = baseline_node.joules_per_token
|
| 291 |
+
jdelta = base_j - chosen_j
|
| 292 |
+
saving_label = LABEL_ESTIMATE # monetary saving cannot be MEASURED w/o a price
|
| 293 |
+
saving = {
|
| 294 |
+
"metric": "joules_per_token",
|
| 295 |
+
"chosen_joules_per_token": round(chosen_j, 9),
|
| 296 |
+
"baseline_joules_per_token": round(base_j, 9),
|
| 297 |
+
"delta_joules_per_token": round(jdelta, 9),
|
| 298 |
+
"delta_pct": (round(100.0 * jdelta / base_j, 4) if base_j else None),
|
| 299 |
+
"baseline_node": baseline_node.name,
|
| 300 |
+
"note": (
|
| 301 |
+
"ESTIMATE (monetary): energy delta is MEASURED (real per-node J/token), "
|
| 302 |
+
"but NO live grid price this read, so a euro saving cannot be MEASURED — "
|
| 303 |
+
"we report the MEASURED joules delta only and never assume a price."
|
| 304 |
+
),
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
decision = dict(base_decision)
|
| 308 |
+
decision.update({
|
| 309 |
+
"decision": "placed",
|
| 310 |
+
"chosen_node": chosen.name,
|
| 311 |
+
"rank_metric": metric,
|
| 312 |
+
"reason": ("chosen node minimizes %s among comparable MEASURED-intensity "
|
| 313 |
+
"sovereign nodes this tick" % metric),
|
| 314 |
+
"ranking": [c.name for c in ranked],
|
| 315 |
+
"saving": saving,
|
| 316 |
+
"saving_label": saving_label,
|
| 317 |
+
})
|
| 318 |
+
return _finalize(decision, prev_digest)
|
| 319 |
+
|
| 320 |
+
|
| 321 |
+
def _finalize(decision: Dict[str, Any], prev_digest: str) -> Dict[str, Any]:
|
| 322 |
+
"""Attach the re-hashable payload_digest and the chain prev_digest. The
|
| 323 |
+
entry_digest binds (prev_digest, payload_digest) the same way the energy ledger
|
| 324 |
+
binds its entries, so a cheapest-watt receipt slots into the same chain shape."""
|
| 325 |
+
payload_digest = sha256_canon(decision)
|
| 326 |
+
entry_digest = sha256_canon({"prev_digest": prev_digest,
|
| 327 |
+
"payload_digest": payload_digest})
|
| 328 |
+
return {
|
| 329 |
+
"decision": decision,
|
| 330 |
+
"payload_digest": payload_digest,
|
| 331 |
+
"prev_digest": prev_digest,
|
| 332 |
+
"entry_digest": entry_digest,
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
|
| 336 |
+
# ---------------------------------------------------------------------------
|
| 337 |
+
# CheapestWattLedger — a small, in-process, hash-chained tally of placement
|
| 338 |
+
# decisions + cumulative MEASURED savings. Thread-safe; bounded recent tail.
|
| 339 |
+
# It NEVER persists a key and NEVER fabricates — it only records what evaluate()
|
| 340 |
+
# returned. Cumulative MEASURED savings sum ONLY the receipts whose saving_label
|
| 341 |
+
# is MEASURED (both legs real). ESTIMATE/none savings are tallied separately.
|
| 342 |
+
# ---------------------------------------------------------------------------
|
| 343 |
+
class CheapestWattLedger:
|
| 344 |
+
def __init__(self, max_tail: int = 50) -> None:
|
| 345 |
+
self._lock = threading.RLock()
|
| 346 |
+
self._head = GENESIS_PREV
|
| 347 |
+
self._count = 0
|
| 348 |
+
self._placed = 0
|
| 349 |
+
self._no_choice = 0
|
| 350 |
+
self._cum_measured_eur_per_token_saved = 0.0 # sum of MEASURED €/token deltas
|
| 351 |
+
self._measured_saving_receipts = 0
|
| 352 |
+
self._estimate_saving_receipts = 0
|
| 353 |
+
self._recent: List[Dict[str, Any]] = []
|
| 354 |
+
|
| 355 |
+
def record(self, status: Dict[str, Any],
|
| 356 |
+
baseline: str = "most_expensive_comparable") -> Dict[str, Any]:
|
| 357 |
+
"""Evaluate against a live status and append the resulting receipt to the
|
| 358 |
+
chain. Returns the receipt. MEASURED savings accumulate ONLY from receipts
|
| 359 |
+
whose saving_label==MEASURED — honest by construction."""
|
| 360 |
+
with self._lock:
|
| 361 |
+
receipt = evaluate(status, baseline=baseline, prev_digest=self._head)
|
| 362 |
+
self._head = receipt["entry_digest"]
|
| 363 |
+
self._count += 1
|
| 364 |
+
d = receipt["decision"]
|
| 365 |
+
if d["decision"] == "placed":
|
| 366 |
+
self._placed += 1
|
| 367 |
+
lab = d.get("saving_label")
|
| 368 |
+
sv = d.get("saving") or {}
|
| 369 |
+
if lab == LABEL_MEASURED and "delta_eur_per_token" in sv:
|
| 370 |
+
self._cum_measured_eur_per_token_saved += float(sv["delta_eur_per_token"])
|
| 371 |
+
self._measured_saving_receipts += 1
|
| 372 |
+
elif lab == LABEL_ESTIMATE:
|
| 373 |
+
self._estimate_saving_receipts += 1
|
| 374 |
+
else:
|
| 375 |
+
self._no_choice += 1
|
| 376 |
+
self._recent.append(receipt)
|
| 377 |
+
if len(self._recent) > 50:
|
| 378 |
+
self._recent.pop(0)
|
| 379 |
+
return receipt
|
| 380 |
+
|
| 381 |
+
def verify(self) -> Tuple[bool, int, int]:
|
| 382 |
+
"""Re-walk the chain offline: each receipt re-hashes to its payload_digest
|
| 383 |
+
AND its entry_digest binds (prev_digest, payload_digest); each prev links to
|
| 384 |
+
the previous entry_digest. Returns (ok, length, first_break_index)."""
|
| 385 |
+
with self._lock:
|
| 386 |
+
prev = GENESIS_PREV
|
| 387 |
+
for i, r in enumerate(self._recent):
|
| 388 |
+
pd = sha256_canon(r["decision"])
|
| 389 |
+
ed = sha256_canon({"prev_digest": r["prev_digest"],
|
| 390 |
+
"payload_digest": pd})
|
| 391 |
+
if (pd != r["payload_digest"] or ed != r["entry_digest"]
|
| 392 |
+
or r["prev_digest"] != prev):
|
| 393 |
+
return (False, len(self._recent), i)
|
| 394 |
+
prev = r["entry_digest"]
|
| 395 |
+
return (True, len(self._recent), -1)
|
| 396 |
+
|
| 397 |
+
def status(self) -> Dict[str, Any]:
|
| 398 |
+
with self._lock:
|
| 399 |
+
ok, length, brk = self.verify()
|
| 400 |
+
return {
|
| 401 |
+
"service": "cheapest-watt-placement",
|
| 402 |
+
"kind": "carbon/cost-aware placement + accounting (NOT fused VRAM)",
|
| 403 |
+
"decisions_total": self._count,
|
| 404 |
+
"placed": self._placed,
|
| 405 |
+
"no_choice": self._no_choice,
|
| 406 |
+
"cumulative_measured_eur_per_token_saved":
|
| 407 |
+
float(f"{self._cum_measured_eur_per_token_saved:.9e}")
|
| 408 |
+
if self._cum_measured_eur_per_token_saved else 0.0,
|
| 409 |
+
"cumulative_measured_saving_label": LABEL_MEASURED,
|
| 410 |
+
"measured_saving_receipts": self._measured_saving_receipts,
|
| 411 |
+
"estimate_saving_receipts": self._estimate_saving_receipts,
|
| 412 |
+
"chain": {
|
| 413 |
+
"head": self._head,
|
| 414 |
+
"length": length,
|
| 415 |
+
"ok": ok,
|
| 416 |
+
"first_break_index": brk,
|
| 417 |
+
"genesis_prev": GENESIS_PREV,
|
| 418 |
+
},
|
| 419 |
+
"recent_decisions": [r["decision"] for r in self._recent[-10:]],
|
| 420 |
+
"doctrine": DOCTRINE,
|
| 421 |
+
"honesty": (
|
| 422 |
+
"cumulative_measured_eur_per_token_saved sums ONLY receipts whose "
|
| 423 |
+
"saving_label==MEASURED (both the chosen leg and the named declined-"
|
| 424 |
+
"alternative leg are real per-node MEASURED J/token AND a live grid "
|
| 425 |
+
"price). ESTIMATE savings (e.g. no live price this read) are counted "
|
| 426 |
+
"separately and never folded into the MEASURED total. no_choice ticks "
|
| 427 |
+
"(<2 comparable MEASURED nodes) claim NO saving. Never fabricated."
|
| 428 |
+
),
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
|
| 432 |
+
# Module-level singleton the endpoint drives (one tally per process).
|
| 433 |
+
_LEDGER: Optional[CheapestWattLedger] = None
|
| 434 |
+
_LEDGER_LOCK = threading.Lock()
|
| 435 |
+
|
| 436 |
+
|
| 437 |
+
def get_ledger() -> CheapestWattLedger:
|
| 438 |
+
global _LEDGER
|
| 439 |
+
with _LEDGER_LOCK:
|
| 440 |
+
if _LEDGER is None:
|
| 441 |
+
_LEDGER = CheapestWattLedger()
|
| 442 |
+
return _LEDGER
|
| 443 |
+
|
| 444 |
+
|
| 445 |
+
# ---------------------------------------------------------------------------
|
| 446 |
+
# Offline self-test — proves the honesty gates with NO live GPU and NO network.
|
| 447 |
+
# ---------------------------------------------------------------------------
|
| 448 |
+
def _selftest() -> dict:
|
| 449 |
+
out: dict = {}
|
| 450 |
+
|
| 451 |
+
# (a) Two comparable MEASURED nodes + a live price => MEASURED saving, cheaper wins.
|
| 452 |
+
status_two = {
|
| 453 |
+
"grid_price_eur_mwh": 111.24,
|
| 454 |
+
"power_w_sample": 13.02,
|
| 455 |
+
"nodes_computing": ["rtx-betterwithage", "chaski"],
|
| 456 |
+
"by_node": {
|
| 457 |
+
"rtx-betterwithage": {"joules_label": "MEASURED",
|
| 458 |
+
"joules_measured": 910844.34, "tokens": 12002478},
|
| 459 |
+
# synthetic 2nd MEASURED node for the gate (more J/token = pricier)
|
| 460 |
+
"chaski": {"joules_label": "MEASURED",
|
| 461 |
+
"joules_measured": 200000.0, "tokens": 1024134},
|
| 462 |
+
},
|
| 463 |
+
}
|
| 464 |
+
r = evaluate(status_two)
|
| 465 |
+
d = r["decision"]
|
| 466 |
+
assert d["decision"] == "placed", d
|
| 467 |
+
assert d["saving_label"] == "MEASURED", d
|
| 468 |
+
# cheaper = lower J/token. rtx: ~0.0759 J/tok ; chaski: ~0.1953 J/tok -> rtx chosen
|
| 469 |
+
assert d["chosen_node"] == "rtx-betterwithage", d["chosen_node"]
|
| 470 |
+
assert d["saving"]["delta_eur_per_token"] > 0, d["saving"]
|
| 471 |
+
# receipt re-hashes offline
|
| 472 |
+
assert sha256_canon(d) == r["payload_digest"]
|
| 473 |
+
out["two_measured_live_price_measured_saving"] = True
|
| 474 |
+
|
| 475 |
+
# (b) Only ONE comparable MEASURED node (chaski PENDING) => no placement choice.
|
| 476 |
+
status_one = {
|
| 477 |
+
"grid_price_eur_mwh": 111.24,
|
| 478 |
+
"power_w_sample": 13.02,
|
| 479 |
+
"nodes_computing": ["rtx-betterwithage", "chaski"],
|
| 480 |
+
"by_node": {
|
| 481 |
+
"rtx-betterwithage": {"joules_label": "MEASURED",
|
| 482 |
+
"joules_measured": 910844.34, "tokens": 12002478},
|
| 483 |
+
"chaski": {"joules_label": "PENDING_EXPORTER",
|
| 484 |
+
"joules_measured": 0.0, "tokens": 1024134},
|
| 485 |
+
},
|
| 486 |
+
}
|
| 487 |
+
r1 = evaluate(status_one)
|
| 488 |
+
assert r1["decision"]["decision"] == "no_choice", r1["decision"]
|
| 489 |
+
assert r1["decision"]["reason"] == "no placement choice this tick"
|
| 490 |
+
assert r1["decision"]["saving"] is None
|
| 491 |
+
out["one_node_no_choice"] = True
|
| 492 |
+
|
| 493 |
+
# (c) Two MEASURED nodes but NO live price => energy-only ranking, ESTIMATE saving.
|
| 494 |
+
status_noprice = dict(status_two)
|
| 495 |
+
status_noprice = {**status_two, "grid_price_eur_mwh": None}
|
| 496 |
+
r2 = evaluate(status_noprice)
|
| 497 |
+
d2 = r2["decision"]
|
| 498 |
+
assert d2["decision"] == "placed" and d2["rank_metric"] == "joules_per_token", d2
|
| 499 |
+
assert d2["saving_label"] == "ESTIMATE", d2 # no price => monetary saving not MEASURED
|
| 500 |
+
assert "delta_eur_per_token" not in (d2["saving"] or {}), d2["saving"]
|
| 501 |
+
out["no_price_estimate_saving_no_fabricated_euro"] = True
|
| 502 |
+
|
| 503 |
+
# (d) Ledger: MEASURED savings accumulate ONLY from MEASURED receipts; chain verifies.
|
| 504 |
+
led = CheapestWattLedger()
|
| 505 |
+
led.record(status_two) # MEASURED saving
|
| 506 |
+
led.record(status_one) # no_choice (no saving)
|
| 507 |
+
led.record(status_noprice) # ESTIMATE saving (not folded into MEASURED total)
|
| 508 |
+
st = led.status()
|
| 509 |
+
assert st["decisions_total"] == 3 and st["placed"] == 2 and st["no_choice"] == 1, st
|
| 510 |
+
assert st["measured_saving_receipts"] == 1, st
|
| 511 |
+
assert st["estimate_saving_receipts"] == 1, st
|
| 512 |
+
assert st["cumulative_measured_eur_per_token_saved"] > 0, st
|
| 513 |
+
assert st["chain"]["ok"] is True and st["chain"]["length"] == 3, st["chain"]
|
| 514 |
+
out["ledger_measured_only_accumulation_and_chain_ok"] = True
|
| 515 |
+
|
| 516 |
+
return out
|
| 517 |
+
|
| 518 |
+
|
| 519 |
+
if __name__ == "__main__":
|
| 520 |
+
import sys as _sys
|
| 521 |
+
print("=" * 70)
|
| 522 |
+
print("szl_cheapest_watt — self-test (honesty gates, no live GPU, no network)")
|
| 523 |
+
print("=" * 70)
|
| 524 |
+
res = _selftest()
|
| 525 |
+
print(json.dumps(res, indent=2))
|
| 526 |
+
ok = all(res.values())
|
| 527 |
+
print("\nSELFTEST", "PASS" if ok else "FAIL")
|
| 528 |
+
_sys.exit(0 if ok else 1)
|