betterwithage commited on
Commit
17632c8
·
verified ·
1 Parent(s): fccecd6

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
Deleted (gone from the repo + Dockerfile COPY set): a11oy_orbital_page.py

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 (2) hide show
  1. Dockerfile +9 -5
  2. a11oy_orbital_page.py +0 -418
Dockerfile CHANGED
@@ -156,11 +156,6 @@ COPY joule_billing.py szl_energy_ledger.py szl_energy_operator.py szl_energy_pro
156
  # /api/a11oy/v1/orbital/{topology,projection} 404 live. szl_orbital_projection reuses
157
  # szl_energy_operator (the REAL measured ground J/token coefficient), already COPY'd above.
158
  COPY szl_orbital_topology.py szl_orbital_projection.py ./
159
- # Orbital PAGE (frontend demo surface) — serve.py imports a11oy_orbital_page (guarded)
160
- # to mount GET /orbital (the MODELED constellation demo, banner-labeled, 0 CDN via the
161
- # vendor3d three.js COPY'd below). MUST be per-file COPY'd or /orbital falls back to the
162
- # SPA catch-all (white screen / no orbital surface).
163
- COPY a11oy_orbital_page.py ./
164
  # K-Verify governed-inference benchmark — imported by serve.py (guarded). MUST be
165
  # per-file COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back and
166
  # /api/a11oy/v1/kverify/* 404s. Reuses szl_energy_operator (inference + NVML joules)
@@ -1055,6 +1050,15 @@ COPY web/energy.html ./web/energy.html
1055
  # receipt digest). Per-file served asset -> declared image_only in copy-sync-
1056
  # lockstep.json (same baked-only pattern as web/energy.html). Codename-free.
1057
  COPY web/immune.html ./web/immune.html
 
 
 
 
 
 
 
 
 
1058
 
1059
  # git_sha wireup (FORGE-INSTRUCTION-gitsha-quiet-window): surface the deployed commit
1060
  # at the /honest endpoint so a stale box or Space is self-detecting. Provided at build
 
156
  # /api/a11oy/v1/orbital/{topology,projection} 404 live. szl_orbital_projection reuses
157
  # szl_energy_operator (the REAL measured ground J/token coefficient), already COPY'd above.
158
  COPY szl_orbital_topology.py szl_orbital_projection.py ./
 
 
 
 
 
159
  # K-Verify governed-inference benchmark — imported by serve.py (guarded). MUST be
160
  # per-file COPY'd (this Dockerfile uses no `COPY . .`) or the import falls back and
161
  # /api/a11oy/v1/kverify/* 404s. Reuses szl_energy_operator (inference + NVML joules)
 
1050
  # receipt digest). Per-file served asset -> declared image_only in copy-sync-
1051
  # lockstep.json (same baked-only pattern as web/energy.html). Codename-free.
1052
  COPY web/immune.html ./web/immune.html
1053
+ # Materials (Q'allariy) honest Verifiable Alloy & Crystal Discovery page (/materials,
1054
+ # /a11oy/materials). Standalone sovereign page (0 runtime CDN), binds to live
1055
+ # /api/a11oy/v1/materials/* (novelty/certify/screen) + /immune/verdict fallback; a
1056
+ # crystal-novelty form, a PAC-Bayes certificate panel, an Immune screen panel, and an
1057
+ # honest PROVEN/CONJECTURE/ROADMAP claim-sheet footer. image_only (baked into the
1058
+ # GitHub-built image via this per-file COPY, served from /app/web/) and declared an
1059
+ # accepted divergence in .github/hf-module-drift-allow.json (same baked-only pattern
1060
+ # as web/immune.html + web/energy.html). Codename-free.
1061
+ COPY web/materials.html ./web/materials.html
1062
 
1063
  # git_sha wireup (FORGE-INSTRUCTION-gitsha-quiet-window): surface the deployed commit
1064
  # at the /honest endpoint so a stale box or Space is self-detecting. Provided at build
