betterwithage commited on
Commit
2cdd702
·
verified ·
1 Parent(s): 7e09d8f

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, szl_spaces_proxy.py, szl_spaces_surface.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 +4 -0
  2. szl_spaces_proxy.py +337 -0
  3. szl_spaces_surface.py +473 -0
Dockerfile CHANGED
@@ -142,6 +142,10 @@ COPY knowledge.json ./static/knowledge.json
142
  # Signed-off-by: Yachay <yachay@szlholdings.ai>
143
  # ---------------------------------------------------------------------------
144
  COPY knowledge.json szl_parity_gaps.py a11oy_warhacker_obs.py serve.py a11oy_wireA_metrics.py cathedral.html a11oy_operator_organ.py a11oy_hf_assets.py szl_b2_secdata.py gates_manifest.json a11oy_code_orchestrator.py a11oy_agent_loop.py a11oy_org_rag.py a11oy_mcp_client.py szl_rag.py a11oy_code_ide.html wayra_serve.py wayra_snapshot.json wayra_digests_7d.json szl_khipu_os_routes.py ./
 
 
 
 
145
  COPY szl_khipu_consensus.py szl_puriq_formulas.py ayni_os_serve.py szl_live_wires.py live_wires.html live_wires_3d.js szl_dsse.py szl_provenance.py szl_be_hardening.py szl_unay.py szl_khipu_lmdb.py szl_khipu_replicate.py szl_unay_routes.py szl_warhacker_aliases.py a11oy_v4_hickok.py szl_khipu.py szl_formulas.py a11oy_v4_formulas.py szl_anatomy_3d.py szl_anatomy_routes.py ./
146
  COPY _vendor_blobs.py szl_v4_fleet.py operator_shell_v4.py szl_bridge.py szl_bridge_schemas.py agent.html a11oy_bridge_cli.py szl_ken.py a11oy_formula_endpoints.py a11oy_formulas_page.py a11oy_frontier_patch.py a11oy_v4_agent.py szl_brain.py szl_wire.py szl_hub.py szl_rosie_companion.py szl_receipt_substrate.py szl_alloy_embed_fabric.py szl_ayni_quorum.py szl_agentic_loop.py ./
147
  COPY szl_formula_wiring.py a11oy_code_engine.py a11oy_code.py a11oy_seismic.py szl_warhacker_real.py szl_warhacker_demos.py NOTICE_warhacker_demos.txt szl_llm_registry.py szl_elite_console.py szl_alloy_models.py szl_scaling.py szl_allodial.py szl_entanglement.py szl_neuroplasticity.py szl_chain_of_title.py szl_sovereign_compute.py a11oy_active_flux_router.py ./
 
142
  # Signed-off-by: Yachay <yachay@szlholdings.ai>
143
  # ---------------------------------------------------------------------------
144
  COPY knowledge.json szl_parity_gaps.py a11oy_warhacker_obs.py serve.py a11oy_wireA_metrics.py cathedral.html a11oy_operator_organ.py a11oy_hf_assets.py szl_b2_secdata.py gates_manifest.json a11oy_code_orchestrator.py a11oy_agent_loop.py a11oy_org_rag.py a11oy_mcp_client.py szl_rag.py a11oy_code_ide.html wayra_serve.py wayra_snapshot.json wayra_digests_7d.json szl_khipu_os_routes.py ./
145
+ # Spaces-on-a11oy.net shared modules (Dev2+3) — reverse-proxy + console surface.
146
+ # Per-file COPY (this Dockerfile uses no `COPY . .`) or serve.py's guarded import
147
+ # falls back and /spaces + /api/<ns>/v1/spaces/health 404. Byte-identical a11oy+killinchu.
148
+ COPY szl_spaces_proxy.py szl_spaces_surface.py ./
149
  COPY szl_khipu_consensus.py szl_puriq_formulas.py ayni_os_serve.py szl_live_wires.py live_wires.html live_wires_3d.js szl_dsse.py szl_provenance.py szl_be_hardening.py szl_unay.py szl_khipu_lmdb.py szl_khipu_replicate.py szl_unay_routes.py szl_warhacker_aliases.py a11oy_v4_hickok.py szl_khipu.py szl_formulas.py a11oy_v4_formulas.py szl_anatomy_3d.py szl_anatomy_routes.py ./
150
  COPY _vendor_blobs.py szl_v4_fleet.py operator_shell_v4.py szl_bridge.py szl_bridge_schemas.py agent.html a11oy_bridge_cli.py szl_ken.py a11oy_formula_endpoints.py a11oy_formulas_page.py a11oy_frontier_patch.py a11oy_v4_agent.py szl_brain.py szl_wire.py szl_hub.py szl_rosie_companion.py szl_receipt_substrate.py szl_alloy_embed_fabric.py szl_ayni_quorum.py szl_agentic_loop.py ./
151
  COPY szl_formula_wiring.py a11oy_code_engine.py a11oy_code.py a11oy_seismic.py szl_warhacker_real.py szl_warhacker_demos.py NOTICE_warhacker_demos.txt szl_llm_registry.py szl_elite_console.py szl_alloy_models.py szl_scaling.py szl_allodial.py szl_entanglement.py szl_neuroplasticity.py szl_chain_of_title.py szl_sovereign_compute.py a11oy_active_flux_router.py ./
