betterwithage commited on
Commit
4b34e75
·
verified ·
1 Parent(s): 988d619

chore(sync): mirror backend .py + Dockerfile to Space (hf-sync-backend)

Browse files

Automated backend sync from szl-holdings/a11oy main via hf-sync-backend.
Updated (differed from the Space): Dockerfile, serve.py, szl_energy_live.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.

Files changed (3) hide show
  1. Dockerfile +3 -0
  2. serve.py +16 -0
  3. szl_energy_live.py +593 -0
Dockerfile CHANGED
@@ -183,6 +183,9 @@ COPY szl_energy_budget.py szl_energy_sovereign.py szl_energy_provenance.py szl_h
183
  # energy operator/ledger/projection modules — imported by serve.py (guarded);
184
  # MUST be per-file COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back to a STUB.
185
  COPY joule_billing.py szl_energy_ledger.py szl_energy_operator.py szl_energy_projection.py szl_cheapest_watt.py ./
 
 
 
186
  # Orbital tier (MODELED roadmap) — imported by serve.py (guarded); MUST be per-file
187
  # COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back and
188
  # /api/a11oy/v1/orbital/{topology,projection} 404 live. szl_orbital_projection reuses
 
183
  # energy operator/ledger/projection modules — imported by serve.py (guarded);
184
  # MUST be per-file COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back to a STUB.
185
  COPY joule_billing.py szl_energy_ledger.py szl_energy_operator.py szl_energy_projection.py szl_cheapest_watt.py ./
186
+ # energy LIVE feed (szl_energy_live) — imported by serve.py (guarded); MUST be per-file
187
+ # COPY'd or /api/a11oy/v1/energy/{live,mesh,harvest} fall through to the SPA catch-all.
188
+ COPY szl_energy_live.py ./
189
  # Orbital tier (MODELED roadmap) — imported by serve.py (guarded); MUST be per-file
190
  # COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back and
191
  # /api/a11oy/v1/orbital/{topology,projection} 404 live. szl_orbital_projection reuses
serve.py CHANGED
@@ -311,6 +311,22 @@ try:
311
  except Exception as _szl_eb_e: # pragma: no cover
312
  print(f"[a11oy] Energy-budget receipt NOT registered: {_szl_eb_e!r}", file=__import__("sys").stderr)
313
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
  # ── Energy / Sovereign-Compute instrumentation (Lane C: sovereign-energy). Reads REAL
315
  # J/token + carbon + speculative-decode + KV-cache + router + carbon-schedule from the
316
  # on-box vLLM /metrics ONLY when the live sovereign probe shows gpu_reachable; otherwise
 
311
  except Exception as _szl_eb_e: # pragma: no cover
312
  print(f"[a11oy] Energy-budget receipt NOT registered: {_szl_eb_e!r}", file=__import__("sys").stderr)
313
 
314
+ # ── Proven Energy Engine — LIVE feed (energy-live). Binds the dashboards to REAL data:
315
+ # GET /api/a11oy/v1/energy/{live,mesh,harvest}. /live is a real-time NVML power+energy
316
+ # snapshot scraped from the SZL_GLM_METER Prometheus exporter (/metrics) with a SHORT 2s
317
+ # timeout + ~5s last-good cache (always fast, never hangs); joules are MEASURED only when
318
+ # the meter is reachable, else UNAVAILABLE with joules NOT fabricated. /mesh combines the
319
+ # in-process sovereign-mesh govern/health posture with per-node NVML watts/joules + a 0..1
320
+ # draw for the 3D view (honest empty-states). /harvest exposes the Bekenstein budget ledger
321
+ # as a time-ordered joules_est series (F19/TH6 gate) plus a CLEARLY-LABELED client-side
322
+ # tariff-window heuristic (NOT a live feed). Additive, try/except-guarded, before the SPA.
323
+ try:
324
+ import szl_energy_live as _szl_energy_live
325
+ _szl_energy_live.register(app, ns="a11oy")
326
+ print("[a11oy] Energy LIVE feed registered: /api/a11oy/v1/energy/{live,mesh,harvest}", file=__import__("sys").stderr)
327
+ except Exception as _szl_el_e: # pragma: no cover
328
+ print(f"[a11oy] Energy LIVE feed NOT registered: {_szl_el_e!r}", file=__import__("sys").stderr)
329
+
330
  # ── Energy / Sovereign-Compute instrumentation (Lane C: sovereign-energy). Reads REAL