a11oy_orbital_page.py DELETED
@@ -1,418 +0,0 @@
1
- # SPDX-License-Identifier: Apache-2.0
2
- # © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11
3
- """a11oy_orbital_page — ADDITIVE /orbital demo surface (page + 3D/viz).
4
-
5
- Renders the MODELED SZL orbital-compute constellation against the already-live
6
- backend (PR #468): GET /api/a11oy/v1/orbital/topology and .../orbital/projection.
7
-
8
- What it draws (all MODELED — SZL has NO on-orbit hardware):
9
- * LEO edge-compute shell, MEO aggregation ring, GEO backhaul tier (nodes),
10
- * OISL inter-satellite links + ground-space downlinks to the REAL ground fabric,
11
- * a governed-receipt overlay: each MODELED orbital job shows a MODELED energy
12
- figure (joules/kWh) derived from the REAL ground-measured J/token coefficient
13
- (cited) PLUS a would-be signed receipt — the SZL moat (governed energy-receipt
14
- + signed provenance) applied to space compute. The receipt is explicitly a
15
- MODELED would-be artifact, never presented as a real signed receipt.
16
-
17
- HONESTY (doctrine v11, non-negotiable):
18
- * The ENTIRE surface is visibly + persistently labeled
19
- "MODELED — Orbital Roadmap (no on-orbit hardware yet)". It can never be mistaken
20
- for live telemetry.
21
- * No orbital node/joule/receipt is fabricated. Nodes come straight from the live
22
- topology endpoint (modeled:true / reachable:false). The energy figure comes from
23
- the live projection endpoint, whose ONLY MEASURED input is the ground J/token
24
- coefficient; the orbital joules are MODELED and labeled MODELED. A MODELED
25
- orbital joule is NEVER labeled MEASURED here.
26
- * 0 runtime CDN: three.js r160 (MIT) is loaded from the in-image vendored path
27
- /hero/vendor3d/ (the same proven, allowlisted, runtime-served route the
28
- cathedral hero uses). No external host is ever fetched.
29
- * If an endpoint is unreachable the page degrades honestly (shows the error,
30
- draws nothing fabricated) — honest BLOCKED beats fake green.
31
-
32
- Pattern mirrors a11oy_formulas_page.register(app, ns): mounts
33
- GET /orbital (self-contained HTML, 0 CDN)
34
- GET /api/<ns>/v1/orbital/page-manifest (JSON nav descriptor)
35
- Registered BEFORE the SPA /{full_path:path} catch-all; try/except-guarded in
36
- serve.py so a missing dep can never take down the Space. Λ = Conjecture 1;
37
- sovereign=false on this path. Doctrine v11 LOCKED.
38
- """
39
- from __future__ import annotations
40
-
41
- from fastapi import FastAPI
42
- from fastapi.responses import HTMLResponse, JSONResponse
43
-
44
- DOCTRINE = {"version": "v11", "lambda": "Conjecture 1", "sovereign": False}
45
- MODELED_BANNER = "MODELED — Orbital Roadmap (no on-orbit hardware yet)"
46
-
47
- # The two LIVE backend endpoints this surface renders (PR #468). Wired client-side.
48
- _TOPOLOGY_EP = "/api/{ns}/v1/orbital/topology"
49
- _PROJECTION_EP = "/api/{ns}/v1/orbital/projection"
50
-
51
- # 0-CDN vendored three.js r160 — the proven, allowlisted, runtime-served hero path
52
- # (serve.py GET /hero/vendor3d/{fname}; identical to cathedral_genius.html importmap).
53
- _THREE_MAIN = "/hero/vendor3d/three.module.min.js"
54
- _THREE_ADDONS = "/hero/vendor3d/"
55
-
56
-
57
- def _page_html(ns: str) -> str:
58
- topology_ep = _TOPOLOGY_EP.format(ns=ns)
59
- projection_ep = _PROJECTION_EP.format(ns=ns)
60
- return f"""<!doctype html>
61
- <html lang="en"><head>
62
- <meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/>
63
- <title>A11oy — Orbital Compute Tier (MODELED Roadmap)</title>
64
- <!-- Sovereign importmap: ONLY vendored local files. 0 runtime CDN. Doctrine v11. -->
65
- <script type="importmap">
66
- {{
67
- "imports": {{
68
- "three": "{_THREE_MAIN}",
69
- "three/addons/": "{_THREE_ADDONS}"
70
- }}
71
- }}
72
- </script>
73
- <style>
74
- :root {{ --bg:#070b16; --panel:#101a2e; --ink:#e8eef7; --muted:#8aa0bd;
75
- --indigo:#4d8fcc; --terra:#c8643c; --gold:#d8a23c; --amber:#e8c074;
76
- --green:#2fd07a; --warn:#c8893c; }}
77
- * {{ box-sizing:border-box; }}
78
- html,body {{ margin:0; height:100%; }}
79
- body {{ font-family:ui-sans-serif,system-ui,Segoe UI,Roboto,sans-serif;
80
- background:radial-gradient(1200px 700px at 70% -10%, #14213b, var(--bg));
81
- color:var(--ink); overflow:hidden; }}
82
- /* Persistent, unmissable MODELED banner — top of every viewport. */
83
- #modeled-banner {{ position:fixed; top:0; left:0; right:0; z-index:50;
84
- background:linear-gradient(90deg, rgba(216,162,60,.22), rgba(200,100,60,.18));
85
- border-bottom:1px solid rgba(232,192,116,.5);
86
- color:var(--amber); font-family:ui-monospace,monospace; font-size:.82rem;
87
- letter-spacing:.06em; text-transform:uppercase; padding:.55rem 1rem;
88
- display:flex; align-items:center; gap:.6rem; backdrop-filter:blur(4px); }}
89
- #modeled-banner .dot {{ width:.6rem; height:.6rem; border-radius:50%;
90
- background:var(--amber); box-shadow:0 0 8px var(--amber); flex:0 0 auto; }}
91
- #modeled-banner b {{ color:var(--gold); }}
92
- #scene {{ position:fixed; inset:0; }}
93
- #hud {{ position:fixed; top:3rem; left:0; right:0; bottom:0; pointer-events:none;
94
- padding:1rem 1.1rem; display:flex; flex-direction:column; gap:.8rem; }}
95
- .plaque {{ font-family:ui-monospace,monospace; font-size:.7rem; letter-spacing:.12em;
96
- color:var(--muted); text-transform:uppercase; }}
97
- .plaque b {{ color:var(--gold); }}
98
- h1 {{ font-size:clamp(1.4rem,3vw,2.1rem); margin:.2rem 0 0; }}
99
- h1 .accent {{ color:var(--terra); }}
100
- .sub {{ color:var(--muted); max-width:64ch; line-height:1.5; font-size:.86rem; margin:.3rem 0 0; }}
101
- .panels {{ display:flex; gap:.8rem; flex-wrap:wrap; margin-top:auto; }}
102
- .panel {{ pointer-events:auto; background:rgba(16,26,46,.86); border:1px solid #21304d;
103
- border-radius:12px; padding:.85rem 1rem; min-width:240px; max-width:340px;
104
- box-shadow:0 18px 40px -28px #000; backdrop-filter:blur(6px); }}
105
- .panel h3 {{ margin:0 0 .5rem; font-family:ui-monospace,monospace; color:var(--indigo);
106
- font-size:.9rem; display:flex; align-items:center; gap:.45rem; }}
107
- .kv {{ display:flex; justify-content:space-between; gap:1rem; font-size:.78rem;
108
- padding:.18rem 0; border-bottom:1px dashed rgba(138,160,189,.14); }}
109
- .kv span:first-child {{ color:var(--muted); }}
110
- .kv span:last-child {{ font-family:ui-monospace,monospace; }}
111
- .badge {{ font-size:.6rem; padding:.14rem .45rem; border-radius:999px; letter-spacing:.06em;
112
- text-transform:uppercase; font-family:ui-monospace,monospace; }}
113
- .badge.modeled {{ background:rgba(232,192,116,.16); color:var(--amber); border:1px solid rgba(232,192,116,.45); }}
114
- .badge.measured {{ background:rgba(47,208,122,.16); color:var(--green); border:1px solid rgba(47,208,122,.45); }}
115
- .receipt {{ font-family:ui-monospace,monospace; font-size:.7rem; color:#9fb1bf;
116
- background:#070c17; border:1px solid #1a2742; border-radius:8px;
117
- padding:.5rem .6rem; margin-top:.5rem; word-break:break-all; line-height:1.45; }}
118
- .receipt .lbl {{ color:var(--amber); }}
119
- .status {{ font-size:.74rem; color:var(--muted); }}
120
- .status.err {{ color:var(--warn); }}
121
- a.back {{ color:var(--muted); text-decoration:none; font-size:.8rem; pointer-events:auto; }}
122
- #legend {{ display:flex; gap:1rem; flex-wrap:wrap; font-size:.72rem; color:var(--muted);
123
- font-family:ui-monospace,monospace; }}
124
- #legend i {{ width:.7rem; height:.7rem; border-radius:2px; display:inline-block;
125
- margin-right:.35rem; vertical-align:middle; }}
126
- noscript {{ color:var(--amber); display:block; padding:4rem 1.5rem; }}
127
- </style></head>
128
- <body>
129
- <div id="modeled-banner">
130
- <span class="dot"></span>
131
- <span><b>{MODELED_BANNER}</b> &nbsp;·&nbsp; SZL operates a REAL ground GPU fabric today;
132
- every orbital node/link/joule below is a MODELED design artifact — not reachable,
133
- never serving a real job. Λ = Conjecture 1.</span>
134
- </div>
135
-
136
- <canvas id="scene"></canvas>
137
-
138
- <div id="hud">
139
- <div>
140
- <div class="plaque">SZL HOLDINGS / A11OY / DOCTRINE <b>V11 · LOCKED</b> / Λ = CONJECTURE 1</div>
141
- <h1>The orbital <span class="accent">moat</span>, modeled.</h1>
142
- <p class="sub" id="subline">Loading the MODELED constellation from the live
143
- <code>/orbital/*</code> endpoints… Governed energy-receipts + signed provenance,
144
- applied to space compute — a FORWARD design, not a deployed system.</p>
145
- <div id="legend"></div>
146
- </div>
147
-
148
- <div class="panels">
149
- <div class="panel" id="panel-topology">
150
- <h3>◇ Constellation <span class="badge modeled">MODELED</span></h3>
151
- <div id="topo-body"><div class="status" id="topo-status">fetching topology…</div></div>
152
- </div>
153
- <div class="panel" id="panel-receipt">
154
- <h3>⛓ Governed receipt <span class="badge modeled">MODELED</span></h3>
155
- <div id="receipt-body"><div class="status" id="proj-status">fetching projection…</div></div>
156
- </div>
157
- <div style="align-self:flex-end"><a class="back" href="/">← back to console</a></div>
158
- </div>
159
- </div>
160
-
161
- <noscript>This MODELED orbital roadmap surface requires JavaScript to render its 3D
162
- constellation. No live telemetry is shown — SZL has no on-orbit hardware.</noscript>
163
-
164
- <script type="module">
165
- import * as THREE from 'three';
166
- import {{ OrbitControls }} from 'three/addons/OrbitControls.js';
167
-
168
- const TOPOLOGY_EP = {topology_ep!r};
169
- const PROJECTION_EP = {projection_ep!r};
170
-
171
- // ---- honesty helpers --------------------------------------------------------
172
- const TIER_COLOR = {{
173
- 'LEO-edge': 0x4d8fcc, // indigo
174
- 'MEO-aggregation': 0xd8a23c, // gold
175
- 'GEO-backhaul': 0xc8643c, // terra
176
- }};
177
- const TIER_RADIUS = {{ 'LEO-edge': 9, 'MEO-aggregation': 15, 'GEO-backhaul': 22 }};
178
- const AMBER = '#e8c074', GREEN = '#2fd07a';
179
-
180
- function esc(s) {{ return String(s).replace(/[&<>"']/g, c =>
181
- ({{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}}[c])); }}
182
-
183
- // ---- three.js scene (r160, vendored, 0 CDN) --------------------------------
184
- const canvas = document.getElementById('scene');
185
- const renderer = new THREE.WebGLRenderer({{ canvas, antialias:true, alpha:true }});
186
- renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
187
- const scene = new THREE.Scene();
188
- const camera = new THREE.PerspectiveCamera(55, 1, 0.1, 2000);
189
- camera.position.set(0, 18, 64);
190
- const controls = new OrbitControls(camera, canvas);
191
- controls.enableDamping = true; controls.dampingFactor = 0.06;
192
- controls.autoRotate = true; controls.autoRotateSpeed = 0.35;
193
-
194
- scene.add(new THREE.AmbientLight(0x88aacc, 0.7));
195
- const key = new THREE.PointLight(0xffffff, 1.2); key.position.set(40, 50, 50); scene.add(key);
196
-
197
- // Earth proxy (MODELED globe — purely a visual reference, not a data claim).
198
- const earth = new THREE.Mesh(
199
- new THREE.SphereGeometry(5.6, 48, 48),
200
- new THREE.MeshStandardMaterial({{ color:0x0d2238, emissive:0x06121f, roughness:0.9, metalness:0.1, wireframe:false }})
201
- );
202
- scene.add(earth);
203
- const grid = new THREE.Mesh(
204
- new THREE.SphereGeometry(5.7, 24, 24),
205
- new THREE.MeshBasicMaterial({{ color:0x1d3a5c, wireframe:true, transparent:true, opacity:0.35 }})
206
- );
207
- scene.add(grid);
208
-
209
- const nodeGroup = new THREE.Group(); scene.add(nodeGroup);
210
- const linkGroup = new THREE.Group(); scene.add(linkGroup);
211
-
212
- function resize() {{
213
- const w = innerWidth, h = innerHeight;
214
- renderer.setSize(w, h, false);
215
- camera.aspect = w / h; camera.updateProjectionMatrix();
216
- }}
217
- addEventListener('resize', resize); resize();
218
-
219
- (function loop() {{
220
- requestAnimationFrame(loop);
221
- controls.update();
222
- earth.rotation.y += 0.0008; grid.rotation.y += 0.0008;
223
- renderer.render(scene, camera);
224
- }})();
225
-
226
- // Deterministic placement: spread a tier's nodes evenly around a ring, tilted per plane.
227
- function placeNodes(nodes) {{
228
- const byTier = {{}};
229
- for (const n of nodes) (byTier[n.tier] = byTier[n.tier] || []).push(n);
230
- const pos = {{}};
231
- for (const [tier, arr] of Object.entries(byTier)) {{
232
- const R = TIER_RADIUS[tier] || 12;
233
- arr.forEach((n, i) => {{
234
- const a = (i / arr.length) * Math.PI * 2;
235
- const tilt = ((n.orbital_plane || 0) * 0.5);
236
- pos[n.id] = new THREE.Vector3(
237
- Math.cos(a) * R,
238
- Math.sin(tilt) * R * 0.35 + Math.sin(a) * 1.5,
239
- Math.sin(a) * R
240
- );
241
- }});
242
- }}
243
- return pos;
244
- }}
245
-
246
- function drawTopology(t) {{
247
- nodeGroup.clear(); linkGroup.clear();
248
- const nodes = t.orbital_nodes || [];
249
- const pos = placeNodes(nodes);
250
- // ground stations sit just outside the globe surface
251
- const gsList = t.ground_stations || [];
252
- gsList.forEach((gs, i) => {{
253
- const a = (i / Math.max(gsList.length,1)) * Math.PI * 2;
254
- pos[gs.id] = new THREE.Vector3(Math.cos(a) * 6.2, -1.5, Math.sin(a) * 6.2);
255
- }});
256
-
257
- for (const n of nodes) {{
258
- const color = TIER_COLOR[n.tier] || 0x9fb1bf;
259
- // reachable is REAL-PROBE-ONLY; topology always reports false — render as hollow.
260
- const mat = new THREE.MeshStandardMaterial({{
261
- color, emissive:color, emissiveIntensity:0.35, roughness:0.5,
262
- transparent:true, opacity:0.92
263
- }});
264
- const m = new THREE.Mesh(new THREE.SphereGeometry(0.55, 20, 20), mat);
265
- m.position.copy(pos[n.id]);
266
- nodeGroup.add(m);
267
- }}
268
- // ground stations: small green markers (REAL ground side; the downlink is MODELED)
269
- for (const gs of gsList) {{
270
- const m = new THREE.Mesh(new THREE.SphereGeometry(0.4, 16, 16),
271
- new THREE.MeshStandardMaterial({{ color:0x2fd07a, emissive:0x2fd07a, emissiveIntensity:0.4 }}));
272
- m.position.copy(pos[gs.id]); nodeGroup.add(m);
273
- }}
274
-
275
- for (const l of (t.links || [])) {{
276
- const a = pos[l.src], b = pos[l.dst];
277
- if (!a || !b) continue;
278
- const isDown = l.kind === 'ground-space-downlink';
279
- const geo = new THREE.BufferGeometry().setFromPoints([a, b]);
280
- const mat = new THREE.LineBasicMaterial({{
281
- color: isDown ? 0x2fd07a : 0x6fb1ff, transparent:true, opacity: isDown ? 0.7 : 0.4
282
- }});
283
- linkGroup.add(new THREE.Line(geo, mat));
284
- }}
285
-
286
- // legend
287
- document.getElementById('legend').innerHTML = [
288
- ['#4d8fcc','LEO edge (MODELED)'], ['#d8a23c','MEO aggregation (MODELED)'],
289
- ['#c8643c','GEO backhaul (MODELED)'], ['#6fb1ff','OISL link (MODELED)'],
290
- ['#2fd07a','ground downlink (MODELED) → REAL ground node'],
291
- ].map(([c,t]) => `<span><i style="background:${{c}}"></i>${{esc(t)}}</span>`).join('');
292
-
293
- // topology panel
294
- const s = t.summary || {{}};
295
- document.getElementById('topo-body').innerHTML = [
296
- ['data_kind', t.data_kind], ['status', t.status],
297
- ['on-orbit hardware', String(t.on_orbit_hardware)],
298
- ['LEO / MEO / GEO', `${{s.leo_edge_nodes}} / ${{s.meo_aggregation_nodes}} / ${{s.geo_backhaul_nodes}}`],
299
- ['total nodes / links', `${{s.total_nodes}} / ${{s.total_links}}`],
300
- ['reachable nodes', String(s.reachable_nodes)],
301
- ].map(([k,v]) => `<div class="kv"><span>${{esc(k)}}</span><span>${{esc(v)}}</span></div>`).join('');
302
- }}
303
-
304
- // Build a would-be (MODELED) signed receipt from the MODELED projection. This is
305
- // the SZL moat illustrated — NOT a real signed receipt; explicitly labeled MODELED.
306
- async function modeledReceiptId(proj) {{
307
- const op = proj.orbital_projection || {{}};
308
- const j = (op.orbital_joules && op.orbital_joules.value) || 0;
309
- const basis = JSON.stringify({{ j, ts: proj.timestamp_utc, node: (proj.orbital_node||{{}}).id }});
310
- let hex = 'unavailable';
311
- try {{
312
- const buf = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(basis));
313
- hex = Array.from(new Uint8Array(buf)).map(b => b.toString(16).padStart(2,'0')).join('').slice(0, 32);
314
- }} catch (e) {{ hex = 'sha256-unavailable-(no-subtlecrypto)'; }}
315
- return hex;
316
- }}
317
-
318
- async function drawProjection(p) {{
319
- const coeff = p.ground_measured_coefficient || {{}};
320
- const op = p.orbital_projection || {{}};
321
- const jpt = (coeff.j_per_token && coeff.j_per_token.value);
322
- const ojoules = (op.orbital_joules && op.orbital_joules.value);
323
- const okwh = (op.orbital_kwh && op.orbital_kwh.value);
324
- const rid = await modeledReceiptId(p);
325
-
326
- document.getElementById('receipt-body').innerHTML = `
327
- <div class="kv"><span>ground J/token</span><span>${{esc(jpt)}} <span class="badge measured">MEASURED</span></span></div>
328
- <div class="kv"><span>coeff source</span><span>${{esc(coeff.measured_source || '—')}}</span></div>
329
- <div class="kv"><span>orbital joules</span><span>${{esc(ojoules)}} <span class="badge modeled">MODELED</span></span></div>
330
- <div class="kv"><span>orbital kWh</span><span>${{esc(okwh)}} <span class="badge modeled">MODELED</span></span></div>
331
- <div class="receipt">
332
- <span class="lbl">would-be signed receipt (MODELED — not a real signature):</span><br/>
333
- governed-energy-receipt:${{esc(rid)}}<br/>
334
- <span class="lbl">basis:</span> MEASURED ground J/token × MODELED workload × MODELED space-overhead<br/>
335
- <span class="lbl">honesty:</span> sovereign=false · Λ=Conjecture 1 · no on-orbit hardware
336
- </div>`;
337
- document.getElementById('subline').innerHTML =
338
- 'Each MODELED orbital job carries a MODELED energy figure (derived from the REAL ' +
339
- 'ground-measured J/token coefficient, cited above) and a <b>would-be signed ' +
340
- 'governed-energy-receipt</b> — the SZL moat, applied to space compute. Forward design, not deployed.';
341
- }}
342
-
343
- function fail(elId, msg) {{
344
- const el = document.getElementById(elId);
345
- if (el) {{ el.className = 'status err'; el.textContent = msg; }}
346
- }}
347
-
348
- (async function load() {{
349
- try {{
350
- const r = await fetch(TOPOLOGY_EP, {{ headers:{{Accept:'application/json'}} }});
351
- const t = await r.json();
352
- if (!r.ok || t.ok === false) throw new Error('topology ' + r.status);
353
- drawTopology(t);
354
- }} catch (e) {{ fail('topo-status', 'topology unavailable: ' + e + ' (nothing fabricated)'); }}
355
-
356
- try {{
357
- const r = await fetch(PROJECTION_EP, {{ headers:{{Accept:'application/json'}} }});
358
- const p = await r.json();
359
- if (!r.ok || p.ok === false) throw new Error('projection ' + r.status);
360
- await drawProjection(p);
361
- }} catch (e) {{ fail('proj-status', 'projection unavailable: ' + e + ' (no fabricated joule)'); }}
362
- }})();
363
- </script>
364
- </body></html>"""
365
-
366
-
367
- def register(app: FastAPI, ns: str = "a11oy") -> str:
368
- """Mount GET /orbital (HTML) + GET /api/<ns>/v1/orbital/page-manifest (JSON).
369
- ADDITIVE — registered before the SPA catch-all; touches no existing route."""
370
-
371
- @app.get("/orbital", include_in_schema=False)
372
- async def orbital_page() -> HTMLResponse: # noqa: ANN202
373
- return HTMLResponse(_page_html(ns))
374
-
375
- @app.get(f"/api/{ns}/v1/orbital/page-manifest", include_in_schema=False)
376
- async def orbital_page_manifest() -> JSONResponse: # noqa: ANN202
377
- return JSONResponse({
378
- "section": "Orbital",
379
- "page": "/orbital",
380
- "data_kind": "MODELED-roadmap",
381
- "banner": MODELED_BANNER,
382
- "on_orbit_hardware": False,
383
- "doctrine": DOCTRINE,
384
- "renders_endpoints": [
385
- _TOPOLOGY_EP.format(ns=ns),
386
- _PROJECTION_EP.format(ns=ns),
387
- ],
388
- "vendored_3d": {"three": _THREE_MAIN, "addons": _THREE_ADDONS, "revision": "r160", "runtime_cdn": 0},
389
- "note": ("MODELED orbital roadmap surface — no on-orbit hardware. Nodes/joules "
390
- "come from the live MODELED endpoints; the signed receipt shown is a "
391
- "MODELED would-be artifact, never a real signature."),
392
- })
393
-
394
- return f"orbital-page mounted: GET /orbital + page-manifest (renders MODELED topology+projection, 0 CDN)"
395
-
396
-
397
- def _selftest() -> None:
398
- html = _page_html("a11oy")
399
- # 1) the persistent MODELED banner is present, verbatim
400
- assert MODELED_BANNER in html, "MODELED banner missing"
401
- assert "no on-orbit hardware" in html, "no-hardware honesty note missing"
402
- # 2) both live endpoints are wired client-side
403
- assert "/api/a11oy/v1/orbital/topology" in html, "topology endpoint not wired"
404
- assert "/api/a11oy/v1/orbital/projection" in html, "projection endpoint not wired"
405
- # 3) 0 runtime CDN — three.js loads from the vendored hero path, no external host
406
- assert _THREE_MAIN in html and "http://" not in html and "https://" not in html, \
407
- "external URL / CDN reference found (0-CDN doctrine)"
408
- # 4) a renderable marker exists (canvas + heading) so a live grep proves real content
409
- assert 'id="scene"' in html and "orbital" in html.lower(), "render marker missing"
410
- # 5) honesty: a MODELED orbital joule is never relabeled MEASURED; only the
411
- # ground coefficient carries MEASURED. The receipt is explicitly MODELED.
412
- assert "would-be signed receipt (MODELED" in html, "receipt not labeled MODELED"
413
- assert "Conjecture 1" in html, "Λ label missing"
414
- print("a11oy_orbital_page: ALL OK (MODELED banner, endpoints wired, 0 CDN, render marker, honest receipt)")
415
-
416
-
417
- if __name__ == "__main__":
418
- _selftest()