szl_spaces_proxy.py ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ # © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173
4
+ """szl_spaces_proxy.py — surface the live HF Spaces estate under a11oy.net/spaces/*.
5
+
6
+ ADDITIVE, self-contained, SHARED (byte-identical in a11oy + killinchu). Founder rule:
7
+ "all the huggingface on my a11oy.net" with NO new subdomains. This module reverse-
8
+ proxies each live Hugging Face Space to a same-origin path:
9
+
10
+ GET/HEAD /spaces -> index (delegates to szl_spaces_surface tiles if
11
+ present; else a minimal honest index of the 11)
12
+ GET/HEAD /spaces/{name} -> reverse-proxy of https://szlholdings-{name}.hf.space/
13
+ GET/HEAD /spaces/{name}/{path} -> reverse-proxy of that Space's sub-paths/assets
14
+
15
+ The proxy is a SERVER-SIDE fetch over the app's shared httpx.AsyncClient (resolved
16
+ lazily from serve.py's module global, like szl_engine_status), NOT a browser CDN load —
17
+ so it satisfies the 0-runtime-CDN doctrine for the same reason a11oy_hf_assets.py states
18
+ (server-side fetch, not a browser CDN). HTML responses get a <base href="/spaces/{name}/">
19
+ injected so the Space's root-relative assets resolve back through this proxy.
20
+
21
+ HONEST DEGRADE: upstream timeout / connect error / unreachable -> a clean 502 page
22
+ ("Space <name> is starting / unreachable — open directly: <hf.space url>"). NEVER a fake
23
+ 200. Hop-by-hop headers are stripped. The proxy is an ALLOWLIST of the known Space names
24
+ only (no open proxy); unknown names -> 404. a11oy is NOT self-proxied (would loop) and
25
+ killinchu is served on its own host — both are listed as TILES (by szl_spaces_surface)
26
+ linking to their canonical hosts, but are NOT in the reverse-proxy allowlist here.
27
+
28
+ No auth token is forwarded to HF — these are PUBLIC Spaces.
29
+
30
+ Routes are inserted at the FRONT of app.router.routes (app.router.routes[0:0] = new)
31
+ so they win over the /api/<ns>/{path:path} Node proxy + the /{full_path:path} SPA
32
+ catch-all (the same route-to-front idiom a11oy_hf_assets.py uses).
33
+
34
+ Doctrine v11: locked-proven = EXACTLY 8 {F1,F4,F7,F11,F12,F18,F19,F22} @ c7c0ba17;
35
+ Λ = Conjecture 1; Khipu = Conjecture 2; trust never 100%; 0 runtime CDN (server-side
36
+ fetch); no user-visible codenames (Space names are their own honest titles); never
37
+ commits a key; additive-only; never weakens a gate; honest 502 beats a fake 200.
38
+
39
+ Signed-off-by: Stephen Lutar <stephenlutar2@gmail.com>
40
+ Co-Authored-By: Perplexity Computer Agent <agent@perplexity.ai>
41
+ """
42
+ from __future__ import annotations
43
+
44
+ import sys
45
+ from typing import Any
46
+
47
+ _ORG_PREFIX = "szlholdings-"
48
+
49
+ # The 11 live Spaces (all RUNNING). app URL pattern: https://szlholdings-<name>.hf.space
50
+ # PROXY allowlist = the names we reverse-proxy under /spaces/<name>. We SKIP:
51
+ # - "a11oy" : self-proxy would loop (a11oy.net IS the a11oy Space).
52
+ # - "killinchu": served on its own host; we link the tile to its host, never proxy it.
53
+ # Both skipped names are still listed as TILES by szl_spaces_surface.
54
+ ALL_SPACES = [
55
+ "immune", "sda", "anatomy", "cathedral", "energy", "yarqa",
56
+ "khipu-constellation", "llm-router-live", "hatun-mcp", "a11oy", "killinchu",
57
+ ]
58
+ # Names we DO reverse-proxy (allowlist). Order preserved for the fallback index.
59
+ PROXY_SPACES = [n for n in ALL_SPACES if n not in ("a11oy", "killinchu")]
60
+
61
+
62
+ def hf_url(name: str) -> str:
63
+ """Canonical HF app URL for a Space name (lowercase, org-prefixed)."""
64
+ return f"https://{_ORG_PREFIX}{name}.hf.space"
65
+
66
+
67
+ # Hop-by-hop headers (RFC 7230 §6.1) — never forwarded across the proxy boundary.
68
+ _HOP_BY_HOP = {
69
+ "connection", "keep-alive", "proxy-authenticate", "proxy-authorization",
70
+ "te", "trailers", "transfer-encoding", "upgrade",
71
+ # content-encoding/length are recomputed by our Response; strip to avoid mismatch.
72
+ "content-encoding", "content-length",
73
+ }
74
+
75
+ _PROXY_TIMEOUT = 8.0 # short timeout — honest 502 beats a hung request.
76
+ _PROXY_RETRIES = 1 # one quick retry on a transient flap before degrading.
77
+ _MAX_BYTES = 25 * 1024 * 1024 # 25MB cap per proxied response (Spaces are light pages).
78
+
79
+
80
+ def _honest_502(name: str) -> bytes:
81
+ """Clean 502 page — NEVER a fake 200. Tells the user to open the Space directly."""
82
+ url = hf_url(name)
83
+ return (
84
+ "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\">"
85
+ "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">"
86
+ "<title>Space %s — starting / unreachable</title></head>"
87
+ "<body style=\"margin:0;background:#0b0f14;color:#cdd6e0;"
88
+ "font:15px/1.6 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;"
89
+ "display:flex;min-height:100vh;align-items:center;justify-content:center\">"
90
+ "<main style=\"max-width:560px;padding:2rem;text-align:center\">"
91
+ "<div style=\"font-size:2.2rem;margin-bottom:.4rem\">&#9889;</div>"
92
+ "<h1 style=\"font-size:1.25rem;margin:0 0 .6rem;color:#e7eef6\">"
93
+ "Space &ldquo;%s&rdquo; is starting or unreachable</h1>"
94
+ "<p style=\"color:#8a96a3;margin:0 0 1.2rem\">The upstream Hugging Face Space did "
95
+ "not respond in time. This is an honest 502 &mdash; not a faked page. "
96
+ "It usually means the Space is waking from sleep; try again shortly.</p>"
97
+ "<p><a href=\"%s\" style=\"color:#d4a444;text-decoration:none;font-weight:600\">"
98
+ "Open %s directly on Hugging Face &rarr;</a></p>"
99
+ "<p style=\"margin-top:1.4rem\"><a href=\"/spaces\" "
100
+ "style=\"color:#7c8794;text-decoration:none\">&larr; All Spaces</a></p>"
101
+ "</main></body></html>" % (name, name, url, name)
102
+ ).encode("utf-8")
103
+
104
+
105
+ def _fallback_index() -> bytes:
106
+ """Minimal honest /spaces index — used ONLY if szl_spaces_surface (the rich tiles
107
+ page) is not registered. Lists every Space name with both links. 0 CDN."""
108
+ rows = []
109
+ for name in ALL_SPACES:
110
+ if name in ("a11oy", "killinchu"):
111
+ local = hf_url(name) # own canonical host (not self-proxied here)
112
+ local_label = "Open on HF"
113
+ else:
114
+ local = "/spaces/%s" % name
115
+ local_label = "Open in a11oy.net"
116
+ rows.append(
117
+ "<li style=\"margin:.4rem 0\"><strong style=\"color:#e7eef6\">%s</strong> "
118
+ "&middot; <a href=\"%s\" style=\"color:#d4a444;text-decoration:none\">%s</a> "
119
+ "&middot; <a href=\"%s\" style=\"color:#7c8794;text-decoration:none\">Open on HF</a>"
120
+ "</li>" % (name, local, local_label, hf_url(name))
121
+ )
122
+ return (
123
+ "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\">"
124
+ "<meta name=\"viewport\" content=\"width=device-width,initial-scale=1\">"
125
+ "<title>Spaces</title></head>"
126
+ "<body style=\"margin:0;background:#0b0f14;color:#cdd6e0;"
127
+ "font:15px/1.6 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;padding:2rem\">"
128
+ "<main style=\"max-width:760px;margin:0 auto\">"
129
+ "<h1 style=\"color:#e7eef6\">Hugging Face Spaces</h1>"
130
+ "<p style=\"color:#8a96a3\">All live Spaces, surfaced under a11oy.net. "
131
+ "Server-side reverse proxy &mdash; 0 browser CDN.</p>"
132
+ "<ul style=\"list-style:none;padding:0\">" + "".join(rows) + "</ul>"
133
+ "</main></body></html>"
134
+ ).encode("utf-8")
135
+
136
+
137
+ def _resolve_client() -> Any:
138
+ """Resolve the app's shared httpx.AsyncClient lazily from serve.py's module global
139
+ (same idiom as szl_engine_status) so registration order doesn't matter."""
140
+ try:
141
+ import serve as _serve # type: ignore
142
+ return getattr(_serve, "_http_client", None)
143
+ except Exception:
144
+ return None
145
+
146
+
147
+ def _rewrite_html(body: bytes, name: str) -> bytes:
148
+ """Inject <base href="/spaces/<name>/"> so the Space's root-relative asset URLs
149
+ (e.g. /assets/app.js, href="/"...) resolve back through this proxy. Idempotent:
150
+ if a base href for this proxy is already present, leave the body untouched."""
151
+ base_tag = ('<base href="/spaces/%s/">' % name).encode("utf-8")
152
+ if base_tag in body:
153
+ return body
154
+ low = body.lower()
155
+ # Prefer to place the <base> right after <head ...> so it applies to all assets.
156
+ h = low.find(b"<head")
157
+ if h != -1:
158
+ gt = body.find(b">", h)
159
+ if gt != -1:
160
+ return body[: gt + 1] + base_tag + body[gt + 1:]
161
+ # No <head> — try right after <html ...>.
162
+ h = low.find(b"<html")
163
+ if h != -1:
164
+ gt = body.find(b">", h)
165
+ if gt != -1:
166
+ return body[: gt + 1] + base_tag + body[gt + 1:]
167
+ # No usable anchor — prepend (still better than broken relative assets).
168
+ return base_tag + body
169
+
170
+
171
+ async def _proxy(name: str, subpath: str, request) -> Any:
172
+ """Reverse-proxy one request to the named Space. Honest 502 on any upstream flap."""
173
+ from starlette.responses import Response
174
+
175
+ if name not in PROXY_SPACES:
176
+ # Not in the allowlist — either unknown, or a deliberately-skipped self/own-host
177
+ # Space. 404 (no open proxy). The skipped ones are reachable as tiles only.
178
+ return Response(content=b"Unknown or non-proxied Space.\n",
179
+ status_code=404, media_type="text/plain")
180
+
181
+ client = _resolve_client()
182
+ if client is None:
183
+ return Response(content=_honest_502(name), status_code=502,
184
+ media_type="text/html")
185
+
186
+ target = hf_url(name) + "/" + subpath
187
+ # Forward only safe request headers (drop Host so httpx sets the upstream host;
188
+ # drop hop-by-hop). No auth token forwarded — public Spaces.
189
+ fwd_headers = {
190
+ k: v for k, v in request.headers.items()
191
+ if k.lower() not in _HOP_BY_HOP and k.lower() not in ("host", "cookie")
192
+ }
193
+ method = request.method.upper()
194
+
195
+ upstream = None
196
+ last_exc = None
197
+ for _attempt in range(_PROXY_RETRIES + 1):
198
+ try:
199
+ upstream = await client.request(
200
+ method, target, headers=fwd_headers,
201
+ timeout=_PROXY_TIMEOUT, follow_redirects=True,
202
+ )
203
+ break
204
+ except Exception as e: # connect error / timeout / read error -> honest degrade
205
+ last_exc = e
206
+ upstream = None
207
+
208
+ if upstream is None:
209
+ print("[spaces-proxy] upstream flap for %s: %r" % (name, last_exc),
210
+ file=sys.stderr)
211
+ return Response(content=_honest_502(name), status_code=502,
212
+ media_type="text/html")
213
+
214
+ ct = (upstream.headers.get("content-type") or "").lower()
215
+ body = upstream.content or b""
216
+ if len(body) > _MAX_BYTES:
217
+ body = body[:_MAX_BYTES]
218
+
219
+ # HTML: inject <base href> so assets resolve under /spaces/<name>/.
220
+ if "text/html" in ct:
221
+ body = _rewrite_html(body, name)
222
+
223
+ out_headers = {
224
+ k: v for k, v in upstream.headers.items()
225
+ if k.lower() not in _HOP_BY_HOP
226
+ }
227
+ # HEAD must carry no body.
228
+ if method == "HEAD":
229
+ body = b""
230
+
231
+ return Response(content=body, status_code=upstream.status_code,
232
+ headers=out_headers,
233
+ media_type=upstream.headers.get("content-type"))
234
+
235
+
236
+ def register(app, ns: str = "a11oy") -> str:
237
+ """ADDITIVE: mount the /spaces reverse-proxy routes at the FRONT of the router so
238
+ they beat the SPA + Node-proxy catch-alls. try/except-guarded by the caller."""
239
+ try:
240
+ from starlette.responses import Response
241
+ except Exception as e: # pragma: no cover
242
+ return "unavailable: %r" % (e,)
243
+
244
+ n_before = len(app.router.routes)
245
+
246
+ async def _spaces_index(request):
247
+ # Delegate the rich tiles page to szl_spaces_surface if it owns /spaces; this
248
+ # fallback index only renders if that module isn't present. Idempotent: this
249
+ # route is inserted only once per register() and register() is guarded upstream.
250
+ if request.method.upper() == "HEAD":
251
+ return Response(content=b"", status_code=200, media_type="text/html")
252
+ return Response(content=_fallback_index(), status_code=200,
253
+ media_type="text/html")
254
+
255
+ async def _spaces_name(request):
256
+ name = request.path_params.get("name", "")
257
+ return await _proxy(name, "", request)
258
+
259
+ async def _spaces_path(request):
260
+ name = request.path_params.get("name", "")
261
+ subpath = request.path_params.get("path", "")
262
+ return await _proxy(name, subpath, request)
263
+
264
+ from starlette.routing import Route
265
+ # NOTE: szl_spaces_surface registers its OWN richer /spaces tiles page and inserts
266
+ # it at the front AFTER this module (it's registered second in serve.py), so the
267
+ # tiles page wins over this fallback index — by design. Both are idempotent.
268
+ routes = [
269
+ Route("/spaces", _spaces_index, methods=["GET", "HEAD"]),
270
+ Route("/spaces/{name}", _spaces_name, methods=["GET", "HEAD"]),
271
+ Route("/spaces/{name}/{path:path}", _spaces_path, methods=["GET", "HEAD"]),
272
+ ]
273
+ for r in routes:
274
+ app.router.routes.append(r)
275
+
276
+ new = app.router.routes[n_before:]
277
+ del app.router.routes[n_before:]
278
+ app.router.routes[0:0] = new
279
+ print("[%s] Spaces reverse-proxy registered: /spaces + /spaces/{name} + "
280
+ "/spaces/{name}/{path} (%d proxied: %s) [moved %d routes to front]"
281
+ % (ns, len(PROXY_SPACES), ",".join(PROXY_SPACES), len(new)), file=sys.stderr)
282
+ return "ok: %d proxied spaces, %d routes" % (len(PROXY_SPACES), len(new))
283
+
284
+
285
+ # ---------------------------------------------------------------------------
286
+ # Self-test — pure stdlib + starlette TestClient; no real network. Stubs the shared
287
+ # client to assert: allowlist enforced (unknown -> 404), honest 502 on a dead client,
288
+ # <base href> injection, HEAD carries no body, and the fallback index lists all 11.
289
+ # ---------------------------------------------------------------------------
290
+ if __name__ == "__main__":
291
+ import ast as _ast
292
+ # parse-self guard
293
+ with open(__file__, "r", encoding="utf-8") as _fh:
294
+ _ast.parse(_fh.read())
295
+
296
+ # base-href injection
297
+ out = _rewrite_html(b"<html><head><title>x</title></head><body>hi</body></html>", "immune")
298
+ assert b'<base href="/spaces/immune/">' in out, "must inject base href"
299
+ assert _rewrite_html(out, "immune") == out, "base href injection must be idempotent"
300
+
301
+ # honest 502 content
302
+ p = _honest_502("sda")
303
+ assert b"honest 502" in p and b"szlholdings-sda.hf.space" in p, "502 must be honest + direct link"
304
+
305
+ # allowlist
306
+ assert "a11oy" not in PROXY_SPACES and "killinchu" not in PROXY_SPACES, "self/own-host skipped"
307
+ assert len(ALL_SPACES) == 11 and len(PROXY_SPACES) == 9, (len(ALL_SPACES), len(PROXY_SPACES))
308
+
309
+ # fallback index lists all 11 names
310
+ idx = _fallback_index()
311
+ for nm in ALL_SPACES:
312
+ assert nm.encode() in idx, "index missing %s" % nm
313
+
314
+ from starlette.applications import Starlette
315
+ from starlette.responses import PlainTextResponse
316
+ from starlette.routing import Route as _R
317
+ from starlette.testclient import TestClient
318
+
319
+ a = Starlette(routes=[_R("/{full_path:path}", lambda req: PlainTextResponse("SPA"))])
320
+ st = register(a, ns="a11oy")
321
+ assert st.startswith("ok:"), st
322
+ c = TestClient(a)
323
+ # /spaces fallback index resolves before the SPA catch-all and lists all names
324
+ r = c.get("/spaces")
325
+ assert r.status_code == 200 and "immune" in r.text and "killinchu" in r.text, r.status_code
326
+ # unknown / non-proxied name -> 404 (no open proxy); a11oy is deliberately skipped
327
+ assert c.get("/spaces/a11oy").status_code == 404, "a11oy must not be self-proxied"
328
+ assert c.get("/spaces/notreal").status_code == 404, "unknown -> 404"
329
+ # known name with no shared client wired -> honest 502 (never fake 200)
330
+ r502 = c.get("/spaces/immune")
331
+ assert r502.status_code == 502 and "honest 502" in r502.text, (r502.status_code, r502.text[:80])
332
+ # HEAD on a known name -> still 502 here (no client) but no body
333
+ rh = c.head("/spaces/immune")
334
+ assert rh.status_code == 502, rh.status_code
335
+
336
+ print("szl_spaces_proxy: ALL OK (allowlist; honest 502; base-href idempotent; "
337
+ "%d proxied of %d; 0 CDN server-side fetch)" % (len(PROXY_SPACES), len(ALL_SPACES)))
szl_spaces_surface.py ADDED
@@ -0,0 +1,473 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ # © 2026 Lutar, Stephen P. — SZL Holdings · ORCID 0009-0001-0110-4173
4
+ """szl_spaces_surface.py — console "Spaces" surface (health API + tiles + nav).
5
+
6
+ ADDITIVE, self-contained, SHARED (byte-identical in a11oy + killinchu). The console
7
+ companion to szl_spaces_proxy: a LIVE health view of the whole HF Spaces estate plus a
8
+ clean tiles page and ONE idempotent nav item, following the additive-injector pattern
9
+ (a11oy_nav_wireup.py / killinchu_nav_wireup.py).
10
+
11
+ ROUTES (additive, inserted at the FRONT of the router so they beat the SPA + Node-proxy
12
+ catch-alls — same route-to-front idiom as a11oy_hf_assets.py):
13
+
14
+ GET /api/<ns>/v1/spaces/health -> for each Space, an HONEST status:
15
+ {name, title, stage, app_reachable, url, proxy_url}
16
+ - stage : runtime.stage from the HF API
17
+ (https://huggingface.co/api/spaces/SZLHOLDINGS/<name>),
18
+ or "unknown" if that API call degrades. LABELLED as HF-API.
19
+ - app_reachable : a REAL same-origin server-side probe of
20
+ https://szlholdings-<name>.hf.space/ (HEAD, short timeout).
21
+ true ONLY when the probe really succeeded. Never fabricated.
22
+ Degrade -> stage:"unknown", app_reachable:false. NEVER a faked stage/200.
23
+
24
+ GET/HEAD /spaces -> a clean tiles page (one card per Space: honest
25
+ title, live status dot fed by /health, "Open in a11oy.net" -> /spaces/<name>,
26
+ "Open on HF" -> hf.space url). Pure inline markup, 0 browser CDN. The status
27
+ dots are filled by a tiny inline fetch of the SAME-ORIGIN /health JSON (not a
28
+ CDN; the data is our own server-side-probed endpoint).
29
+
30
+ NAV: a BaseHTTPMiddleware injector adds ONE nav item "Spaces" -> /spaces into the
31
+ console left-nav (before <div class="side-foot">, with nav-group / nav-item fallbacks).
32
+ Idempotent — keyed by data-attribute data-nav-spaces="hf1"; removes NOTHING from the SPA
33
+ source; never touches /api, /v1, /assets, /static, /vendor responses. Works identically
34
+ on the a11oy /console and killinchu /elite consoles (same sidebar markup) — which is why
35
+ this module can be byte-identical in both apps.
36
+
37
+ The /spaces probe + HF-API call are SERVER-SIDE fetches (resolve the shared httpx client
38
+ lazily from serve.py, like szl_engine_status) — 0 runtime CDN, same justification as
39
+ a11oy_hf_assets.py. No auth token forwarded to HF (public Spaces / public API).
40
+
41
+ Doctrine v11: locked-proven = EXACTLY 8 {F1,F4,F7,F11,F12,F18,F19,F22} @ c7c0ba17;
42
+ Λ = Conjecture 1; Khipu = Conjecture 2; trust never 100%; 0 runtime CDN; no user-visible
43
+ codenames (Space names are their own honest titles); never commits a key; additive-only;
44
+ honest "unknown"/false beats a fabricated stage.
45
+
46
+ Signed-off-by: Stephen Lutar <stephenlutar2@gmail.com>
47
+ Co-Authored-By: Perplexity Computer Agent <agent@perplexity.ai>
48
+ """
49
+ from __future__ import annotations
50
+
51
+ import sys
52
+ import time
53
+ from typing import Any
54
+
55
+ _ORG = "SZLHOLDINGS"
56
+ _ORG_PREFIX = "szlholdings-"
57
+
58
+ # The 11 live Spaces + their honest, public titles (NOT codenames — each Space's own
59
+ # name). a11oy + killinchu are listed as tiles linking to their own canonical hosts;
60
+ # they are NOT reverse-proxied by szl_spaces_proxy (self / own-host).
61
+ SPACES: list[dict[str, str]] = [
62
+ {"name": "immune", "title": "Immune — Verifiable Screening"},
63
+ {"name": "sda", "title": "SDA — Space Domain Awareness"},
64
+ {"name": "anatomy", "title": "Anatomy — Canonical Formula Registry"},
65
+ {"name": "cathedral", "title": "Cathedral — Estate Cathedral"},
66
+ {"name": "energy", "title": "Energy — Sovereign Compute"},
67
+ {"name": "yarqa", "title": "Yarqa — Data Channel"},
68
+ {"name": "khipu-constellation", "title": "Khipu Constellation — Receipt Mesh"},
69
+ {"name": "llm-router-live", "title": "LLM Router (Live)"},
70
+ {"name": "hatun-mcp", "title": "Hatun — MCP Server"},
71
+ {"name": "a11oy", "title": "a11oy — Brand Orchestration Layer"},
72
+ {"name": "killinchu", "title": "Killinchu — Edge Console"},
73
+ ]
74
+ # Spaces served on their OWN canonical host (not reverse-proxied here): the tile's
75
+ # primary "open" link points at HF rather than /spaces/<name>.
76
+ _OWN_HOST = {"a11oy", "killinchu"}
77
+
78
+ _DOCTRINE = {
79
+ "version": "v11",
80
+ "lambda": "Conjecture 1",
81
+ "khipu": "Conjecture 2",
82
+ "locked_proven": ["F1", "F4", "F7", "F11", "F12", "F18", "F19", "F22"],
83
+ "trust_ceiling": "never 100%",
84
+ }
85
+
86
+ _PROBE_TIMEOUT = 6.0
87
+ _HF_API_TIMEOUT = 6.0
88
+ _HEALTH_CACHE_TTL = 20.0 # seconds — keep the tiles page snappy without re-probing 11x.
89
+ _HEALTH_CACHE: dict[str, Any] = {"ts": 0.0, "payload": None}
90
+
91
+
92
+ def hf_url(name: str) -> str:
93
+ return f"https://{_ORG_PREFIX}{name}.hf.space"
94
+
95
+
96
+ def hf_api_url(name: str) -> str:
97
+ return f"https://huggingface.co/api/spaces/{_ORG}/{name}"
98
+
99
+
100
+ def proxy_url(name: str) -> str:
101
+ """Where the tile's primary "open" link points. Own-host Spaces -> their HF host;
102
+ everyone else -> the same-origin reverse proxy at /spaces/<name>."""
103
+ return hf_url(name) if name in _OWN_HOST else f"/spaces/{name}"
104
+
105
+
106
+ def _resolve_client() -> Any:
107
+ """Lazily resolve the app's shared httpx.AsyncClient from serve.py (same idiom as
108
+ szl_engine_status), so registration order doesn't matter."""
109
+ try:
110
+ import serve as _serve # type: ignore
111
+ return getattr(_serve, "_http_client", None)
112
+ except Exception:
113
+ return None
114
+
115
+
116
+ async def _probe_one(client: Any, sp: dict[str, str]) -> dict[str, Any]:
117
+ """HONEST per-Space status. app_reachable is a REAL HEAD probe; stage is from the
118
+ HF API. Any failure degrades to honest false/'unknown' — never fabricated."""
119
+ name = sp["name"]
120
+ result: dict[str, Any] = {
121
+ "name": name,
122
+ "title": sp["title"],
123
+ "url": hf_url(name),
124
+ "proxy_url": proxy_url(name),
125
+ "own_host": name in _OWN_HOST,
126
+ "stage": "unknown", # from HF API; HF-API-labelled below
127
+ "stage_source": "hf-api",
128
+ "app_reachable": False, # REAL probe; only true when the probe truly succeeds
129
+ }
130
+ if client is None:
131
+ result["note"] = "no http client; honest degrade"
132
+ return result
133
+
134
+ # (1) REAL same-origin liveness probe of the Space app (HEAD; fall back to tiny GET).
135
+ try:
136
+ r = await client.request("HEAD", hf_url(name) + "/",
137
+ timeout=_PROBE_TIMEOUT, follow_redirects=True)
138
+ result["app_reachable"] = bool(r.status_code < 500)
139
+ result["app_status"] = r.status_code
140
+ except Exception:
141
+ try:
142
+ r = await client.get(hf_url(name) + "/", timeout=_PROBE_TIMEOUT,
143
+ follow_redirects=True)
144
+ result["app_reachable"] = bool(r.status_code < 500)
145
+ result["app_status"] = r.status_code
146
+ except Exception as e:
147
+ result["app_reachable"] = False
148
+ result["probe_error"] = type(e).__name__
149
+
150
+ # (2) HF API runtime.stage (public API, no token). Honest "unknown" on any failure.
151
+ try:
152
+ ra = await client.get(hf_api_url(name), timeout=_HF_API_TIMEOUT,
153
+ headers={"User-Agent": "szl-spaces-surface/1.0"})
154
+ if ra.status_code == 200:
155
+ data = ra.json()
156
+ stage = (((data or {}).get("runtime") or {}).get("stage"))
157
+ if isinstance(stage, str) and stage:
158
+ result["stage"] = stage
159
+ else:
160
+ result["stage_http"] = ra.status_code
161
+ except Exception as e:
162
+ result["stage_error"] = type(e).__name__
163
+
164
+ return result
165
+
166
+
167
+ async def spaces_health() -> dict[str, Any]:
168
+ """Aggregate honest health for all 11 Spaces (short TTL cache)."""
169
+ now = time.monotonic()
170
+ if _HEALTH_CACHE["payload"] is not None and (now - _HEALTH_CACHE["ts"]) < _HEALTH_CACHE_TTL:
171
+ return _HEALTH_CACHE["payload"]
172
+
173
+ client = _resolve_client()
174
+ spaces: list[dict[str, Any]] = []
175
+ if client is None:
176
+ for sp in SPACES:
177
+ spaces.append({
178
+ "name": sp["name"], "title": sp["title"], "url": hf_url(sp["name"]),
179
+ "proxy_url": proxy_url(sp["name"]), "own_host": sp["name"] in _OWN_HOST,
180
+ "stage": "unknown", "stage_source": "hf-api", "app_reachable": False,
181
+ "note": "no http client; honest degrade",
182
+ })
183
+ else:
184
+ import asyncio as _asyncio
185
+ spaces = await _asyncio.gather(*[_probe_one(client, sp) for sp in SPACES])
186
+ spaces = list(spaces)
187
+
188
+ payload = {
189
+ "count": len(spaces),
190
+ "spaces": spaces,
191
+ "labels": {
192
+ "stage": "HF API runtime.stage (https://huggingface.co/api/spaces/SZLHOLDINGS/<name>)",
193
+ "app_reachable": "REAL same-origin server-side HEAD/GET probe of the Space app",
194
+ "degrade": "stage:'unknown' + app_reachable:false; never fabricated",
195
+ },
196
+ "note": "Server-side probed; 0 browser CDN. Honest live/unknown only.",
197
+ "doctrine": _DOCTRINE,
198
+ "fetchedAt": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
199
+ }
200
+ _HEALTH_CACHE["payload"] = payload
201
+ _HEALTH_CACHE["ts"] = now
202
+ return payload
203
+
204
+
205
+ # ---------------------------------------------------------------------------
206
+ # Tiles page — pure inline markup, 0 CDN. Status dots are filled by a tiny inline
207
+ # fetch of the SAME-ORIGIN /api/<ns>/v1/spaces/health (our own server-side-probed
208
+ # endpoint, not a CDN). Cards are pre-rendered so the page is useful even with JS off.
209
+ # ---------------------------------------------------------------------------
210
+ def _tiles_page(ns: str) -> bytes:
211
+ cards = []
212
+ for sp in SPACES:
213
+ name = sp["name"]
214
+ title = sp["title"]
215
+ primary = proxy_url(name)
216
+ primary_label = "Open on HF" if name in _OWN_HOST else "Open in a11oy.net"
217
+ cards.append(
218
+ '<article class="sp-card" data-space="%s">'
219
+ '<header class="sp-head">'
220
+ '<span class="sp-dot" data-dot="%s" title="status">&#9679;</span>'
221
+ '<h2 class="sp-title">%s</h2></header>'
222
+ '<div class="sp-stage" data-stage="%s">stage: <span>checking&hellip;</span></div>'
223
+ '<div class="sp-links">'
224
+ '<a class="sp-open" href="%s">%s</a>'
225
+ '<a class="sp-hf" href="%s" rel="noopener" target="_blank">Open on HF &#8599;</a>'
226
+ '</div></article>'
227
+ % (name, name, title, name, primary, primary_label, hf_url(name))
228
+ )
229
+ html = (
230
+ '<!doctype html><html lang="en"><head><meta charset="utf-8">'
231
+ '<meta name="viewport" content="width=device-width,initial-scale=1">'
232
+ '<title>Spaces &middot; a11oy</title>'
233
+ '<style>'
234
+ ':root{color-scheme:dark}'
235
+ '*{box-sizing:border-box}'
236
+ 'body{margin:0;background:#0b0f14;color:#cdd6e0;'
237
+ 'font:15px/1.6 system-ui,-apple-system,Segoe UI,Roboto,sans-serif}'
238
+ '.sp-wrap{max-width:1100px;margin:0 auto;padding:2rem 1.25rem}'
239
+ '.sp-h1{color:#e7eef6;font-size:1.6rem;margin:0 0 .25rem}'
240
+ '.sp-sub{color:#8a96a3;margin:0 0 1.6rem}'
241
+ '.sp-grid{display:grid;gap:1rem;'
242
+ 'grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}'
243
+ '.sp-card{background:#121821;border:1px solid #1d2632;border-radius:12px;'
244
+ 'padding:1rem 1.1rem;display:flex;flex-direction:column;gap:.5rem}'
245
+ '.sp-head{display:flex;align-items:center;gap:.55rem}'
246
+ '.sp-dot{color:#5b6675;font-size:.7rem;line-height:1}'
247
+ '.sp-dot.up{color:#3ad07a}.sp-dot.down{color:#e0593a}.sp-dot.unknown{color:#c9a23a}'
248
+ '.sp-title{font-size:1rem;margin:0;color:#e7eef6;font-weight:600}'
249
+ '.sp-stage{color:#7c8794;font-size:.82rem}'
250
+ '.sp-stage span{color:#9fb0c0}'
251
+ '.sp-links{margin-top:auto;display:flex;gap:.9rem;flex-wrap:wrap;padding-top:.4rem}'
252
+ '.sp-open{color:#d4a444;text-decoration:none;font-weight:600}'
253
+ '.sp-hf{color:#7c8794;text-decoration:none}'
254
+ '.sp-foot{color:#5b6675;font-size:.8rem;margin-top:1.6rem}'
255
+ '</style></head>'
256
+ '<body><main class="sp-wrap">'
257
+ '<h1 class="sp-h1">Hugging Face Spaces</h1>'
258
+ '<p class="sp-sub">All live Spaces, surfaced on a11oy.net &mdash; server-side '
259
+ 'reverse proxy + honest live health. 0 browser CDN.</p>'
260
+ '<div class="sp-grid">' + "".join(cards) + '</div>'
261
+ '<p class="sp-foot">Status dot &amp; stage are filled from the same-origin '
262
+ '<code>/api/' + ns + '/v1/spaces/health</code> endpoint (real server-side probe '
263
+ '+ HF API). Honest: a grey/amber dot means starting or unknown, never a faked up.</p>'
264
+ '</main>'
265
+ '<script>'
266
+ '(function(){'
267
+ 'fetch("/api/' + ns + '/v1/spaces/health").then(function(r){return r.json();})'
268
+ '.then(function(d){(d.spaces||[]).forEach(function(s){'
269
+ 'var card=document.querySelector(\'[data-space="\'+s.name+\'"]\');if(!card)return;'
270
+ 'var dot=card.querySelector(".sp-dot");'
271
+ 'if(dot){dot.classList.remove("up","down","unknown");'
272
+ 'dot.classList.add(s.app_reachable?"up":(s.stage&&s.stage!=="unknown"?"unknown":"down"));'
273
+ 'dot.title=(s.app_reachable?"reachable":"unreachable")+" / stage:"+(s.stage||"unknown");}'
274
+ 'var st=card.querySelector(".sp-stage span");'
275
+ 'if(st){st.textContent=(s.stage||"unknown")+(s.app_reachable?" \\u00b7 reachable":" \\u00b7 unreachable");}'
276
+ '});}).catch(function(){});'
277
+ '})();'
278
+ '</script>'
279
+ '</body></html>'
280
+ )
281
+ return html.encode("utf-8")
282
+
283
+
284
+ # ---------------------------------------------------------------------------
285
+ # Nav injector — ONE "Spaces" nav item into the console left-nav. Same additive,
286
+ # idempotent BaseHTTPMiddleware idiom as a11oy_nav_wireup / killinchu_nav_wireup.
287
+ # ---------------------------------------------------------------------------
288
+ _NAV_MARKER = b'data-nav-spaces="hf1"'
289
+ _FOOT_ANCHOR = b'<div class="side-foot">'
290
+ _GROUP_ANCHOR = b'<div class="nav-group">'
291
+ _NAVITEM_ANCHOR = b'<div class="nav-item"'
292
+
293
+
294
+ def _nav_item() -> bytes:
295
+ """ONE 'Spaces' nav item, mirroring the console's own nav-item markup so it inherits
296
+ the console styling (0 CDN, 0 codename). Globe glyph; honest label."""
297
+ return (
298
+ '<div class="nav-item" data-nav-spaces="hf1" data-wireup-path="/spaces" '
299
+ 'onclick="location.href=\'/spaces\'" style="cursor:pointer">'
300
+ '<span class="ico">\U0001F310</span>Spaces</div>'
301
+ ).encode("utf-8")
302
+
303
+
304
+ def _make_injector():
305
+ from starlette.middleware.base import BaseHTTPMiddleware
306
+ from starlette.responses import Response
307
+
308
+ nav_item = _nav_item()
309
+
310
+ class _SpacesNavInjector(BaseHTTPMiddleware):
311
+ async def dispatch(self, request, call_next):
312
+ resp = await call_next(request)
313
+ try:
314
+ ct = (resp.headers.get("content-type") or "").lower()
315
+ if "text/html" not in ct:
316
+ return resp
317
+ p = request.url.path
318
+ if (p.startswith("/api/") or p.startswith("/v1/")
319
+ or p.startswith("/vendor/") or p.startswith("/assets/")
320
+ or p.startswith("/static/")):
321
+ return resp
322
+ # The /spaces tiles page IS our own page; don't inject the sidebar nav
323
+ # into it (it has no console sidebar). Cheap guard — also keeps it idempotent.
324
+ if p == "/spaces" or p.startswith("/spaces/"):
325
+ return resp
326
+
327
+ body = b""
328
+ async for chunk in resp.body_iterator:
329
+ body += chunk if isinstance(chunk, (bytes, bytearray)) else str(chunk).encode()
330
+
331
+ if _NAV_MARKER not in body:
332
+ if _FOOT_ANCHOR in body:
333
+ body = body.replace(_FOOT_ANCHOR, nav_item + _FOOT_ANCHOR, 1)
334
+ elif _NAVITEM_ANCHOR in body:
335
+ # No footer found, but a nav exists -> place after the first
336
+ # nav-item div so 'Spaces' still lands in the nav.
337
+ start = body.find(_NAVITEM_ANCHOR)
338
+ end = body.find(b"</div>", start)
339
+ if end != -1:
340
+ end += len(b"</div>")
341
+ body = body[:end] + nav_item + body[end:]
342
+ elif _GROUP_ANCHOR in body:
343
+ body = body.replace(_GROUP_ANCHOR, _GROUP_ANCHOR + nav_item, 1)
344
+
345
+ # body_iterator is consumed — MUST rebuild the Response even if unchanged,
346
+ # else downstream sees an empty body (white screen).
347
+ headers = dict(resp.headers)
348
+ headers.pop("content-length", None)
349
+ return Response(content=body, status_code=resp.status_code,
350
+ headers=headers, media_type="text/html")
351
+ except Exception:
352
+ return resp
353
+
354
+ return _SpacesNavInjector
355
+
356
+
357
+ def register(app, ns: str = "a11oy") -> str:
358
+ """ADDITIVE: mount GET /api/<ns>/v1/spaces/health + GET/HEAD /spaces (rich tiles)
359
+ at the FRONT of the router (beat the SPA + Node-proxy catch-alls), and attach the
360
+ idempotent 'Spaces' nav injector. try/except-guarded by the caller."""
361
+ try:
362
+ from fastapi.responses import JSONResponse # noqa: F401
363
+ from starlette.responses import Response, JSONResponse as _JSON
364
+ except Exception as e: # pragma: no cover
365
+ return "unavailable: %r" % (e,)
366
+
367
+ n_before = len(app.router.routes)
368
+ tiles = _tiles_page(ns)
369
+
370
+ async def _health(request):
371
+ payload = await spaces_health()
372
+ return _JSON(payload)
373
+
374
+ async def _tiles(request):
375
+ if request.method.upper() == "HEAD":
376
+ return Response(content=b"", status_code=200, media_type="text/html")
377
+ return Response(content=tiles, status_code=200, media_type="text/html")
378
+
379
+ from starlette.routing import Route
380
+ routes = [
381
+ Route("/api/%s/v1/spaces/health" % ns, _health, methods=["GET"]),
382
+ # The rich tiles page OWNS /spaces (wins over szl_spaces_proxy's fallback index
383
+ # because this module is registered SECOND and front-inserts after it).
384
+ Route("/spaces", _tiles, methods=["GET", "HEAD"]),
385
+ ]
386
+ for r in routes:
387
+ app.router.routes.append(r)
388
+
389
+ new = app.router.routes[n_before:]
390
+ del app.router.routes[n_before:]
391
+ app.router.routes[0:0] = new
392
+
393
+ app.add_middleware(_make_injector())
394
+
395
+ print("[%s] Spaces surface registered: /api/%s/v1/spaces/health + /spaces (tiles, "
396
+ "%d spaces) + nav injector [moved %d routes to front]"
397
+ % (ns, ns, len(SPACES), len(new)), file=sys.stderr)
398
+ return "ok: %d spaces, health + tiles + nav, %d routes" % (len(SPACES), len(new))
399
+
400
+
401
+ # ---------------------------------------------------------------------------
402
+ # Self-test — pure stdlib + starlette TestClient; no real network. Stubs the shared
403
+ # client to assert: health degrades honestly (no client -> stage unknown + reachable
404
+ # false), tiles page lists ALL 11 names + has the health-fetch JS, nav injects exactly
405
+ # once + is idempotent + removes nothing, /spaces is NOT nav-injected.
406
+ # ---------------------------------------------------------------------------
407
+ if __name__ == "__main__":
408
+ import ast as _ast
409
+ with open(__file__, "r", encoding="utf-8") as _fh:
410
+ _ast.parse(_fh.read())
411
+
412
+ assert len(SPACES) == 11, len(SPACES)
413
+ tp = _tiles_page("a11oy")
414
+ for sp in SPACES:
415
+ assert sp["name"].encode() in tp, "tiles missing %s" % sp["name"]
416
+ assert sp["title"].encode() in tp, "tiles missing title %s" % sp["title"]
417
+ assert b"/api/a11oy/v1/spaces/health" in tp, "tiles must fetch the health endpoint"
418
+ assert b"http://" not in tp, "tiles must be 0 CDN (no http://)"
419
+ # the only https in the page should be the hf.space open links (server-named, fine)
420
+ assert tp.count(b"https://huggingface.co") == 0, "tiles must not pull from HF CDN"
421
+
422
+ from starlette.applications import Starlette
423
+ from starlette.responses import HTMLResponse, PlainTextResponse
424
+ from starlette.routing import Route as _R
425
+ from starlette.testclient import TestClient
426
+
427
+ SAMPLE_CONSOLE = (
428
+ '<html><body><aside>'
429
+ '<div class="nav-group">Operate</div>'
430
+ '<div class="nav-item" data-view="x" onclick="go(\'x\')">'
431
+ '<span class="ico">+</span>Existing</div>'
432
+ '<div class="side-foot">footer</div>'
433
+ '</aside></body></html>'
434
+ )
435
+
436
+ async def _console(req):
437
+ return HTMLResponse(SAMPLE_CONSOLE)
438
+
439
+ app = Starlette(routes=[
440
+ _R("/console", _console),
441
+ _R("/{full_path:path}", lambda req: PlainTextResponse("SPA")),
442
+ ])
443
+ st = register(app, ns="a11oy")
444
+ assert st.startswith("ok:"), st
445
+ c = TestClient(app)
446
+
447
+ # health: no client wired -> honest degrade for all 11
448
+ h = c.get("/api/a11oy/v1/spaces/health").json()
449
+ assert h["count"] == 11, h["count"]
450
+ assert all(s["stage"] == "unknown" and s["app_reachable"] is False for s in h["spaces"]), \
451
+ "no client must degrade to unknown/false (never fabricated)"
452
+ assert h["doctrine"]["locked_proven"] == ["F1", "F4", "F7", "F11", "F12", "F18", "F19", "F22"]
453
+
454
+ # tiles page resolves + lists all names
455
+ t = c.get("/spaces")
456
+ assert t.status_code == 200 and "text/html" in t.headers["content-type"], t.status_code
457
+ for sp in SPACES:
458
+ assert sp["name"] in t.text, "tiles page missing %s" % sp["name"]
459
+
460
+ # nav injects exactly once + idempotent + removes nothing
461
+ p1 = c.get("/console").text
462
+ p2 = c.get("/console").text
463
+ assert p1.count('data-nav-spaces="hf1"') == 1, "nav must inject exactly once"
464
+ assert p2.count('data-nav-spaces="hf1"') == 1, "nav must be idempotent"
465
+ assert "location.href='/spaces'" in p1, "nav must link /spaces"
466
+ assert "Operate</div>" in p1 and "Existing</div>" in p1 and "footer</div>" in p1, \
467
+ "must remove nothing from the SPA source"
468
+ assert p1 == p2, "second console render must be byte-identical (idempotent)"
469
+ # the tiles page itself must NOT be nav-injected (it has no console sidebar)
470
+ assert 'data-nav-spaces="hf1"' not in c.get("/spaces").text, "/spaces must not be nav-injected"
471
+
472
+ print("szl_spaces_surface: ALL OK (11 spaces; honest degrade; tiles 0-CDN; nav "
473
+ "idempotent + additive; /spaces not self-injected)")