331
  # J/token + carbon + speculative-decode + KV-cache + router + carbon-schedule from the
332
  # on-box vLLM /metrics ONLY when the live sovereign probe shows gpu_reachable; otherwise
szl_energy_live.py ADDED
@@ -0,0 +1,593 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """szl_energy_live.py — LIVE energy feed binding the dashboards to real hardware.
2
+
3
+ Three additive read endpoints under /api/<ns>/v1/energy that turn the Proven Energy
4
+ Engine from EMPTY/SAMPLE surfaces into a real-time feed wired to (a) the on-box NVML
5
+ power-meter exporter and (b) the in-process sovereign-mesh governance posture.
6
+
7
+ GET /api/<ns>/v1/energy/live real-time power+energy snapshot (NVML + mesh posture)
8
+ GET /api/<ns>/v1/energy/mesh per-node energy + governance posture for the 3D view
9
+ GET /api/<ns>/v1/energy/harvest Bekenstein budget series + a heuristic tariff window
10
+
11
+ DOCTRINE (v11 — NEVER violate):
12
+ - HONEST LABELS. joules read MEASURED only from a REAL, reachable NVML exporter;
13
+ when the meter is unreachable the label is UNAVAILABLE and joules is null with a
14
+ note that joules were NOT fabricated. We NEVER invent a number.
15
+ - The exporter is the SZL_GLM_METER NVML exporter (default https://meter2.a-11-oy.com),
16
+ scraped at GET /metrics in Prometheus exposition format (szl_gpu_power_watts{...},
17
+ szl_gpu_energy_joules{...}).
18
+ - The sovereign-mesh posture (which nodes are live/down) is read from the SAME mesh the
19
+ in-process govern/health surface uses (szl_governed_api.MESH + _engine_live), so /live
20
+ and /mesh never diverge from /api/<ns>/v1/govern/health.
21
+ - The tariff window in /harvest is a CLIENT-SIDE HEURISTIC from the server clock — it is
22
+ explicitly NOT a live tariff feed. NO free-energy / perpetual-motion claims anywhere.
23
+ - FAST + NEVER HANGS: the meter is fetched with httpx on a SHORT (2s) timeout and the last
24
+ good sample is cached ~5s; mesh liveness probes are bounded by a deadline. A slow or down
25
+ backend degrades to an honest UNAVAILABLE/empty state, never a hang and never a fake.
26
+
27
+ Pure stdlib + httpx (already a repo dep) + Starlette. No key, no Node, no CDN.
28
+ """
29
+ import os
30
+ import re
31
+ import threading
32
+ import time
33
+ import concurrent.futures
34
+ from datetime import datetime, timezone
35
+
36
+ from starlette.requests import Request
37
+ from starlette.routing import Route
38
+ from starlette.responses import JSONResponse
39
+
40
+ # Honest labels (mirror szl_governed_api / szl_joules_truth vocabulary).
41
+ LABEL_MEASURED = "MEASURED"
42
+ LABEL_UNAVAILABLE = "UNAVAILABLE"
43
+
44
+ # The NVML exporter URL — SAME env the governed-inference GLM engine meters off.
45
+ METER_URL = os.environ.get("SZL_GLM_METER", "https://meter2.a-11-oy.com").rstrip("/")
46
+ # Short timeout so a down/slow meter can never hang the endpoint.
47
+ METER_TIMEOUT_S = float(os.environ.get("SZL_ENERGY_LIVE_TIMEOUT_S", "2.0"))
48
+ # Cache the last good meter sample this long (fire-and-forget freshness window).
49
+ SNAPSHOT_TTL_S = float(os.environ.get("SZL_ENERGY_LIVE_TTL_S", "5.0"))
50
+ # Bounded deadline for the mesh-liveness probe so /live/mesh stay fast.
51
+ MESH_PROBE_DEADLINE_S = float(os.environ.get("SZL_ENERGY_LIVE_MESH_DEADLINE_S", "2.5"))
52
+
53
+ _UA = "Mozilla/5.0 (compatible; szl-energy-live/1.0; +https://a-11-oy.com)"
54
+
55
+ # Prometheus exposition line: metric{labels} value (comments/# lines ignored).
56
+ _PROM_LINE = re.compile(
57
+ r"^(?P<metric>szl_gpu_[a-zA-Z_]+)(?:\{(?P<labels>[^}]*)\})?\s+(?P<val>[-+0-9.eEnN]+)\s*$"
58
+ )
59
+ _PROM_LABEL = re.compile(r'([a-zA-Z_][a-zA-Z0-9_]*)="((?:[^"\\]|\\.)*)"')
60
+
61
+
62
+ def _now_iso() -> str:
63
+ return datetime.now(timezone.utc).isoformat()
64
+
65
+
66
+ # ---------------------------------------------------------------------------
67
+ # Prometheus parsing — szl_gpu_power_watts{gpu,name}, szl_gpu_energy_joules{...}.
68
+ # ---------------------------------------------------------------------------
69
+ def _parse_labels(raw: str) -> dict:
70
+ if not raw:
71
+ return {}
72
+ return {k: v for k, v in _PROM_LABEL.findall(raw)}
73
+
74
+
75
+ def _coerce_float(s: str):
76
+ try:
77
+ f = float(s)
78
+ except (TypeError, ValueError):
79
+ return None
80
+ if f != f or f in (float("inf"), float("-inf")): # NaN / inf are not readings
81
+ return None
82
+ return f
83
+
84
+
85
+ def parse_meter_metrics(text: str) -> dict:
86
+ """Parse Prometheus exposition text into per-GPU watts + cumulative joules.
87
+
88
+ Groups by the (gpu,name) label tuple. Returns {gpus:[{gpu,name,watts,joules}],
89
+ total_watts, total_joules}. A metric line without a recognized value is skipped
90
+ (never fabricated). Pure + deterministic."""
91
+ gpus: dict = {}
92
+ for line in text.splitlines():
93
+ line = line.strip()
94
+ if not line or line.startswith("#"):
95
+ continue
96
+ m = _PROM_LINE.match(line)
97
+ if not m:
98
+ continue
99
+ metric = m.group("metric")
100
+ if metric not in ("szl_gpu_power_watts", "szl_gpu_energy_joules"):
101
+ continue
102
+ val = _coerce_float(m.group("val"))
103
+ if val is None:
104
+ continue
105
+ labels = _parse_labels(m.group("labels") or "")
106
+ key = (labels.get("gpu", ""), labels.get("name", ""))
107
+ slot = gpus.setdefault(key, {"gpu": labels.get("gpu"), "name": labels.get("name"),
108
+ "watts": None, "joules": None})
109
+ if metric == "szl_gpu_power_watts":
110
+ slot["watts"] = val
111
+ else:
112
+ slot["joules"] = val
113
+ rows = list(gpus.values())
114
+ total_watts = sum(g["watts"] for g in rows if isinstance(g["watts"], (int, float)))
115
+ j_vals = [g["joules"] for g in rows if isinstance(g["joules"], (int, float))]
116
+ total_joules = sum(j_vals) if j_vals else None
117
+ return {
118
+ "gpus": rows,
119
+ "total_watts": round(total_watts, 6),
120
+ "total_joules": (round(total_joules, 6) if total_joules is not None else None),
121
+ }
122
+
123
+
124
+ # ---------------------------------------------------------------------------
125
+ # Meter fetch + ~5s last-good cache (fire-and-forget; never hangs > timeout).
126
+ # ---------------------------------------------------------------------------
127
+ _snap_lock = threading.Lock()
128
+ _snap_cache: dict = {"ts": 0.0, "data": None}
129
+
130
+
131
+ def _fetch_meter() -> dict:
132
+ """Fetch + parse {METER_URL}/metrics with a SHORT timeout. Honest result dict:
133
+ on success {reachable:True, status:'ok', **parsed}; on failure {reachable:False,
134
+ status:'offline:<reason>'|'http-<code>'} with no fabricated numbers."""
135
+ url = f"{METER_URL}/metrics"
136
+ try:
137
+ import httpx
138
+ except Exception as e: # pragma: no cover — httpx is a repo dep
139
+ return {"reachable": False, "status": f"offline:httpx-import:{type(e).__name__}"}
140
+ try:
141
+ with httpx.Client(timeout=METER_TIMEOUT_S, follow_redirects=True) as client:
142
+ resp = client.get(url, headers={"User-Agent": _UA})
143
+ code = resp.status_code
144
+ if code >= 400:
145
+ return {"reachable": False, "status": f"http-{code}"}
146
+ parsed = parse_meter_metrics(resp.text)
147
+ parsed.update({"reachable": True, "status": "ok"})
148
+ return parsed
149
+ except Exception as e: # noqa: BLE001 — unreachable/timeout meter => honest offline
150
+ return {"reachable": False, "status": f"offline:{type(e).__name__}"}
151
+
152
+
153
+ def meter_snapshot(force: bool = False) -> dict:
154
+ """Return the latest meter snapshot, served from the ~5s last-good cache when fresh.
155
+
156
+ Caches only REACHABLE samples; when the meter is down we report the live offline
157
+ status but keep the prior good sample available under 'stale' so callers can show a
158
+ last-known reading WITHOUT relabeling it MEASURED (it carries a stale flag)."""
159
+ now = time.time()
160
+ with _snap_lock:
161
+ cached = _snap_cache.get("data")
162
+ age = now - _snap_cache.get("ts", 0.0)
163
+ if not force and cached is not None and cached.get("reachable") and age <= SNAPSHOT_TTL_S:
164
+ out = dict(cached)
165
+ out["cache_age_s"] = round(age, 3)
166
+ return out
167
+ fresh = _fetch_meter()
168
+ with _snap_lock:
169
+ if fresh.get("reachable"):
170
+ _snap_cache["data"] = fresh
171
+ _snap_cache["ts"] = now
172
+ out = dict(fresh)
173
+ out["cache_age_s"] = 0.0
174
+ return out
175
+ # Meter down: surface the live offline status; attach last-good as stale (no relabel).
176
+ prior = _snap_cache.get("data")
177
+ out = dict(fresh)
178
+ if prior is not None:
179
+ out["stale"] = {**prior, "cache_age_s": round(now - _snap_cache.get("ts", 0.0), 3)}
180
+ return out
181
+
182
+
183
+ # ---------------------------------------------------------------------------
184
+ # Sovereign-mesh posture — read the SAME mesh govern/health uses, liveness bounded.
185
+ # ---------------------------------------------------------------------------
186
+ def _role_for_engine(eng: dict, index: int) -> str:
187
+ """Honest role label for the 3D view: glm | anchor | blackwell | engine-N."""
188
+ if eng.get("is_glm"):
189
+ return "glm"
190
+ name = (eng.get("name") or "").lower()
191
+ if "anchor" in name or "tower" in name:
192
+ return "anchor"
193
+ if "blackwell" in name or "laptop" in name:
194
+ return "blackwell"
195
+ return "anchor" if index == 0 else f"engine-{index}"
196
+
197
+
198
+ def _gpu_model_token(name: str):
199
+ """Extract a GPU model token (e.g. 'RTX 4060 Ti', 'RTX 5050') from a mesh engine
200
+ name so a meter GPU 'name' label can be honestly matched to a mesh node. None when
201
+ no recognizable model is present (then per-node watts/joules stay UNAVAILABLE)."""
202
+ if not name:
203
+ return None
204
+ m = re.search(r"RTX\s*\w+(?:\s+Ti)?", name, re.IGNORECASE)
205
+ return m.group(0).strip() if m else None
206
+
207
+
208
+ def govern_posture(deadline_s: float = MESH_PROBE_DEADLINE_S) -> dict:
209
+ """In-process sovereign-mesh posture (which nodes are live/down), bounded in time.
210
+
211
+ Uses szl_governed_api.MESH + _engine_live — the EXACT mesh + liveness definition the
212
+ /api/<ns>/v1/govern/health surface uses, so postures never diverge. Liveness probes
213
+ run concurrently under a hard deadline; a probe that does not finish in time reports
214
+ live=None (UNKNOWN — honestly not claimed up or down), never a fabricated state."""
215
+ try:
216
+ import szl_governed_api as G
217
+ except Exception as e: # noqa: BLE001 — governed surface optional; absence is honest
218
+ return {"available": False, "nodes": [], "reason": f"govern surface unavailable: {type(e).__name__}"}
219
+ mesh = list(getattr(G, "MESH", []) or [])
220
+ engine_live = getattr(G, "_engine_live", None)
221
+ nodes = []
222
+ live_by_idx: dict = {}
223
+ if callable(engine_live) and mesh:
224
+ with concurrent.futures.ThreadPoolExecutor(max_workers=len(mesh)) as ex:
225
+ futs = {ex.submit(_safe_engine_live, engine_live, e): i for i, e in enumerate(mesh)}
226
+ deadline = time.time() + max(0.1, deadline_s)
227
+ for fut, i in futs.items():
228
+ remaining = deadline - time.time()
229
+ try:
230
+ live_by_idx[i] = fut.result(timeout=max(0.0, remaining))
231
+ except Exception: # noqa: BLE001 — timeout/error => UNKNOWN, not a guess
232
+ live_by_idx[i] = None
233
+ for i, eng in enumerate(mesh):
234
+ nodes.append({
235
+ "name": eng.get("name"),
236
+ "role": _role_for_engine(eng, i),
237
+ "model": eng.get("model"),
238
+ "gpu_model": _gpu_model_token(eng.get("name") or ""),
239
+ "is_glm": bool(eng.get("is_glm")),
240
+ "live": live_by_idx.get(i),
241
+ })
242
+ return {
243
+ "available": True,
244
+ "nodes": nodes,
245
+ "live_count": sum(1 for n in nodes if n["live"] is True),
246
+ "total": len(nodes),
247
+ }
248
+
249
+
250
+ def _safe_engine_live(fn, eng) -> bool:
251
+ try:
252
+ return bool(fn(eng))
253
+ except Exception: # noqa: BLE001
254
+ return False
255
+
256
+
257
+ # ---------------------------------------------------------------------------
258
+ # /energy/live — real-time power+energy snapshot (NVML + mesh posture).
259
+ # ---------------------------------------------------------------------------
260
+ def build_live() -> dict:
261
+ snap = meter_snapshot()
262
+ reachable = bool(snap.get("reachable"))
263
+ posture = govern_posture()
264
+ if reachable:
265
+ label = LABEL_MEASURED
266
+ joules_label = LABEL_MEASURED
267
+ gpus = snap.get("gpus") or []
268
+ nodes = [{
269
+ "name": (g.get("name") or f"gpu{g.get('gpu')}"),
270
+ "live": True,
271
+ "watts": g.get("watts"),
272
+ "joules": g.get("joules"),
273
+ "source": "NVML",
274
+ } for g in gpus]
275
+ total_watts = snap.get("total_watts")
276
+ total_joules = snap.get("total_joules")
277
+ note = "joules MEASURED from the live NVML exporter (Prometheus /metrics)"
278
+ else:
279
+ label = LABEL_UNAVAILABLE
280
+ joules_label = LABEL_UNAVAILABLE
281
+ # Honest empty draw-list: surface the sovereign nodes that EXIST (mesh posture)
282
+ # so the dashboard still shows the topology, but with null watts/joules — never faked.
283
+ nodes = [{
284
+ "name": n.get("name"),
285
+ "live": n.get("live"),
286
+ "watts": None,
287
+ "joules": None,
288
+ "source": "mesh-posture",
289
+ } for n in (posture.get("nodes") or [])]
290
+ total_watts = None
291
+ total_joules = None
292
+ note = "meter offline — joules NOT fabricated"
293
+ return {
294
+ "ts": _now_iso(),
295
+ "label": label,
296
+ "nodes": nodes,
297
+ "total_watts": total_watts,
298
+ "total_joules": total_joules,
299
+ "joules_label": joules_label,
300
+ "meter_url": METER_URL,
301
+ "meter_status": snap.get("status"),
302
+ "exporter": "NVML" if reachable else None,
303
+ "mesh": posture,
304
+ "note": note,
305
+ "doctrine": "v11 — joules MEASURED only from a reachable NVML exporter; never fabricated.",
306
+ }
307
+
308
+
309
+ # ---------------------------------------------------------------------------
310
+ # /energy/mesh — per-node energy + governance posture for the 3D view.
311
+ # ---------------------------------------------------------------------------
312
+ def build_mesh() -> dict:
313
+ snap = meter_snapshot()
314
+ reachable = bool(snap.get("reachable"))
315
+ posture = govern_posture()
316
+ gpus = snap.get("gpus") or [] if reachable else []
317
+
318
+ # Honest attribution: match a meter GPU to a mesh node by GPU model token (e.g. the
319
+ # node "…RTX 4060 Ti…" gets the meter GPU whose name label contains "RTX 4060 Ti").
320
+ # A node with no model match keeps null watts/joules (UNAVAILABLE), never a guess.
321
+ def _match_gpu(gpu_model):
322
+ if not gpu_model:
323
+ return None
324
+ gm = gpu_model.lower()
325
+ for g in gpus:
326
+ if gm in (g.get("name") or "").lower():
327
+ return g
328
+ return None
329
+
330
+ nodes = []
331
+ watt_vals = []
332
+ for n in (posture.get("nodes") or []):
333
+ g = _match_gpu(n.get("gpu_model"))
334
+ watts = g.get("watts") if g else None
335
+ joules = g.get("joules") if g else None
336
+ if isinstance(watts, (int, float)):
337
+ watt_vals.append(watts)
338
+ nodes.append({
339
+ "name": n.get("name"),
340
+ "role": n.get("role"),
341
+ "live": n.get("live"),
342
+ "watts": watts,
343
+ "joules": joules,
344
+ "joules_label": LABEL_MEASURED if isinstance(joules, (int, float)) else LABEL_UNAVAILABLE,
345
+ "source": "NVML" if g else "mesh-posture",
346
+ })
347
+
348
+ # Normalized 0..1 draw for visualization (relative to the busiest live node this tick).
349
+ max_w = max(watt_vals) if watt_vals else 0.0
350
+ for node in nodes:
351
+ w = node["watts"]
352
+ node["draw"] = (round(w / max_w, 6) if (isinstance(w, (int, float)) and max_w > 0) else None)
353
+
354
+ label = LABEL_MEASURED if reachable else LABEL_UNAVAILABLE
355
+ return {
356
+ "ts": _now_iso(),
357
+ "label": label,
358
+ "nodes": nodes,
359
+ "node_count": len(nodes),
360
+ "live_count": posture.get("live_count", 0),
361
+ "total_watts": snap.get("total_watts") if reachable else None,
362
+ "total_joules": snap.get("total_joules") if reachable else None,
363
+ "joules_label": label,
364
+ "meter_url": METER_URL,
365
+ "meter_status": snap.get("status"),
366
+ "draw_basis": "watts normalized 0..1 vs the busiest live node this tick (null when no live watts)",
367
+ "note": ("per-node watts/joules attributed by GPU-model match to the live NVML exporter; "
368
+ "unmatched nodes are UNAVAILABLE, never fabricated"),
369
+ "doctrine": "v11 — honest empty-states; joules MEASURED only with a real exporter reading.",
370
+ }
371
+
372
+
373
+ # ---------------------------------------------------------------------------
374
+ # /energy/harvest — Bekenstein budget series + a heuristic tariff window.
375
+ # ---------------------------------------------------------------------------
376
+ _TARIFF_LABEL = ("client-side heuristic from the server clock, NOT a live tariff feed "
377
+ "(no real-time grid price wired)")
378
+
379
+
380
+ def _tariff_window(now=None) -> dict:
381
+ """Off-peak / normal / peak window from the LOCAL server clock. Explicitly a
382
+ heuristic — NOT a live tariff feed. Honest, mirrors the energy surface copy."""
383
+ now = datetime.now() if now is None else now
384
+ hour = now.hour
385
+ if 0 <= hour < 7:
386
+ window = "off-peak"
387
+ elif 17 <= hour < 21:
388
+ window = "peak"
389
+ else:
390
+ window = "normal"
391
+ return {
392
+ "window": window,
393
+ "local_hour": hour,
394
+ "label": _TARIFF_LABEL,
395
+ "bands": {"off-peak": "00:00-07:00", "normal": "07:00-17:00 & 21:00-24:00", "peak": "17:00-21:00"},
396
+ }
397
+
398
+
399
+ def _budget_series() -> dict:
400
+ """Time-ordered Bekenstein budget series from the in-memory energy-budget ledger
401
+ (szl_energy_budget): each task receipt's joules_est over time + cumulative, plus the
402
+ F19/TH6 all_within_bound gate. Honest SAMPLE/ESTIMATE labels carried through."""
403
+ try:
404
+ import szl_energy_budget as B
405
+ except Exception as e: # noqa: BLE001
406
+ return {"available": False, "series": [], "reason": f"budget unavailable: {type(e).__name__}"}
407
+ receipts = list(getattr(B, "_LEDGER", []) or [])
408
+ ordered = sorted(receipts, key=lambda r: r.get("ts") or "")
409
+ series = []
410
+ cum = 0.0
411
+ for r in ordered:
412
+ j = float(r.get("joules_est", 0.0) or 0.0)
413
+ cum += j
414
+ series.append({
415
+ "ts": r.get("ts"),
416
+ "joules_est": round(j, 6),
417
+ "cumulative_joules_est": round(cum, 6),
418
+ "within_bound": bool(r.get("within_bound")),
419
+ "shannon_bits": r.get("shannon_bits"),
420
+ "bekenstein_bound_bits": r.get("bekenstein_bound_bits"),
421
+ })
422
+ summary = {}
423
+ try:
424
+ summary = B.budget_summary()
425
+ except Exception: # noqa: BLE001
426
+ summary = {}
427
+ return {
428
+ "available": True,
429
+ "series": series,
430
+ "task_count": len(series),
431
+ "all_within_bound": summary.get("all_within_bound"),
432
+ "gate": "F19/TH6 Bekenstein: Σ shannon_bits <= Σ output_bytes*8 (proven inequality, locked-8)",
433
+ "total_joules_est": summary.get("total_joules_est"),
434
+ "total_joules_est_label": summary.get("total_joules_est_label"),
435
+ "joules_label": summary.get("joules_label", "sample"),
436
+ }
437
+
438
+
439
+ def _ledger_totals() -> dict:
440
+ """Signed-receipt-chain totals from szl_energy_ledger (MEASURED-billable joules are
441
+ honest; SAMPLE/blocked entries contribute 0). Guarded — a missing ledger degrades
442
+ to an honest unavailable block, never a fabricated total."""
443
+ try:
444
+ import szl_energy_ledger as L
445
+ led = L.get_ledger()
446
+ totals = led.totals()
447
+ chain = led.verify()
448
+ return {
449
+ "available": True,
450
+ "jobs": totals.get("jobs"),
451
+ "joules_measured_billable": totals.get("joules_measured_billable"),
452
+ "joules_measured_label": LABEL_MEASURED,
453
+ "kwh_total": totals.get("kwh_total"),
454
+ "chain_ok": chain.get("ok"),
455
+ "chain_length": chain.get("length"),
456
+ }
457
+ except Exception as e: # noqa: BLE001
458
+ return {"available": False, "reason": f"ledger unavailable: {type(e).__name__}"}
459
+
460
+
461
+ def build_harvest() -> dict:
462
+ budget = _budget_series()
463
+ ledger = _ledger_totals()
464
+ return {
465
+ "ts": _now_iso(),
466
+ "model": "Proven Energy Engine — harvest/grid view",
467
+ "tariff_window": _tariff_window(),
468
+ "budget": budget,
469
+ "signed_ledger": ledger,
470
+ "total_joules": budget.get("total_joules_est"),
471
+ "total_joules_label": budget.get("total_joules_est_label"),
472
+ "honesty": (
473
+ "The joules_est series is SAMPLE/ESTIMATE (no on-box meter behind the budget "
474
+ "layer); the signed_ledger joules_measured_billable is MEASURED (real NVML "
475
+ "deltas only). The tariff window is a client-side heuristic, NOT a live feed. "
476
+ "We harvest WASTED energy and PROVE bounded work — NO free-energy / "
477
+ "perpetual-motion claims, EVER. Bekenstein gate F19/TH6 is a proven inequality."
478
+ ),
479
+ "doctrine": "v11 — honest labels; no fabricated joules; no free-energy claims.",
480
+ }
481
+
482
+
483
+ # ---------------------------------------------------------------------------
484
+ # HTTP handlers + registration (matches szl_energy_budget: add_api_route, before SPA).
485
+ # ---------------------------------------------------------------------------
486
+ def _h_live(req: Request):
487
+ return JSONResponse(build_live())
488
+
489
+
490
+ def _h_mesh(req: Request):
491
+ return JSONResponse(build_mesh())
492
+
493
+
494
+ def _h_harvest(req: Request):
495
+ return JSONResponse(build_harvest())
496
+
497
+
498
+ def register(app, ns: str = "a11oy"):
499
+ """Wire the live energy endpoints onto the app under /api/<ns>/v1/energy/*.
500
+
501
+ Additive. Prefers FastAPI's add_api_route (so routes resolve BEFORE the SPA
502
+ catch-all, matching the other szl_energy_* modules); falls back to a Starlette
503
+ Route append for a bare Starlette app. Returns the list of mounted paths."""
504
+ base = f"/api/{ns}/v1/energy"
505
+ handlers = [
506
+ (f"{base}/live", _h_live),
507
+ (f"{base}/mesh", _h_mesh),
508
+ (f"{base}/harvest", _h_harvest),
509
+ ]
510
+ add_api_route = getattr(app, "add_api_route", None)
511
+ mounted = []
512
+ for path, fn in handlers:
513
+ try:
514
+ if callable(add_api_route):
515
+ app.add_api_route(path, fn, methods=["GET"])
516
+ else:
517
+ app.router.routes.append(Route(path, fn))
518
+ mounted.append(path)
519
+ except Exception:
520
+ continue
521
+ return mounted
522
+
523
+
524
+ # ---------------------------------------------------------------------------
525
+ # No-server self-test — proves parsing + honest labels, no live meter required.
526
+ # ---------------------------------------------------------------------------
527
+ def _selftest() -> dict:
528
+ out: dict = {}
529
+
530
+ # (a) Prometheus parse: per-GPU watts + cumulative joules; totals summed.
531
+ sample = (
532
+ "# HELP szl_gpu_power_watts GPU power draw.\n"
533
+ "# TYPE szl_gpu_power_watts gauge\n"
534
+ 'szl_gpu_power_watts{gpu="0",name="RTX 4060 Ti"} 142.5\n'
535
+ 'szl_gpu_energy_joules{gpu="0",name="RTX 4060 Ti"} 78369.586\n'
536
+ 'szl_gpu_power_watts{gpu="1",name="RTX 5050"} 60.0\n'
537
+ 'szl_gpu_energy_joules{gpu="1",name="RTX 5050"} 1000.0\n'
538
+ "szl_other_metric 5\n"
539
+ )
540
+ parsed = parse_meter_metrics(sample)
541
+ assert len(parsed["gpus"]) == 2, parsed
542
+ assert abs(parsed["total_watts"] - 202.5) < 1e-6, parsed
543
+ assert abs(parsed["total_joules"] - 79369.586) < 1e-6, parsed
544
+ out["prom_parse"] = True
545
+
546
+ # (b) MEASURED live snapshot wiring (inject a reachable parsed snapshot).
547
+ with _snap_lock:
548
+ _snap_cache["data"] = {**parse_meter_metrics(sample), "reachable": True, "status": "ok"}
549
+ _snap_cache["ts"] = time.time()
550
+ live = build_live()
551
+ assert live["label"] == LABEL_MEASURED and live["joules_label"] == LABEL_MEASURED, live
552
+ assert live["total_watts"] == 202.5, live
553
+ assert all(n["source"] == "NVML" and n["live"] is True for n in live["nodes"]), live
554
+ out["live_measured"] = True
555
+
556
+ # (c) UNAVAILABLE when the meter is offline — joules NOT fabricated.
557
+ with _snap_lock:
558
+ _snap_cache["data"] = None
559
+ _snap_cache["ts"] = 0.0
560
+ # Force a real fetch against an unroutable address so it fails fast/honestly.
561
+ _prev = globals()["METER_URL"]
562
+ try:
563
+ globals()["METER_URL"] = "http://127.0.0.1:9" # nothing listens here
564
+ snap = meter_snapshot(force=True)
565
+ assert snap["reachable"] is False, snap
566
+ live2 = build_live()
567
+ assert live2["label"] == LABEL_UNAVAILABLE and live2["total_joules"] is None, live2
568
+ assert "NOT fabricated" in live2["note"], live2
569
+ finally:
570
+ globals()["METER_URL"] = _prev
571
+ out["unavailable_honest"] = True
572
+
573
+ # (d) Harvest: budget series + heuristic window labeled NOT a live feed; no free energy.
574
+ harvest = build_harvest()
575
+ assert "NOT a live tariff feed" in harvest["tariff_window"]["label"], harvest["tariff_window"]
576
+ assert harvest["tariff_window"]["window"] in ("off-peak", "normal", "peak")
577
+ assert "free-energy" in harvest["honesty"].lower() or "no free" in harvest["honesty"].lower()
578
+ assert harvest["budget"]["available"] in (True, False)
579
+ out["harvest_honest"] = True
580
+
581
+ # (e) Mesh: honest empty-states; draw normalized or null, never fabricated.
582
+ mesh = build_mesh()
583
+ assert "nodes" in mesh and isinstance(mesh["nodes"], list)
584
+ assert mesh["label"] in (LABEL_MEASURED, LABEL_UNAVAILABLE)
585
+ out["mesh_shape"] = True
586
+
587
+ out["ok"] = all(v is True for v in out.values())
588
+ return out
589
+
590
+
591
+ if __name__ == "__main__":
592
+ import json
593
+ print(json.dumps(_selftest(), indent=2))