Spaces:
Running
Running
deploy(hf): sync szl-holdings/a11oy@88a286749ffeafc466b438f36fbbb3ba755a1e41 derived COPY set
Browse filesReusable Dockerfile-COPY-derived deploy from szl-holdings/a11oy 88a286749ffeafc466b438f36fbbb3ba755a1e41.
Files: 1186 Pruned: 0
Derived from Dockerfile COPY sources (NO hand-maintained allowlist).
Signed-off-by: SZL Holdings <noreply@szlholdings.ai>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- routers/__init__.py +5 -0
- routers/frontier_now_control_plane.py +621 -0
- routers/frontier_now_web/app.js +356 -0
- routers/frontier_now_web/index.html +179 -0
- routers/frontier_now_web/styles.css +466 -0
- routers/frontier_reads.py +19 -1
routers/__init__.py
CHANGED
|
@@ -24,6 +24,10 @@ Action Passports, signed receipts, and bounded one-attempt effectors. It is expo
|
|
| 24 |
here so invocation and package-integrity checks can prove the production module is
|
| 25 |
intentional rather than an orphaned source file.
|
| 26 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
The package top-level name is `routers` (not szl_*/a11oy_*), so it is intentionally
|
| 28 |
OUTSIDE the guarded-import-liveness first-party scan — and the files exist anyway.
|
| 29 |
|
|
@@ -34,5 +38,6 @@ __all__ = [
|
|
| 34 |
"lambda_bounty",
|
| 35 |
"research_3d",
|
| 36 |
"frontier_reads",
|
|
|
|
| 37 |
"series_a_control_plane",
|
| 38 |
]
|
|
|
|
| 24 |
here so invocation and package-integrity checks can prove the production module is
|
| 25 |
intentional rather than an orphaned source file.
|
| 26 |
|
| 27 |
+
`frontier_now_control_plane` is an additive GET/HEAD-only projection over that
|
| 28 |
+
existing Series-A seam. It intentionally owns no database, signer, credentials,
|
| 29 |
+
scheduler, passport authority, or effectors.
|
| 30 |
+
|
| 31 |
The package top-level name is `routers` (not szl_*/a11oy_*), so it is intentionally
|
| 32 |
OUTSIDE the guarded-import-liveness first-party scan — and the files exist anyway.
|
| 33 |
|
|
|
|
| 38 |
"lambda_bounty",
|
| 39 |
"research_3d",
|
| 40 |
"frontier_reads",
|
| 41 |
+
"frontier_now_control_plane",
|
| 42 |
"series_a_control_plane",
|
| 43 |
]
|
routers/frontier_now_control_plane.py
ADDED
|
@@ -0,0 +1,621 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 3 |
+
# (c) 2026 Lutar, Stephen P. - SZL Holdings - ORCID 0009-0001-0110-4173
|
| 4 |
+
"""Read-only Frontier Now projection over the existing Series-A service.
|
| 5 |
+
|
| 6 |
+
This module is intentionally not a second control authority. It owns no provider
|
| 7 |
+
credential, database, signer, receipt chain, scheduler, or effector. Every GET and
|
| 8 |
+
HEAD is a bounded projection of ``app.state.szl_series_a_service``. Missing or
|
| 9 |
+
stale evidence remains visible as UNAVAILABLE/STALE and public claims stay held
|
| 10 |
+
until an exact source-to-runtime binding is observed elsewhere.
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
import hashlib
|
| 14 |
+
import json
|
| 15 |
+
from datetime import datetime, timezone
|
| 16 |
+
from pathlib import Path
|
| 17 |
+
from typing import Any, Callable, Mapping
|
| 18 |
+
|
| 19 |
+
from fastapi import FastAPI, HTTPException, Request
|
| 20 |
+
from fastapi.responses import HTMLResponse, JSONResponse, Response
|
| 21 |
+
|
| 22 |
+
SCHEMA_SUMMARY = "szl.frontier-now-summary/v1"
|
| 23 |
+
SCHEMA_INVENTORY = "szl.frontier-now-inventory/v1"
|
| 24 |
+
OPERATING_MODE = "OBSERVE_ONLY"
|
| 25 |
+
MAX_INVENTORY_LIMIT = 50
|
| 26 |
+
PROVIDERS = {"all", "github", "huggingface", "runtime", "web"}
|
| 27 |
+
NO_STORE_HEADERS = {
|
| 28 |
+
"cache-control": "no-store",
|
| 29 |
+
"x-content-type-options": "nosniff",
|
| 30 |
+
"referrer-policy": "no-referrer",
|
| 31 |
+
}
|
| 32 |
+
PAGE_HEADERS = {
|
| 33 |
+
**NO_STORE_HEADERS,
|
| 34 |
+
"content-security-policy": (
|
| 35 |
+
"default-src 'none'; script-src 'self'; script-src-attr 'none'; "
|
| 36 |
+
"style-src 'self'; style-src-attr 'none'; connect-src 'self'; "
|
| 37 |
+
"img-src 'self' data:; font-src 'self'; object-src 'none'; "
|
| 38 |
+
"base-uri 'none'; form-action 'none'; frame-ancestors 'self' "
|
| 39 |
+
"https://huggingface.co https://*.hf.space https://*.huggingface.co"
|
| 40 |
+
),
|
| 41 |
+
"permissions-policy": (
|
| 42 |
+
"camera=(), microphone=(), geolocation=(), payment=(), usb=(), "
|
| 43 |
+
"accelerometer=(), gyroscope=()"
|
| 44 |
+
),
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def _now() -> str:
|
| 49 |
+
return datetime.now(timezone.utc).isoformat(timespec="milliseconds").replace(
|
| 50 |
+
"+00:00", "Z"
|
| 51 |
+
)
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def _safe_mapping(value: Any) -> dict[str, Any]:
|
| 55 |
+
return dict(value) if isinstance(value, Mapping) else {}
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def _manifest_digest(value: Mapping[str, Any]) -> str:
|
| 59 |
+
payload = json.dumps(
|
| 60 |
+
dict(value),
|
| 61 |
+
ensure_ascii=False,
|
| 62 |
+
sort_keys=True,
|
| 63 |
+
separators=(",", ":"),
|
| 64 |
+
allow_nan=False,
|
| 65 |
+
).encode("utf-8")
|
| 66 |
+
return hashlib.sha256(payload).hexdigest()
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
def _service(app: FastAPI) -> Any:
|
| 70 |
+
return getattr(app.state, "szl_series_a_service", None)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def _snapshot(
|
| 74 |
+
service: Any,
|
| 75 |
+
*,
|
| 76 |
+
include_receipts: bool = True,
|
| 77 |
+
) -> tuple[
|
| 78 |
+
dict[str, Any],
|
| 79 |
+
dict[str, Any],
|
| 80 |
+
list[dict[str, Any]],
|
| 81 |
+
str | None,
|
| 82 |
+
str,
|
| 83 |
+
]:
|
| 84 |
+
if service is None:
|
| 85 |
+
return (
|
| 86 |
+
{
|
| 87 |
+
"state": "UNAVAILABLE",
|
| 88 |
+
"terminal": True,
|
| 89 |
+
"detail": "Series-A estate observer is not registered",
|
| 90 |
+
},
|
| 91 |
+
{},
|
| 92 |
+
[],
|
| 93 |
+
None,
|
| 94 |
+
"UNAVAILABLE",
|
| 95 |
+
)
|
| 96 |
+
try:
|
| 97 |
+
for _ in range(2):
|
| 98 |
+
status = _safe_mapping(service.latest_status())
|
| 99 |
+
latest = service.store.latest_snapshot()
|
| 100 |
+
digest = (
|
| 101 |
+
str(latest.get("digest"))
|
| 102 |
+
if isinstance(latest, Mapping) and latest.get("digest")
|
| 103 |
+
else None
|
| 104 |
+
)
|
| 105 |
+
status_digest = status.get("manifest_digest")
|
| 106 |
+
if (digest is None and not status_digest) or status_digest == digest:
|
| 107 |
+
manifest = (
|
| 108 |
+
_safe_mapping(latest.get("manifest"))
|
| 109 |
+
if isinstance(latest, Mapping)
|
| 110 |
+
else {}
|
| 111 |
+
)
|
| 112 |
+
if digest is not None and _manifest_digest(manifest) != digest:
|
| 113 |
+
return (
|
| 114 |
+
{
|
| 115 |
+
"state": "UNAVAILABLE",
|
| 116 |
+
"terminal": True,
|
| 117 |
+
"detail": "Persisted estate manifest digest mismatch",
|
| 118 |
+
"reason": "MANIFEST_DIGEST_MISMATCH",
|
| 119 |
+
},
|
| 120 |
+
{},
|
| 121 |
+
[],
|
| 122 |
+
None,
|
| 123 |
+
"UNAVAILABLE",
|
| 124 |
+
)
|
| 125 |
+
receipts: list[dict[str, Any]] = []
|
| 126 |
+
proof_state = "NOT_REQUESTED"
|
| 127 |
+
if include_receipts:
|
| 128 |
+
try:
|
| 129 |
+
receipt_values = service.store.list_receipts(8)
|
| 130 |
+
receipts = [
|
| 131 |
+
dict(item)
|
| 132 |
+
for item in receipt_values
|
| 133 |
+
if isinstance(item, Mapping)
|
| 134 |
+
]
|
| 135 |
+
proof_state = "OBSERVED"
|
| 136 |
+
except Exception:
|
| 137 |
+
proof_state = "UNAVAILABLE"
|
| 138 |
+
return (
|
| 139 |
+
status,
|
| 140 |
+
manifest,
|
| 141 |
+
receipts,
|
| 142 |
+
digest,
|
| 143 |
+
proof_state,
|
| 144 |
+
)
|
| 145 |
+
return (
|
| 146 |
+
{
|
| 147 |
+
"state": "UNAVAILABLE",
|
| 148 |
+
"terminal": True,
|
| 149 |
+
"detail": "Estate snapshot changed during bounded projection",
|
| 150 |
+
"reason": "SNAPSHOT_CHANGED_DURING_READ",
|
| 151 |
+
},
|
| 152 |
+
{},
|
| 153 |
+
[],
|
| 154 |
+
None,
|
| 155 |
+
"UNAVAILABLE",
|
| 156 |
+
)
|
| 157 |
+
except Exception:
|
| 158 |
+
return (
|
| 159 |
+
{
|
| 160 |
+
"state": "UNAVAILABLE",
|
| 161 |
+
"terminal": True,
|
| 162 |
+
"detail": "Series-A read projection failed closed",
|
| 163 |
+
"reason": "SERIES_A_READ_FAILED",
|
| 164 |
+
},
|
| 165 |
+
{},
|
| 166 |
+
[],
|
| 167 |
+
None,
|
| 168 |
+
"UNAVAILABLE",
|
| 169 |
+
)
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def _capability_state(raw: Any, observation_state: str) -> str:
|
| 173 |
+
value = str(raw or "UNAVAILABLE")
|
| 174 |
+
if observation_state == "STALE" and value in {"OBSERVED", "PARTIAL"}:
|
| 175 |
+
return "STALE"
|
| 176 |
+
return value
|
| 177 |
+
|
| 178 |
+
|
| 179 |
+
def _capabilities(
|
| 180 |
+
manifest: Mapping[str, Any], observation_state: str
|
| 181 |
+
) -> list[dict[str, Any]]:
|
| 182 |
+
github = _safe_mapping(manifest.get("github"))
|
| 183 |
+
github_value = _safe_mapping(github.get("value"))
|
| 184 |
+
github_detail = _safe_mapping(github.get("detail"))
|
| 185 |
+
github_state = _capability_state(github.get("state"), observation_state)
|
| 186 |
+
|
| 187 |
+
rows: list[dict[str, Any]] = [
|
| 188 |
+
{
|
| 189 |
+
"provider": "github",
|
| 190 |
+
"capability": "repositories",
|
| 191 |
+
"state": github_state,
|
| 192 |
+
"count": (
|
| 193 |
+
github_value.get("repository_count")
|
| 194 |
+
if github_state == "OBSERVED"
|
| 195 |
+
else None
|
| 196 |
+
),
|
| 197 |
+
"scope": (
|
| 198 |
+
"AUTHENTICATED_SCOPE_REDACTED"
|
| 199 |
+
if github_detail.get("authenticated")
|
| 200 |
+
else "PUBLIC_ONLY"
|
| 201 |
+
),
|
| 202 |
+
},
|
| 203 |
+
{
|
| 204 |
+
"provider": "github",
|
| 205 |
+
"capability": "open_pull_requests",
|
| 206 |
+
"state": github_state,
|
| 207 |
+
"count": (
|
| 208 |
+
github_value.get("open_pull_request_count")
|
| 209 |
+
if github_state == "OBSERVED"
|
| 210 |
+
else None
|
| 211 |
+
),
|
| 212 |
+
"scope": (
|
| 213 |
+
"AUTHENTICATED_SCOPE_REDACTED"
|
| 214 |
+
if github_detail.get("authenticated")
|
| 215 |
+
else "PUBLIC_ONLY"
|
| 216 |
+
),
|
| 217 |
+
},
|
| 218 |
+
]
|
| 219 |
+
|
| 220 |
+
huggingface = _safe_mapping(manifest.get("huggingface"))
|
| 221 |
+
huggingface_value = _safe_mapping(huggingface.get("value"))
|
| 222 |
+
huggingface_detail = _safe_mapping(huggingface.get("detail"))
|
| 223 |
+
categories = _safe_mapping(huggingface_value.get("categories"))
|
| 224 |
+
for capability in (
|
| 225 |
+
"models",
|
| 226 |
+
"datasets",
|
| 227 |
+
"spaces",
|
| 228 |
+
"collections",
|
| 229 |
+
"buckets",
|
| 230 |
+
"kernels",
|
| 231 |
+
):
|
| 232 |
+
value = _safe_mapping(categories.get(capability))
|
| 233 |
+
state = _capability_state(value.get("state"), observation_state)
|
| 234 |
+
rows.append(
|
| 235 |
+
{
|
| 236 |
+
"provider": "huggingface",
|
| 237 |
+
"capability": capability,
|
| 238 |
+
"state": state,
|
| 239 |
+
"count": value.get("count") if state == "OBSERVED" else None,
|
| 240 |
+
"scope": (
|
| 241 |
+
"AUTHENTICATED_SCOPE_REDACTED"
|
| 242 |
+
if huggingface_detail.get("authenticated")
|
| 243 |
+
else "PUBLIC_ONLY"
|
| 244 |
+
),
|
| 245 |
+
}
|
| 246 |
+
)
|
| 247 |
+
|
| 248 |
+
rows.extend(
|
| 249 |
+
[
|
| 250 |
+
{
|
| 251 |
+
"provider": "runtime",
|
| 252 |
+
"capability": "source_to_hf_overlay_binding",
|
| 253 |
+
"state": "UNAVAILABLE",
|
| 254 |
+
"count": None,
|
| 255 |
+
"scope": "NOT_OBSERVED_BY_ESTATE_MANIFEST",
|
| 256 |
+
},
|
| 257 |
+
{
|
| 258 |
+
"provider": "web",
|
| 259 |
+
"capability": "domain_build_identity",
|
| 260 |
+
"state": "UNAVAILABLE",
|
| 261 |
+
"count": None,
|
| 262 |
+
"scope": "NOT_OBSERVED_BY_ESTATE_MANIFEST",
|
| 263 |
+
},
|
| 264 |
+
]
|
| 265 |
+
)
|
| 266 |
+
return rows
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
def _receipt_projection(items: list[dict[str, Any]]) -> list[dict[str, Any]]:
|
| 270 |
+
projected = []
|
| 271 |
+
for item in items:
|
| 272 |
+
envelope = _safe_mapping(item.get("envelope"))
|
| 273 |
+
projected.append(
|
| 274 |
+
{
|
| 275 |
+
"kind": item.get("kind"),
|
| 276 |
+
"receipt_hash": item.get("receipt_hash"),
|
| 277 |
+
"created_at": item.get("created_at"),
|
| 278 |
+
"signature_status": envelope.get("signature_status", "UNAVAILABLE"),
|
| 279 |
+
"verification_state": "UNAVAILABLE",
|
| 280 |
+
}
|
| 281 |
+
)
|
| 282 |
+
return projected
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
def build_summary(app: FastAPI) -> dict[str, Any]:
|
| 286 |
+
status, manifest, receipts, digest, proof_state = _snapshot(_service(app))
|
| 287 |
+
state = str(status.get("state") or "UNAVAILABLE")
|
| 288 |
+
critical_failures = status.get("critical_failures")
|
| 289 |
+
if not isinstance(critical_failures, list):
|
| 290 |
+
critical_failures = []
|
| 291 |
+
enforcement = "OBSERVE_ONLY" if state == "OBSERVED" and not critical_failures else "FAILED_CLOSED"
|
| 292 |
+
source_revision = status.get("source_revision") or manifest.get("source_revision")
|
| 293 |
+
|
| 294 |
+
raw_counts = _safe_mapping(status.get("counts"))
|
| 295 |
+
current_counts = (
|
| 296 |
+
raw_counts
|
| 297 |
+
if state == "OBSERVED" and not critical_failures
|
| 298 |
+
else {key: None for key in raw_counts}
|
| 299 |
+
)
|
| 300 |
+
|
| 301 |
+
return {
|
| 302 |
+
"schema": SCHEMA_SUMMARY,
|
| 303 |
+
"generated_at": _now(),
|
| 304 |
+
"operating_mode": OPERATING_MODE,
|
| 305 |
+
"observation": {
|
| 306 |
+
"state": state,
|
| 307 |
+
"observed_at": status.get("observed_at"),
|
| 308 |
+
"valid_until": status.get("valid_until"),
|
| 309 |
+
"manifest_digest": digest,
|
| 310 |
+
"critical_failures": critical_failures,
|
| 311 |
+
"detail": status.get("detail"),
|
| 312 |
+
"reason": status.get("reason"),
|
| 313 |
+
},
|
| 314 |
+
"enforcement": {
|
| 315 |
+
"state": enforcement,
|
| 316 |
+
"external_writes": "DISABLED",
|
| 317 |
+
"automatic_retries": 0,
|
| 318 |
+
"effectors": [],
|
| 319 |
+
"reason": (
|
| 320 |
+
"READ_PROJECTION_ONLY"
|
| 321 |
+
if enforcement == "OBSERVE_ONLY"
|
| 322 |
+
else "CURRENT_EVIDENCE_CANNOT_AUTHORIZE_ACTION"
|
| 323 |
+
),
|
| 324 |
+
},
|
| 325 |
+
"identity": {
|
| 326 |
+
"runtime_reported_source_revision": source_revision,
|
| 327 |
+
"github_default_branch_revision": None,
|
| 328 |
+
"huggingface_repository_revision": None,
|
| 329 |
+
"runtime_artifact_digest": None,
|
| 330 |
+
"equivalence_state": "UNAVAILABLE",
|
| 331 |
+
"reason": "ESTATE_MANIFEST_DOES_NOT_BIND_SOURCE_TO_HF_OVERLAY_AND_RUNTIME_ARTIFACT",
|
| 332 |
+
},
|
| 333 |
+
"counts": current_counts,
|
| 334 |
+
"last_known_counts": {
|
| 335 |
+
"state": state,
|
| 336 |
+
"values": raw_counts,
|
| 337 |
+
},
|
| 338 |
+
"coverage": _capabilities(manifest, state),
|
| 339 |
+
"claim_gate": {
|
| 340 |
+
"state": "FAILED_CLOSED",
|
| 341 |
+
"public_claim_status": "HELD",
|
| 342 |
+
"reason": "EXACT_SOURCE_RUNTIME_BINDING_UNAVAILABLE",
|
| 343 |
+
},
|
| 344 |
+
"frontiers": [
|
| 345 |
+
{
|
| 346 |
+
"id": "estate-observation",
|
| 347 |
+
"label": "Estate observation",
|
| 348 |
+
"state": state,
|
| 349 |
+
"source": "series-a-manifest",
|
| 350 |
+
},
|
| 351 |
+
{
|
| 352 |
+
"id": "source-runtime-parity",
|
| 353 |
+
"label": "Source to runtime parity",
|
| 354 |
+
"state": "UNAVAILABLE",
|
| 355 |
+
"source": "binding-not-observed",
|
| 356 |
+
},
|
| 357 |
+
{
|
| 358 |
+
"id": "defensive-activation",
|
| 359 |
+
"label": "Defensive activation",
|
| 360 |
+
"state": "MODELED",
|
| 361 |
+
"source": "no-effectors-bound",
|
| 362 |
+
},
|
| 363 |
+
{
|
| 364 |
+
"id": "atelier-clean-room",
|
| 365 |
+
"label": "ATELIER clean-room innovation",
|
| 366 |
+
"state": "MODELED",
|
| 367 |
+
"source": "release-gate-not-bound",
|
| 368 |
+
},
|
| 369 |
+
],
|
| 370 |
+
"proof_rail": _receipt_projection(receipts),
|
| 371 |
+
"proof_rail_state": proof_state,
|
| 372 |
+
"routes": {
|
| 373 |
+
"series_a_manifest": "/api/a11oy/v1/series-a/manifest",
|
| 374 |
+
"series_a_receipts": "/api/a11oy/v1/series-a/receipts",
|
| 375 |
+
"series_a_events": "/api/a11oy/v1/series-a/events",
|
| 376 |
+
"frontier_manifest": "/api/a11oy/v1/frontier/manifest",
|
| 377 |
+
},
|
| 378 |
+
"private_reasoning_collected": False,
|
| 379 |
+
"claim": "CURRENT_OBSERVATION_NOT_ETERNAL_TRUTH",
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
|
| 383 |
+
def build_inventory(app: FastAPI) -> dict[str, Any]:
|
| 384 |
+
status, manifest, _, digest, _ = _snapshot(
|
| 385 |
+
_service(app), include_receipts=False
|
| 386 |
+
)
|
| 387 |
+
state = str(status.get("state") or "UNAVAILABLE")
|
| 388 |
+
return {
|
| 389 |
+
"manifest_digest": digest,
|
| 390 |
+
"observation_state": state,
|
| 391 |
+
"observed_at": status.get("observed_at"),
|
| 392 |
+
"valid_until": status.get("valid_until"),
|
| 393 |
+
"items": _capabilities(manifest, state),
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
|
| 397 |
+
def _single_query_value(request: Request, name: str, default: str) -> str:
|
| 398 |
+
values = request.query_params.getlist(name)
|
| 399 |
+
if len(values) > 1:
|
| 400 |
+
raise HTTPException(status_code=400, detail=f"{name} must be supplied at most once")
|
| 401 |
+
return values[0] if values else default
|
| 402 |
+
|
| 403 |
+
|
| 404 |
+
def _bounded_integer(
|
| 405 |
+
request: Request,
|
| 406 |
+
name: str,
|
| 407 |
+
default: int,
|
| 408 |
+
*,
|
| 409 |
+
minimum: int,
|
| 410 |
+
maximum: int,
|
| 411 |
+
) -> int:
|
| 412 |
+
raw = _single_query_value(request, name, str(default))
|
| 413 |
+
try:
|
| 414 |
+
value = int(raw)
|
| 415 |
+
except ValueError as exc:
|
| 416 |
+
raise HTTPException(status_code=400, detail=f"{name} must be an integer") from exc
|
| 417 |
+
if value < minimum or value > maximum:
|
| 418 |
+
raise HTTPException(
|
| 419 |
+
status_code=422,
|
| 420 |
+
detail=f"{name} must be between {minimum} and {maximum}",
|
| 421 |
+
)
|
| 422 |
+
return value
|
| 423 |
+
|
| 424 |
+
|
| 425 |
+
def _asset_bytes(name: str) -> bytes:
|
| 426 |
+
path = Path(__file__).resolve().parent / "frontier_now_web" / name
|
| 427 |
+
if not path.is_file():
|
| 428 |
+
raise HTTPException(status_code=404, detail=f"asset missing: {name}")
|
| 429 |
+
return path.read_bytes()
|
| 430 |
+
|
| 431 |
+
|
| 432 |
+
def _asset_digest(name: str) -> str:
|
| 433 |
+
return hashlib.sha256(_asset_bytes(name)).hexdigest()
|
| 434 |
+
|
| 435 |
+
|
| 436 |
+
def _asset_cache_control(request: Request, content: bytes) -> str:
|
| 437 |
+
if request.query_params.get("v") == hashlib.sha256(content).hexdigest():
|
| 438 |
+
return "public,max-age=31536000,immutable"
|
| 439 |
+
return "no-store"
|
| 440 |
+
|
| 441 |
+
|
| 442 |
+
def register(app: FastAPI, ns: str = "a11oy") -> dict[str, Any]:
|
| 443 |
+
prefix = f"/api/{ns}/v1/frontier-now"
|
| 444 |
+
intended_paths = {
|
| 445 |
+
"/frontier-now",
|
| 446 |
+
"/frontier-now/",
|
| 447 |
+
"/now",
|
| 448 |
+
"/now/",
|
| 449 |
+
"/frontier-now/app.js",
|
| 450 |
+
"/frontier-now/app.js/",
|
| 451 |
+
"/frontier-now/styles.css",
|
| 452 |
+
"/frontier-now/styles.css/",
|
| 453 |
+
f"{prefix}/summary",
|
| 454 |
+
f"{prefix}/summary/",
|
| 455 |
+
f"{prefix}/inventory",
|
| 456 |
+
f"{prefix}/inventory/",
|
| 457 |
+
}
|
| 458 |
+
existing = [
|
| 459 |
+
route
|
| 460 |
+
for route in app.router.routes
|
| 461 |
+
if getattr(route, "path", None) in intended_paths
|
| 462 |
+
]
|
| 463 |
+
if existing:
|
| 464 |
+
complete = {getattr(route, "path", None) for route in existing} == intended_paths
|
| 465 |
+
owned = all(
|
| 466 |
+
getattr(getattr(route, "endpoint", None), "__module__", None)
|
| 467 |
+
== __name__
|
| 468 |
+
for route in existing
|
| 469 |
+
)
|
| 470 |
+
methods_complete = all(
|
| 471 |
+
{"GET", "HEAD"}.issubset(getattr(route, "methods", set()))
|
| 472 |
+
for route in existing
|
| 473 |
+
)
|
| 474 |
+
if complete and owned and methods_complete and len(existing) == len(intended_paths):
|
| 475 |
+
return {
|
| 476 |
+
"ok": True,
|
| 477 |
+
"state": "ALREADY_REGISTERED",
|
| 478 |
+
"routes": sorted(intended_paths),
|
| 479 |
+
}
|
| 480 |
+
raise RuntimeError("FRONTIER_NOW_ROUTE_COLLISION")
|
| 481 |
+
|
| 482 |
+
async def page(request: Request) -> Response:
|
| 483 |
+
html = (
|
| 484 |
+
_asset_bytes("index.html")
|
| 485 |
+
.decode("utf-8")
|
| 486 |
+
.replace("__APP_ASSET_DIGEST__", _asset_digest("app.js"))
|
| 487 |
+
.replace("__STYLE_ASSET_DIGEST__", _asset_digest("styles.css"))
|
| 488 |
+
)
|
| 489 |
+
if request.method == "HEAD":
|
| 490 |
+
return Response(
|
| 491 |
+
status_code=200,
|
| 492 |
+
media_type="text/html",
|
| 493 |
+
headers=PAGE_HEADERS,
|
| 494 |
+
)
|
| 495 |
+
return HTMLResponse(html, headers=PAGE_HEADERS)
|
| 496 |
+
|
| 497 |
+
async def js(request: Request) -> Response:
|
| 498 |
+
content = _asset_bytes("app.js")
|
| 499 |
+
headers = {
|
| 500 |
+
"cache-control": _asset_cache_control(request, content),
|
| 501 |
+
"x-content-type-options": "nosniff",
|
| 502 |
+
"referrer-policy": "no-referrer",
|
| 503 |
+
}
|
| 504 |
+
if request.method == "HEAD":
|
| 505 |
+
return Response(
|
| 506 |
+
status_code=200,
|
| 507 |
+
media_type="application/javascript",
|
| 508 |
+
headers=headers,
|
| 509 |
+
)
|
| 510 |
+
return Response(content, media_type="application/javascript", headers=headers)
|
| 511 |
+
|
| 512 |
+
async def css(request: Request) -> Response:
|
| 513 |
+
content = _asset_bytes("styles.css")
|
| 514 |
+
headers = {
|
| 515 |
+
"cache-control": _asset_cache_control(request, content),
|
| 516 |
+
"x-content-type-options": "nosniff",
|
| 517 |
+
"referrer-policy": "no-referrer",
|
| 518 |
+
}
|
| 519 |
+
if request.method == "HEAD":
|
| 520 |
+
return Response(status_code=200, media_type="text/css", headers=headers)
|
| 521 |
+
return Response(content, media_type="text/css", headers=headers)
|
| 522 |
+
|
| 523 |
+
async def summary(request: Request) -> Response:
|
| 524 |
+
if request.method == "HEAD":
|
| 525 |
+
return Response(
|
| 526 |
+
status_code=200,
|
| 527 |
+
media_type="application/json",
|
| 528 |
+
headers=NO_STORE_HEADERS,
|
| 529 |
+
)
|
| 530 |
+
return JSONResponse(build_summary(request.app), headers=NO_STORE_HEADERS)
|
| 531 |
+
|
| 532 |
+
async def inventory(request: Request) -> Response:
|
| 533 |
+
provider = _single_query_value(request, "provider", "all").lower()
|
| 534 |
+
if provider not in PROVIDERS:
|
| 535 |
+
raise HTTPException(
|
| 536 |
+
status_code=422,
|
| 537 |
+
detail="provider must be one of all, github, huggingface, runtime, web",
|
| 538 |
+
)
|
| 539 |
+
cursor = _bounded_integer(
|
| 540 |
+
request, "cursor", 0, minimum=0, maximum=1_000_000
|
| 541 |
+
)
|
| 542 |
+
limit = _bounded_integer(
|
| 543 |
+
request,
|
| 544 |
+
"limit",
|
| 545 |
+
20,
|
| 546 |
+
minimum=1,
|
| 547 |
+
maximum=MAX_INVENTORY_LIMIT,
|
| 548 |
+
)
|
| 549 |
+
projection = build_inventory(request.app)
|
| 550 |
+
rows = projection["items"]
|
| 551 |
+
if provider != "all":
|
| 552 |
+
rows = [item for item in rows if item.get("provider") == provider]
|
| 553 |
+
page_rows = rows[cursor : cursor + limit]
|
| 554 |
+
next_cursor = cursor + len(page_rows) if cursor + len(page_rows) < len(rows) else None
|
| 555 |
+
if request.method == "HEAD":
|
| 556 |
+
return Response(
|
| 557 |
+
status_code=200,
|
| 558 |
+
media_type="application/json",
|
| 559 |
+
headers=NO_STORE_HEADERS,
|
| 560 |
+
)
|
| 561 |
+
return JSONResponse(
|
| 562 |
+
{
|
| 563 |
+
"schema": SCHEMA_INVENTORY,
|
| 564 |
+
"generated_at": _now(),
|
| 565 |
+
"operating_mode": OPERATING_MODE,
|
| 566 |
+
"manifest_digest": projection["manifest_digest"],
|
| 567 |
+
"observation_state": projection["observation_state"],
|
| 568 |
+
"observed_at": projection["observed_at"],
|
| 569 |
+
"valid_until": projection["valid_until"],
|
| 570 |
+
"provider": provider,
|
| 571 |
+
"cursor": cursor,
|
| 572 |
+
"limit": limit,
|
| 573 |
+
"next_cursor": next_cursor,
|
| 574 |
+
"total": len(rows),
|
| 575 |
+
"items": page_rows,
|
| 576 |
+
"asset_names_exposed": False,
|
| 577 |
+
"claim": "CAPABILITY_COVERAGE_NOT_ASSET_READINESS",
|
| 578 |
+
},
|
| 579 |
+
headers=NO_STORE_HEADERS,
|
| 580 |
+
)
|
| 581 |
+
|
| 582 |
+
routes: list[tuple[str, Callable[..., Any], list[str]]] = [
|
| 583 |
+
("/frontier-now", page, ["GET", "HEAD"]),
|
| 584 |
+
("/frontier-now/", page, ["GET", "HEAD"]),
|
| 585 |
+
("/now", page, ["GET", "HEAD"]),
|
| 586 |
+
("/now/", page, ["GET", "HEAD"]),
|
| 587 |
+
("/frontier-now/app.js", js, ["GET", "HEAD"]),
|
| 588 |
+
("/frontier-now/app.js/", js, ["GET", "HEAD"]),
|
| 589 |
+
("/frontier-now/styles.css", css, ["GET", "HEAD"]),
|
| 590 |
+
("/frontier-now/styles.css/", css, ["GET", "HEAD"]),
|
| 591 |
+
(f"{prefix}/summary", summary, ["GET", "HEAD"]),
|
| 592 |
+
(f"{prefix}/summary/", summary, ["GET", "HEAD"]),
|
| 593 |
+
(f"{prefix}/inventory", inventory, ["GET", "HEAD"]),
|
| 594 |
+
(f"{prefix}/inventory/", inventory, ["GET", "HEAD"]),
|
| 595 |
+
]
|
| 596 |
+
added: list[str] = []
|
| 597 |
+
for path, endpoint, methods in routes:
|
| 598 |
+
app.add_api_route(path, endpoint, methods=methods, include_in_schema=False)
|
| 599 |
+
added.append(path)
|
| 600 |
+
|
| 601 |
+
route_set = set(added)
|
| 602 |
+
selected = [
|
| 603 |
+
route
|
| 604 |
+
for route in app.router.routes
|
| 605 |
+
if getattr(route, "path", None) in route_set
|
| 606 |
+
]
|
| 607 |
+
selected_ids = {id(route) for route in selected}
|
| 608 |
+
app.router.routes[:] = selected + [
|
| 609 |
+
route for route in app.router.routes if id(route) not in selected_ids
|
| 610 |
+
]
|
| 611 |
+
|
| 612 |
+
return {
|
| 613 |
+
"ok": True,
|
| 614 |
+
"state": "REGISTERED",
|
| 615 |
+
"namespace": ns,
|
| 616 |
+
"routes": sorted(added),
|
| 617 |
+
"operating_mode": OPERATING_MODE,
|
| 618 |
+
"sign_on_read": False,
|
| 619 |
+
"effectors": [],
|
| 620 |
+
"private_reasoning_collected": False,
|
| 621 |
+
}
|
routers/frontier_now_web/app.js
ADDED
|
@@ -0,0 +1,356 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
* (c) 2026 Lutar, Stephen P. - SZL Holdings - ORCID 0009-0001-0110-4173
|
| 3 |
+
*/
|
| 4 |
+
(() => {
|
| 5 |
+
"use strict";
|
| 6 |
+
|
| 7 |
+
const API = "/api/a11oy/v1/frontier-now";
|
| 8 |
+
const SERIES_EVENTS = "/api/a11oy/v1/series-a/events";
|
| 9 |
+
const TIMEOUT_MS = 8000;
|
| 10 |
+
const INVENTORY_PAGE_SIZE = 50;
|
| 11 |
+
const INVENTORY_MAX_PAGES = 10;
|
| 12 |
+
const MIN_EVENT_RELOAD_MS = 5000;
|
| 13 |
+
const STATES = new Set([
|
| 14 |
+
"OBSERVED",
|
| 15 |
+
"MODELED",
|
| 16 |
+
"PENDING",
|
| 17 |
+
"STALE",
|
| 18 |
+
"BLOCKED",
|
| 19 |
+
"FAILED_CLOSED",
|
| 20 |
+
"UNAVAILABLE",
|
| 21 |
+
"DISABLED",
|
| 22 |
+
"UNKNOWN"
|
| 23 |
+
]);
|
| 24 |
+
|
| 25 |
+
const byId = (id) => document.getElementById(id);
|
| 26 |
+
const terminal = (value, fallback = "UNAVAILABLE") => {
|
| 27 |
+
if (value === null || value === undefined || value === "") return fallback;
|
| 28 |
+
return String(value);
|
| 29 |
+
};
|
| 30 |
+
const state = (value) => {
|
| 31 |
+
const normalized = terminal(value, "UNAVAILABLE").toUpperCase();
|
| 32 |
+
return STATES.has(normalized) ? normalized : "UNKNOWN";
|
| 33 |
+
};
|
| 34 |
+
const setText = (id, value, fallback) => {
|
| 35 |
+
const node = byId(id);
|
| 36 |
+
if (node) node.textContent = terminal(value, fallback);
|
| 37 |
+
};
|
| 38 |
+
const setState = (id, value) => {
|
| 39 |
+
const node = byId(id);
|
| 40 |
+
if (!node) return;
|
| 41 |
+
const normalized = state(value);
|
| 42 |
+
node.textContent = normalized;
|
| 43 |
+
node.dataset.state = normalized;
|
| 44 |
+
};
|
| 45 |
+
const formatTime = (value) => {
|
| 46 |
+
if (!value) return "NOT OBSERVED";
|
| 47 |
+
const date = new Date(value);
|
| 48 |
+
return Number.isNaN(date.valueOf()) ? String(value) : date.toISOString();
|
| 49 |
+
};
|
| 50 |
+
const shortHash = (value) => {
|
| 51 |
+
const text = terminal(value, "UNAVAILABLE");
|
| 52 |
+
return text.length > 24 ? `${text.slice(0, 12)}…${text.slice(-8)}` : text;
|
| 53 |
+
};
|
| 54 |
+
|
| 55 |
+
const activeControllers = new Set();
|
| 56 |
+
const request = async (path) => {
|
| 57 |
+
const controller = new AbortController();
|
| 58 |
+
activeControllers.add(controller);
|
| 59 |
+
const timer = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
| 60 |
+
try {
|
| 61 |
+
const response = await fetch(API + path, {
|
| 62 |
+
method: "GET",
|
| 63 |
+
cache: "no-store",
|
| 64 |
+
credentials: "same-origin",
|
| 65 |
+
headers: {accept: "application/json"},
|
| 66 |
+
signal: controller.signal
|
| 67 |
+
});
|
| 68 |
+
if (!response.ok) throw new Error(`HTTP_${response.status}`);
|
| 69 |
+
const contentType = response.headers.get("content-type") || "";
|
| 70 |
+
if (!contentType.includes("application/json")) {
|
| 71 |
+
throw new Error("NON_JSON_RESPONSE");
|
| 72 |
+
}
|
| 73 |
+
return await response.json();
|
| 74 |
+
} finally {
|
| 75 |
+
clearTimeout(timer);
|
| 76 |
+
activeControllers.delete(controller);
|
| 77 |
+
}
|
| 78 |
+
};
|
| 79 |
+
|
| 80 |
+
const requestInventory = async () => {
|
| 81 |
+
let cursor = 0;
|
| 82 |
+
let identity = null;
|
| 83 |
+
let pageCount = 0;
|
| 84 |
+
const items = [];
|
| 85 |
+
while (pageCount < INVENTORY_MAX_PAGES) {
|
| 86 |
+
const page = await request(
|
| 87 |
+
`/inventory?provider=all&limit=${INVENTORY_PAGE_SIZE}&cursor=${cursor}`
|
| 88 |
+
);
|
| 89 |
+
const pageIdentity = [
|
| 90 |
+
page.manifest_digest,
|
| 91 |
+
page.observation_state,
|
| 92 |
+
page.observed_at,
|
| 93 |
+
page.valid_until
|
| 94 |
+
];
|
| 95 |
+
if (identity && JSON.stringify(identity) !== JSON.stringify(pageIdentity)) {
|
| 96 |
+
throw new Error("INVENTORY_CHANGED_DURING_PAGINATION");
|
| 97 |
+
}
|
| 98 |
+
identity = pageIdentity;
|
| 99 |
+
items.push(...(Array.isArray(page.items) ? page.items : []));
|
| 100 |
+
pageCount += 1;
|
| 101 |
+
if (page.next_cursor === null || page.next_cursor === undefined) {
|
| 102 |
+
return {...page, items};
|
| 103 |
+
}
|
| 104 |
+
if (!Number.isInteger(page.next_cursor) || page.next_cursor <= cursor) {
|
| 105 |
+
throw new Error("INVALID_INVENTORY_CURSOR");
|
| 106 |
+
}
|
| 107 |
+
cursor = page.next_cursor;
|
| 108 |
+
}
|
| 109 |
+
throw new Error("INVENTORY_PAGINATION_BOUND_EXCEEDED");
|
| 110 |
+
};
|
| 111 |
+
|
| 112 |
+
const sameObservation = (summary, inventory) => (
|
| 113 |
+
summary.observation?.manifest_digest === inventory.manifest_digest &&
|
| 114 |
+
summary.observation?.state === inventory.observation_state &&
|
| 115 |
+
summary.observation?.observed_at === inventory.observed_at &&
|
| 116 |
+
summary.observation?.valid_until === inventory.valid_until
|
| 117 |
+
);
|
| 118 |
+
|
| 119 |
+
const readView = async () => {
|
| 120 |
+
const settled = await Promise.allSettled([request("/summary"), requestInventory()]);
|
| 121 |
+
if (settled[0].status !== "fulfilled") throw settled[0].reason;
|
| 122 |
+
let summary = settled[0].value;
|
| 123 |
+
if (settled[1].status !== "fulfilled") {
|
| 124 |
+
return {summary, inventory: null, inventoryError: settled[1].reason};
|
| 125 |
+
}
|
| 126 |
+
let inventory = settled[1].value;
|
| 127 |
+
if (sameObservation(summary, inventory)) {
|
| 128 |
+
return {summary, inventory, inventoryError: null};
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
const retry = await Promise.allSettled([request("/summary"), requestInventory()]);
|
| 132 |
+
if (retry[0].status === "fulfilled") summary = retry[0].value;
|
| 133 |
+
if (retry[1].status !== "fulfilled") {
|
| 134 |
+
return {summary, inventory: null, inventoryError: retry[1].reason};
|
| 135 |
+
}
|
| 136 |
+
inventory = retry[1].value;
|
| 137 |
+
if (!sameObservation(summary, inventory)) {
|
| 138 |
+
return {
|
| 139 |
+
summary,
|
| 140 |
+
inventory: null,
|
| 141 |
+
inventoryError: new Error("SNAPSHOT_CHANGED_DURING_READ")
|
| 142 |
+
};
|
| 143 |
+
}
|
| 144 |
+
return {summary, inventory, inventoryError: null};
|
| 145 |
+
};
|
| 146 |
+
|
| 147 |
+
const renderCoverage = (items, emptyMessage) => {
|
| 148 |
+
const body = byId("coverage-rows");
|
| 149 |
+
body.replaceChildren();
|
| 150 |
+
const rows = Array.isArray(items) ? items : [];
|
| 151 |
+
if (!rows.length) {
|
| 152 |
+
const row = document.createElement("tr");
|
| 153 |
+
const cell = document.createElement("td");
|
| 154 |
+
cell.colSpan = 5;
|
| 155 |
+
cell.textContent = emptyMessage || "UNAVAILABLE · no capability observations returned";
|
| 156 |
+
row.append(cell);
|
| 157 |
+
body.append(row);
|
| 158 |
+
return;
|
| 159 |
+
}
|
| 160 |
+
rows.forEach((item) => {
|
| 161 |
+
const row = document.createElement("tr");
|
| 162 |
+
const provider = document.createElement("td");
|
| 163 |
+
const capability = document.createElement("td");
|
| 164 |
+
const statusCell = document.createElement("td");
|
| 165 |
+
const count = document.createElement("td");
|
| 166 |
+
const scope = document.createElement("td");
|
| 167 |
+
const badge = document.createElement("span");
|
| 168 |
+
|
| 169 |
+
provider.textContent = terminal(item.provider);
|
| 170 |
+
capability.textContent = terminal(item.capability);
|
| 171 |
+
badge.className = "status";
|
| 172 |
+
badge.dataset.state = state(item.state);
|
| 173 |
+
badge.textContent = state(item.state);
|
| 174 |
+
statusCell.append(badge);
|
| 175 |
+
count.textContent = item.count === null || item.count === undefined ? "—" : String(item.count);
|
| 176 |
+
scope.textContent = terminal(item.scope);
|
| 177 |
+
row.append(provider, capability, statusCell, count, scope);
|
| 178 |
+
body.append(row);
|
| 179 |
+
});
|
| 180 |
+
};
|
| 181 |
+
|
| 182 |
+
const renderProof = (items, proofState = "UNAVAILABLE") => {
|
| 183 |
+
const list = byId("proof-rail");
|
| 184 |
+
list.replaceChildren();
|
| 185 |
+
const receipts = Array.isArray(items) ? items : [];
|
| 186 |
+
if (!receipts.length) {
|
| 187 |
+
const item = document.createElement("li");
|
| 188 |
+
const observedEmpty = state(proofState) === "OBSERVED";
|
| 189 |
+
item.textContent = observedEmpty
|
| 190 |
+
? "OBSERVED · no receipts persisted"
|
| 191 |
+
: "UNAVAILABLE · receipt projection could not be read";
|
| 192 |
+
list.append(item);
|
| 193 |
+
setState("proof-state", observedEmpty ? "OBSERVED" : "UNAVAILABLE");
|
| 194 |
+
return;
|
| 195 |
+
}
|
| 196 |
+
receipts.forEach((receipt) => {
|
| 197 |
+
const item = document.createElement("li");
|
| 198 |
+
const kind = document.createElement("span");
|
| 199 |
+
const hash = document.createElement("a");
|
| 200 |
+
const created = document.createElement("time");
|
| 201 |
+
const signature = document.createElement("span");
|
| 202 |
+
const digest = terminal(receipt.receipt_hash);
|
| 203 |
+
|
| 204 |
+
kind.textContent = terminal(receipt.kind);
|
| 205 |
+
hash.href = `/api/a11oy/v1/series-a/receipts/${encodeURIComponent(digest)}`;
|
| 206 |
+
hash.textContent = shortHash(digest);
|
| 207 |
+
hash.className = "text-link";
|
| 208 |
+
hash.title = digest;
|
| 209 |
+
hash.setAttribute("aria-label", `Open receipt SHA-256 ${digest}`);
|
| 210 |
+
created.dateTime = terminal(receipt.created_at, "");
|
| 211 |
+
created.textContent = formatTime(receipt.created_at);
|
| 212 |
+
signature.className = "status";
|
| 213 |
+
signature.dataset.state = "UNAVAILABLE";
|
| 214 |
+
signature.textContent = `REPORTED ${terminal(receipt.signature_status)}`;
|
| 215 |
+
item.append(kind, hash, created, signature);
|
| 216 |
+
list.append(item);
|
| 217 |
+
});
|
| 218 |
+
setState("proof-state", "OBSERVED");
|
| 219 |
+
};
|
| 220 |
+
|
| 221 |
+
const renderCounts = (counts) => {
|
| 222 |
+
document.querySelectorAll("[data-count]").forEach((node) => {
|
| 223 |
+
const value = counts && Object.prototype.hasOwnProperty.call(counts, node.dataset.count)
|
| 224 |
+
? counts[node.dataset.count]
|
| 225 |
+
: null;
|
| 226 |
+
node.textContent = value === null || value === undefined ? "—" : String(value);
|
| 227 |
+
});
|
| 228 |
+
};
|
| 229 |
+
|
| 230 |
+
let loadGeneration = 0;
|
| 231 |
+
const load = async () => {
|
| 232 |
+
activeControllers.forEach((controller) => controller.abort());
|
| 233 |
+
activeControllers.clear();
|
| 234 |
+
const generation = ++loadGeneration;
|
| 235 |
+
const button = byId("refresh-view");
|
| 236 |
+
button.disabled = true;
|
| 237 |
+
setText("view-status", "Reading the persisted estate snapshot.");
|
| 238 |
+
try {
|
| 239 |
+
const {summary, inventory, inventoryError} = await readView();
|
| 240 |
+
if (generation !== loadGeneration) return;
|
| 241 |
+
|
| 242 |
+
setText("operating-mode", summary.operating_mode, "OBSERVE_ONLY");
|
| 243 |
+
setState("estate-state", summary.observation?.state);
|
| 244 |
+
setState("observe-state", summary.observation?.state);
|
| 245 |
+
setState("claim-state", summary.claim_gate?.state);
|
| 246 |
+
setText("observed-at", formatTime(summary.observation?.observed_at));
|
| 247 |
+
setText("as-of", `OBSERVED ${formatTime(summary.observation?.observed_at)} · VALID UNTIL ${formatTime(summary.observation?.valid_until)}`);
|
| 248 |
+
|
| 249 |
+
const revision = summary.identity?.runtime_reported_source_revision;
|
| 250 |
+
setText("runtime-revision", revision, "NOT OBSERVED");
|
| 251 |
+
setText("graph-source", shortHash(revision));
|
| 252 |
+
byId("runtime-source-node").classList.toggle("reported", Boolean(revision));
|
| 253 |
+
byId("runtime-source-node").classList.toggle("unavailable", !revision);
|
| 254 |
+
setText("identity-reason", terminal(summary.identity?.reason));
|
| 255 |
+
renderCounts(summary.counts || {});
|
| 256 |
+
renderCoverage(
|
| 257 |
+
inventory?.items || [],
|
| 258 |
+
inventoryError
|
| 259 |
+
? `UNAVAILABLE · inventory projection: ${terminal(inventoryError.message)}`
|
| 260 |
+
: undefined
|
| 261 |
+
);
|
| 262 |
+
renderProof(summary.proof_rail || [], summary.proof_rail_state);
|
| 263 |
+
setText(
|
| 264 |
+
"view-status",
|
| 265 |
+
`View generated ${formatTime(summary.generated_at)} · ${terminal(summary.claim)}` +
|
| 266 |
+
(inventoryError ? " · COVERAGE UNAVAILABLE" : "")
|
| 267 |
+
);
|
| 268 |
+
} catch (error) {
|
| 269 |
+
if (generation !== loadGeneration) return;
|
| 270 |
+
setState("estate-state", "UNAVAILABLE");
|
| 271 |
+
setState("observe-state", "UNAVAILABLE");
|
| 272 |
+
setState("claim-state", "FAILED_CLOSED");
|
| 273 |
+
setState("proof-state", "UNAVAILABLE");
|
| 274 |
+
renderCounts({});
|
| 275 |
+
renderCoverage([], "UNAVAILABLE · capability projection could not be read");
|
| 276 |
+
renderProof([], "UNAVAILABLE");
|
| 277 |
+
setText("operating-mode", "OBSERVE_ONLY");
|
| 278 |
+
setText("runtime-revision", "NOT OBSERVED");
|
| 279 |
+
setText("graph-source", "NOT OBSERVED");
|
| 280 |
+
byId("runtime-source-node").classList.remove("reported");
|
| 281 |
+
byId("runtime-source-node").classList.add("unavailable");
|
| 282 |
+
setText("observed-at", "NOT OBSERVED");
|
| 283 |
+
setText("identity-reason", "CURRENT_PROJECTION_UNAVAILABLE");
|
| 284 |
+
const reason = error && error.name === "AbortError"
|
| 285 |
+
? `UNAVAILABLE · timed out after ${TIMEOUT_MS / 1000} seconds`
|
| 286 |
+
: `UNAVAILABLE · ${terminal(error && error.message)}`;
|
| 287 |
+
setText("view-status", reason);
|
| 288 |
+
setText("as-of", "TERMINAL UNAVAILABLE STATE");
|
| 289 |
+
} finally {
|
| 290 |
+
if (generation === loadGeneration) button.disabled = false;
|
| 291 |
+
}
|
| 292 |
+
};
|
| 293 |
+
|
| 294 |
+
byId("refresh-view").addEventListener("click", load);
|
| 295 |
+
|
| 296 |
+
const activateRailLink = (active) => {
|
| 297 |
+
document.querySelectorAll('.rail a[href^="#"]').forEach((item) => {
|
| 298 |
+
const selected = item === active;
|
| 299 |
+
item.classList.toggle("active", selected);
|
| 300 |
+
if (selected) item.setAttribute("aria-current", "location");
|
| 301 |
+
else item.removeAttribute("aria-current");
|
| 302 |
+
});
|
| 303 |
+
};
|
| 304 |
+
|
| 305 |
+
document.querySelectorAll('.rail a[href^="#"]').forEach((link) => {
|
| 306 |
+
link.addEventListener("click", () => {
|
| 307 |
+
activateRailLink(link);
|
| 308 |
+
});
|
| 309 |
+
});
|
| 310 |
+
|
| 311 |
+
if ("IntersectionObserver" in window) {
|
| 312 |
+
const links = new Map(
|
| 313 |
+
[...document.querySelectorAll('.rail a[href^="#"]')].map((link) => [
|
| 314 |
+
link.getAttribute("href").slice(1),
|
| 315 |
+
link
|
| 316 |
+
])
|
| 317 |
+
);
|
| 318 |
+
const observer = new IntersectionObserver((entries) => {
|
| 319 |
+
const visible = entries
|
| 320 |
+
.filter((entry) => entry.isIntersecting)
|
| 321 |
+
.sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0];
|
| 322 |
+
if (!visible) return;
|
| 323 |
+
activateRailLink(links.get(visible.target.id));
|
| 324 |
+
}, {rootMargin: "-20% 0px -65%", threshold: [0.05, 0.25, 0.6]});
|
| 325 |
+
links.forEach((_link, id) => {
|
| 326 |
+
const section = byId(id);
|
| 327 |
+
if (section) observer.observe(section);
|
| 328 |
+
});
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
let eventReloadTimer = null;
|
| 332 |
+
let lastEventReload = 0;
|
| 333 |
+
if ("EventSource" in window) {
|
| 334 |
+
const events = new EventSource(SERIES_EVENTS);
|
| 335 |
+
events.addEventListener("open", () => {
|
| 336 |
+
setText("live-updates", "UPDATES CONNECTED");
|
| 337 |
+
});
|
| 338 |
+
events.addEventListener("error", () => {
|
| 339 |
+
setText("live-updates", "UPDATES UNAVAILABLE · MANUAL REFRESH");
|
| 340 |
+
});
|
| 341 |
+
["estate.refresh", "estate.refresh.failed"].forEach((eventName) => {
|
| 342 |
+
events.addEventListener(eventName, () => {
|
| 343 |
+
clearTimeout(eventReloadTimer);
|
| 344 |
+
const wait = Math.max(250, MIN_EVENT_RELOAD_MS - (Date.now() - lastEventReload));
|
| 345 |
+
eventReloadTimer = setTimeout(() => {
|
| 346 |
+
lastEventReload = Date.now();
|
| 347 |
+
load();
|
| 348 |
+
}, wait);
|
| 349 |
+
});
|
| 350 |
+
});
|
| 351 |
+
} else {
|
| 352 |
+
setText("live-updates", "UPDATES UNAVAILABLE · MANUAL REFRESH");
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
load();
|
| 356 |
+
})();
|
routers/frontier_now_web/index.html
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!-- SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
(c) 2026 Lutar, Stephen P. - SZL Holdings - ORCID 0009-0001-0110-4173 -->
|
| 3 |
+
<!doctype html>
|
| 4 |
+
<html lang="en">
|
| 5 |
+
<head>
|
| 6 |
+
<meta charset="utf-8">
|
| 7 |
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
| 8 |
+
<meta name="robots" content="noindex,nofollow">
|
| 9 |
+
<meta name="color-scheme" content="dark">
|
| 10 |
+
<title>A11oy Frontier NOW · Estate Proof Surface</title>
|
| 11 |
+
<link rel="stylesheet" href="/frontier-now/styles.css?v=__STYLE_ASSET_DIGEST__">
|
| 12 |
+
</head>
|
| 13 |
+
<body>
|
| 14 |
+
<a class="skip-link" href="#main">Skip to estate state</a>
|
| 15 |
+
<header class="topbar">
|
| 16 |
+
<a class="brand" href="/frontier-now" aria-label="A11oy Frontier Now home">
|
| 17 |
+
<span class="brand-mark" aria-hidden="true">A11</span>
|
| 18 |
+
<span>A11oy / Frontier NOW</span>
|
| 19 |
+
</a>
|
| 20 |
+
<div class="mode-lock" aria-label="Current operating mode">
|
| 21 |
+
<span class="pulse" aria-hidden="true"></span>
|
| 22 |
+
<span>OPERATING MODE</span>
|
| 23 |
+
<strong id="operating-mode">OBSERVE_ONLY</strong>
|
| 24 |
+
<span aria-hidden="true">·</span>
|
| 25 |
+
<span id="live-updates" aria-live="polite">UPDATES CONNECTING</span>
|
| 26 |
+
</div>
|
| 27 |
+
<button class="quiet-button" id="refresh-view" type="button">Refresh view</button>
|
| 28 |
+
</header>
|
| 29 |
+
|
| 30 |
+
<main id="main" tabindex="-1">
|
| 31 |
+
<section class="hero" aria-labelledby="hero-title">
|
| 32 |
+
<div>
|
| 33 |
+
<p class="kicker">ONE ESTATE · ONE TRUTH BOUNDARY · ZERO HIDDEN WRITES</p>
|
| 34 |
+
<h1 id="hero-title">See the whole system.<br><em>Hold what cannot be proved.</em></h1>
|
| 35 |
+
<p class="hero-copy">A read-only control surface for GitHub, Hugging Face, runtime identity, proof receipts, defensive activation, and clean-room innovation. Every material state carries its evidence boundary.</p>
|
| 36 |
+
</div>
|
| 37 |
+
<dl class="identity-card" aria-label="Build and observation identity">
|
| 38 |
+
<div><dt>Estate observation</dt><dd><span class="status" id="estate-state" data-state="PENDING">PENDING</span></dd></div>
|
| 39 |
+
<div><dt>Runtime source</dt><dd id="runtime-revision">NOT OBSERVED</dd></div>
|
| 40 |
+
<div><dt>HF overlay</dt><dd><span class="status" data-state="UNAVAILABLE">UNAVAILABLE</span></dd></div>
|
| 41 |
+
<div><dt>Claim gate</dt><dd><span class="status" id="claim-state" data-state="FAILED_CLOSED">FAILED_CLOSED</span></dd></div>
|
| 42 |
+
<div><dt>Observed at</dt><dd id="observed-at">NOT OBSERVED</dd></div>
|
| 43 |
+
</dl>
|
| 44 |
+
</section>
|
| 45 |
+
|
| 46 |
+
<section class="metric-band" aria-label="Estate counts">
|
| 47 |
+
<article><span>GitHub repos</span><strong data-count="github_repositories">—</strong><small>latest observed listing</small></article>
|
| 48 |
+
<article><span>Open pull requests</span><strong data-count="github_open_pull_requests">—</strong><small>queue, not readiness</small></article>
|
| 49 |
+
<article><span>HF models</span><strong data-count="models">—</strong><small>catalog observations</small></article>
|
| 50 |
+
<article><span>HF datasets</span><strong data-count="datasets">—</strong><small>catalog observations</small></article>
|
| 51 |
+
<article><span>HF Spaces</span><strong data-count="spaces">—</strong><small>inventory, not runtime proof</small></article>
|
| 52 |
+
<article><span>External writes</span><strong>0</strong><small>disabled in this surface</small></article>
|
| 53 |
+
</section>
|
| 54 |
+
|
| 55 |
+
<section class="workspace" aria-label="Frontier control workspace">
|
| 56 |
+
<nav class="rail" aria-label="Workspace sections">
|
| 57 |
+
<a href="#command" class="active" aria-current="location">Command</a>
|
| 58 |
+
<a href="#coverage">Coverage</a>
|
| 59 |
+
<a href="#parity">Parity</a>
|
| 60 |
+
<a href="#defense">Defense</a>
|
| 61 |
+
<a href="#atelier">ATELIER</a>
|
| 62 |
+
<a href="#proof">Proof rail</a>
|
| 63 |
+
<a href="/series-a">Series-A authority</a>
|
| 64 |
+
<a href="/frontier">Frontier manifest</a>
|
| 65 |
+
</nav>
|
| 66 |
+
|
| 67 |
+
<div class="canvas">
|
| 68 |
+
<section id="command" class="panel command-panel" aria-labelledby="command-title">
|
| 69 |
+
<div class="panel-head">
|
| 70 |
+
<div><p class="eyebrow">CURRENT CONTROL POSTURE</p><h2 id="command-title">Evidence before effect</h2></div>
|
| 71 |
+
<span id="as-of" class="as-of">WAITING FOR OBSERVATION</span>
|
| 72 |
+
</div>
|
| 73 |
+
<div class="command-grid">
|
| 74 |
+
<article class="state-card">
|
| 75 |
+
<span class="card-index">01</span>
|
| 76 |
+
<h3>Observe</h3>
|
| 77 |
+
<p>Read the persisted provider snapshot. Never turn a failed query into a green zero.</p>
|
| 78 |
+
<span class="status" id="observe-state" data-state="PENDING">PENDING</span>
|
| 79 |
+
</article>
|
| 80 |
+
<article class="state-card">
|
| 81 |
+
<span class="card-index">02</span>
|
| 82 |
+
<h3>Bind</h3>
|
| 83 |
+
<p>Link source, HF overlay, runtime artifact, and domain readback only through explicit evidence.</p>
|
| 84 |
+
<span class="status" data-state="UNAVAILABLE">UNAVAILABLE</span>
|
| 85 |
+
</article>
|
| 86 |
+
<article class="state-card">
|
| 87 |
+
<span class="card-index">03</span>
|
| 88 |
+
<h3>Authorize</h3>
|
| 89 |
+
<p>This projection has no POST route, credential, signer, or provider effector.</p>
|
| 90 |
+
<span class="status" data-state="DISABLED">DISABLED</span>
|
| 91 |
+
</article>
|
| 92 |
+
<article class="state-card">
|
| 93 |
+
<span class="card-index">04</span>
|
| 94 |
+
<h3>Prove</h3>
|
| 95 |
+
<p>Show receipt metadata and reported signature status without signing on read or claiming eternal truth.</p>
|
| 96 |
+
<span class="status" id="proof-state" data-state="PENDING">PENDING</span>
|
| 97 |
+
</article>
|
| 98 |
+
</div>
|
| 99 |
+
</section>
|
| 100 |
+
|
| 101 |
+
<section id="coverage" class="panel" aria-labelledby="coverage-title">
|
| 102 |
+
<div class="panel-head">
|
| 103 |
+
<div><p class="eyebrow">CAPABILITY-VISIBLE COVERAGE</p><h2 id="coverage-title">Every gap stays in the frame</h2></div>
|
| 104 |
+
<span class="legend"><i data-state="OBSERVED"></i> observed <i data-state="UNAVAILABLE"></i> unavailable</span>
|
| 105 |
+
</div>
|
| 106 |
+
<div class="table-wrap" role="region" aria-labelledby="coverage-title" tabindex="0">
|
| 107 |
+
<table>
|
| 108 |
+
<thead><tr><th scope="col">Provider</th><th scope="col">Capability</th><th scope="col">State</th><th scope="col">Count</th><th scope="col">Evidence scope</th></tr></thead>
|
| 109 |
+
<tbody id="coverage-rows"><tr><td colspan="5">LOADING CAPABILITY RECEIPTS</td></tr></tbody>
|
| 110 |
+
</table>
|
| 111 |
+
</div>
|
| 112 |
+
</section>
|
| 113 |
+
|
| 114 |
+
<section id="parity" class="panel" aria-labelledby="parity-title">
|
| 115 |
+
<div class="panel-head">
|
| 116 |
+
<div><p class="eyebrow">SOURCE → RUNTIME PROOF GRAPH</p><h2 id="parity-title">No inferred edges</h2></div>
|
| 117 |
+
<span class="status" data-state="FAILED_CLOSED">CLAIM HELD</span>
|
| 118 |
+
</div>
|
| 119 |
+
<div class="proof-graph">
|
| 120 |
+
<div class="graph-node unavailable" id="runtime-source-node"><span>Runtime-reported source</span><strong id="graph-source">NOT OBSERVED</strong></div>
|
| 121 |
+
<div class="edge unknown"><span>binding unavailable</span></div>
|
| 122 |
+
<div class="graph-node unavailable"><span>HF repository overlay</span><strong>UNAVAILABLE</strong></div>
|
| 123 |
+
<div class="edge unknown"><span>artifact unavailable</span></div>
|
| 124 |
+
<div class="graph-node unavailable"><span>Domain build identity</span><strong>UNAVAILABLE</strong></div>
|
| 125 |
+
<div class="edge blocked"><span>claim gate</span></div>
|
| 126 |
+
<div class="graph-node blocked"><span>Public claim</span><strong>HELD</strong></div>
|
| 127 |
+
</div>
|
| 128 |
+
<p class="boundary-note" id="identity-reason">Waiting for identity evidence.</p>
|
| 129 |
+
</section>
|
| 130 |
+
|
| 131 |
+
<section id="defense" class="panel split-panel" aria-labelledby="defense-title">
|
| 132 |
+
<div>
|
| 133 |
+
<p class="eyebrow">DEFENSIVE FRONTIER</p>
|
| 134 |
+
<h2 id="defense-title">Proposal first. Canary before scale.</h2>
|
| 135 |
+
<p>The public cockpit deliberately exposes no mutation controls. Identity, endpoint, cloud, email, source-chain, data, AI, and recovery coverage remain modeled or unavailable until exact telemetry receipts are bound.</p>
|
| 136 |
+
</div>
|
| 137 |
+
<dl class="budget-list">
|
| 138 |
+
<div><dt>External actions</dt><dd>DISABLED</dd></div>
|
| 139 |
+
<div><dt>Automatic retries</dt><dd>0</dd></div>
|
| 140 |
+
<div><dt>Canary target</dt><dd>NOT BOUND</dd></div>
|
| 141 |
+
<div><dt>Rollback proof</dt><dd>UNAVAILABLE</dd></div>
|
| 142 |
+
<div><dt>Public mutation contract</dt><dd>FAILED_CLOSED</dd></div>
|
| 143 |
+
</dl>
|
| 144 |
+
</section>
|
| 145 |
+
|
| 146 |
+
<section id="atelier" class="panel atelier-panel" aria-labelledby="atelier-title">
|
| 147 |
+
<div class="panel-head">
|
| 148 |
+
<div><p class="eyebrow">ATELIER · CLEAN-ROOM INNOVATION LINE</p><h2 id="atelier-title">Learn the pattern. Rebuild the expression.</h2></div>
|
| 149 |
+
<span class="status" data-state="MODELED">MODELED</span>
|
| 150 |
+
</div>
|
| 151 |
+
<ol class="atelier-flow">
|
| 152 |
+
<li><span>01</span><div><strong>Admit lawful sources</strong><p>Record access basis, terms, license, and obligations.</p></div></li>
|
| 153 |
+
<li><span>02</span><div><strong>Seal an original specification</strong><p>Exclude protected copy, trade dress, and source code.</p></div></li>
|
| 154 |
+
<li><span>03</span><div><strong>Build independently</strong><p>Use internal design language and approved dependencies.</p></div></li>
|
| 155 |
+
<li><span>04</span><div><strong>Review the exact artifact</strong><p>Bind revision, digest, obligations, and release surface.</p></div></li>
|
| 156 |
+
</ol>
|
| 157 |
+
<p class="boundary-note">No legal clearance is inferred by this modeled workflow. Human review remains a separate recorded decision.</p>
|
| 158 |
+
</section>
|
| 159 |
+
|
| 160 |
+
<section id="proof" class="panel" aria-labelledby="proof-title">
|
| 161 |
+
<div class="panel-head">
|
| 162 |
+
<div><p class="eyebrow">PERSISTED RECEIPT METADATA</p><h2 id="proof-title">Proof rail</h2></div>
|
| 163 |
+
<a class="text-link" href="/api/a11oy/v1/series-a/receipts">Open canonical receipts</a>
|
| 164 |
+
</div>
|
| 165 |
+
<ol id="proof-rail" class="proof-list"><li>WAITING FOR PERSISTED RECEIPTS</li></ol>
|
| 166 |
+
</section>
|
| 167 |
+
|
| 168 |
+
<section class="truth-footer" aria-label="Truth boundary">
|
| 169 |
+
<p><strong>CURRENT OBSERVATION, NOT ETERNAL TRUTH.</strong> Catalog presence is not deployment. HTTP reachability is not authorization. A pushed branch is not merged source. Merged source is not a witnessed runtime.</p>
|
| 170 |
+
<p id="view-status" aria-live="polite">Loading the persisted estate view.</p>
|
| 171 |
+
</section>
|
| 172 |
+
</div>
|
| 173 |
+
</section>
|
| 174 |
+
</main>
|
| 175 |
+
|
| 176 |
+
<noscript><p class="noscript">JavaScript is required to read the live estate projection. The canonical JSON remains available at <a href="/api/a11oy/v1/frontier-now/summary">the Frontier Now summary endpoint</a>.</p></noscript>
|
| 177 |
+
<script src="/frontier-now/app.js?v=__APP_ASSET_DIGEST__" defer></script>
|
| 178 |
+
</body>
|
| 179 |
+
</html>
|
routers/frontier_now_web/styles.css
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
* (c) 2026 Lutar, Stephen P. - SZL Holdings - ORCID 0009-0001-0110-4173
|
| 3 |
+
*/
|
| 4 |
+
:root {
|
| 5 |
+
color-scheme: dark;
|
| 6 |
+
--ink: #05070a;
|
| 7 |
+
--panel: #0d1117;
|
| 8 |
+
--panel-2: #111820;
|
| 9 |
+
--line: #2a3542;
|
| 10 |
+
--muted: #96a2af;
|
| 11 |
+
--paper: #f3f1ea;
|
| 12 |
+
--acid: #c9b787;
|
| 13 |
+
--cyan: #5fb3a3;
|
| 14 |
+
--amber: #ffc45e;
|
| 15 |
+
--rose: #ff7272;
|
| 16 |
+
--violet: #b6a2ff;
|
| 17 |
+
--radius: 18px;
|
| 18 |
+
--mono: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
|
| 19 |
+
--sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
* { box-sizing: border-box; }
|
| 23 |
+
|
| 24 |
+
html {
|
| 25 |
+
background: var(--ink);
|
| 26 |
+
scroll-behavior: smooth;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
body {
|
| 30 |
+
margin: 0;
|
| 31 |
+
min-width: 320px;
|
| 32 |
+
color: var(--paper);
|
| 33 |
+
background:
|
| 34 |
+
radial-gradient(circle at 82% -10%, rgba(95, 179, 163, .1), transparent 32rem),
|
| 35 |
+
linear-gradient(rgba(255, 255, 255, .018) 1px, transparent 1px),
|
| 36 |
+
linear-gradient(90deg, rgba(255, 255, 255, .018) 1px, transparent 1px),
|
| 37 |
+
var(--ink);
|
| 38 |
+
background-size: auto, 40px 40px, 40px 40px, auto;
|
| 39 |
+
font-family: var(--sans);
|
| 40 |
+
line-height: 1.5;
|
| 41 |
+
}
|
| 42 |
+
|
| 43 |
+
a { color: inherit; }
|
| 44 |
+
|
| 45 |
+
button, a { -webkit-tap-highlight-color: transparent; }
|
| 46 |
+
|
| 47 |
+
button:focus-visible,
|
| 48 |
+
a:focus-visible,
|
| 49 |
+
[tabindex]:focus-visible {
|
| 50 |
+
outline: 3px solid var(--cyan);
|
| 51 |
+
outline-offset: 4px;
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
.skip-link {
|
| 55 |
+
position: fixed;
|
| 56 |
+
top: .75rem;
|
| 57 |
+
left: .75rem;
|
| 58 |
+
z-index: 100;
|
| 59 |
+
padding: .65rem .9rem;
|
| 60 |
+
color: var(--ink);
|
| 61 |
+
background: var(--acid);
|
| 62 |
+
transform: translateY(-180%);
|
| 63 |
+
transition: transform .15s ease;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
.skip-link:focus { transform: translateY(0); }
|
| 67 |
+
|
| 68 |
+
.topbar {
|
| 69 |
+
position: sticky;
|
| 70 |
+
top: 0;
|
| 71 |
+
z-index: 20;
|
| 72 |
+
display: grid;
|
| 73 |
+
grid-template-columns: minmax(0, 1fr) auto auto;
|
| 74 |
+
align-items: center;
|
| 75 |
+
gap: 1rem;
|
| 76 |
+
min-height: 72px;
|
| 77 |
+
padding: .75rem clamp(1rem, 4vw, 4.5rem);
|
| 78 |
+
border-bottom: 1px solid var(--line);
|
| 79 |
+
background: rgba(5, 7, 10, .92);
|
| 80 |
+
backdrop-filter: blur(18px);
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
.brand {
|
| 84 |
+
display: inline-flex;
|
| 85 |
+
align-items: center;
|
| 86 |
+
gap: .8rem;
|
| 87 |
+
width: fit-content;
|
| 88 |
+
color: var(--paper);
|
| 89 |
+
font-weight: 750;
|
| 90 |
+
letter-spacing: .01em;
|
| 91 |
+
text-decoration: none;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
.brand-mark {
|
| 95 |
+
display: grid;
|
| 96 |
+
place-items: center;
|
| 97 |
+
width: 38px;
|
| 98 |
+
height: 38px;
|
| 99 |
+
border: 1px solid var(--acid);
|
| 100 |
+
border-radius: 10px;
|
| 101 |
+
color: var(--acid);
|
| 102 |
+
font: 700 .7rem var(--mono);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
.mode-lock {
|
| 106 |
+
display: flex;
|
| 107 |
+
flex-wrap: wrap;
|
| 108 |
+
align-items: center;
|
| 109 |
+
gap: .55rem;
|
| 110 |
+
color: var(--muted);
|
| 111 |
+
font: 650 .75rem var(--mono);
|
| 112 |
+
letter-spacing: .09em;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
.mode-lock strong { color: var(--acid); }
|
| 116 |
+
|
| 117 |
+
.pulse {
|
| 118 |
+
width: .6rem;
|
| 119 |
+
height: .6rem;
|
| 120 |
+
border-radius: 50%;
|
| 121 |
+
background: var(--acid);
|
| 122 |
+
box-shadow: 0 0 0 .3rem rgba(201, 183, 135, .15);
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
.quiet-button {
|
| 126 |
+
min-height: 42px;
|
| 127 |
+
padding: .6rem .9rem;
|
| 128 |
+
border: 1px solid var(--line);
|
| 129 |
+
border-radius: 999px;
|
| 130 |
+
color: var(--paper);
|
| 131 |
+
background: transparent;
|
| 132 |
+
font: 650 .75rem var(--mono);
|
| 133 |
+
cursor: pointer;
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
.quiet-button:hover { border-color: var(--cyan); color: var(--cyan); }
|
| 137 |
+
.quiet-button:disabled { opacity: .55; cursor: progress; }
|
| 138 |
+
|
| 139 |
+
main { max-width: 1680px; margin: 0 auto; }
|
| 140 |
+
|
| 141 |
+
.hero {
|
| 142 |
+
display: grid;
|
| 143 |
+
grid-template-columns: minmax(0, 1.25fr) minmax(310px, .75fr);
|
| 144 |
+
gap: clamp(2rem, 5vw, 6rem);
|
| 145 |
+
align-items: end;
|
| 146 |
+
padding: clamp(4rem, 9vw, 8.5rem) clamp(1rem, 4vw, 4.5rem) clamp(3rem, 6vw, 5rem);
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
.kicker,
|
| 150 |
+
.eyebrow {
|
| 151 |
+
margin: 0 0 .8rem;
|
| 152 |
+
color: var(--acid);
|
| 153 |
+
font: 700 .72rem var(--mono);
|
| 154 |
+
letter-spacing: .13em;
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
h1 {
|
| 158 |
+
max-width: 15ch;
|
| 159 |
+
margin: 0;
|
| 160 |
+
font-size: clamp(3rem, 7.8vw, 8.2rem);
|
| 161 |
+
font-weight: 680;
|
| 162 |
+
letter-spacing: -.065em;
|
| 163 |
+
line-height: .88;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
h1 em {
|
| 167 |
+
color: transparent;
|
| 168 |
+
-webkit-text-stroke: 1px var(--paper);
|
| 169 |
+
font-style: normal;
|
| 170 |
+
}
|
| 171 |
+
|
| 172 |
+
.hero-copy {
|
| 173 |
+
max-width: 68ch;
|
| 174 |
+
margin: 2rem 0 0;
|
| 175 |
+
color: #c3cbd4;
|
| 176 |
+
font-size: clamp(1rem, 1.4vw, 1.25rem);
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
.identity-card {
|
| 180 |
+
margin: 0;
|
| 181 |
+
padding: 1.2rem;
|
| 182 |
+
border: 1px solid var(--line);
|
| 183 |
+
border-radius: var(--radius);
|
| 184 |
+
background: rgba(13, 17, 23, .82);
|
| 185 |
+
box-shadow: 0 28px 80px rgba(0, 0, 0, .3);
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
.identity-card div {
|
| 189 |
+
display: grid;
|
| 190 |
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
|
| 191 |
+
gap: 1rem;
|
| 192 |
+
align-items: center;
|
| 193 |
+
min-height: 54px;
|
| 194 |
+
border-bottom: 1px solid var(--line);
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
.identity-card div:last-child { border-bottom: 0; }
|
| 198 |
+
.identity-card dt { color: var(--muted); font-size: .82rem; }
|
| 199 |
+
.identity-card dd { margin: 0; overflow-wrap: anywhere; font: 650 .76rem var(--mono); text-align: right; }
|
| 200 |
+
|
| 201 |
+
.status {
|
| 202 |
+
display: inline-flex;
|
| 203 |
+
align-items: center;
|
| 204 |
+
gap: .4rem;
|
| 205 |
+
width: fit-content;
|
| 206 |
+
padding: .28rem .55rem;
|
| 207 |
+
border: 1px solid currentColor;
|
| 208 |
+
border-radius: 999px;
|
| 209 |
+
font: 750 .75rem var(--mono);
|
| 210 |
+
letter-spacing: .04em;
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
.status::before {
|
| 214 |
+
content: "";
|
| 215 |
+
width: .4rem;
|
| 216 |
+
height: .4rem;
|
| 217 |
+
border-radius: 50%;
|
| 218 |
+
background: currentColor;
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
.status[data-state="OBSERVED"] { color: var(--acid); }
|
| 222 |
+
.status[data-state="MODELED"] { color: var(--violet); }
|
| 223 |
+
.status[data-state="PENDING"],
|
| 224 |
+
.status[data-state="STALE"] { color: var(--amber); }
|
| 225 |
+
.status[data-state="FAILED_CLOSED"],
|
| 226 |
+
.status[data-state="BLOCKED"] { color: var(--rose); }
|
| 227 |
+
.status[data-state="UNAVAILABLE"],
|
| 228 |
+
.status[data-state="DISABLED"],
|
| 229 |
+
.status[data-state="UNKNOWN"] { color: var(--muted); }
|
| 230 |
+
|
| 231 |
+
.metric-band {
|
| 232 |
+
display: grid;
|
| 233 |
+
grid-template-columns: repeat(6, minmax(0, 1fr));
|
| 234 |
+
border-block: 1px solid var(--line);
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
.metric-band article {
|
| 238 |
+
min-height: 150px;
|
| 239 |
+
padding: 1.25rem;
|
| 240 |
+
border-right: 1px solid var(--line);
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
.metric-band article:last-child { border-right: 0; }
|
| 244 |
+
.metric-band span, .metric-band small { display: block; color: var(--muted); font-size: .72rem; }
|
| 245 |
+
.metric-band strong { display: block; margin: .5rem 0 .2rem; color: var(--paper); font: 650 clamp(2rem, 4vw, 3.7rem) var(--mono); letter-spacing: -.08em; }
|
| 246 |
+
|
| 247 |
+
.workspace {
|
| 248 |
+
display: grid;
|
| 249 |
+
grid-template-columns: 190px minmax(0, 1fr);
|
| 250 |
+
gap: clamp(1.2rem, 3vw, 3rem);
|
| 251 |
+
padding: clamp(1.2rem, 3vw, 3rem) clamp(1rem, 4vw, 4.5rem) 5rem;
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
.rail {
|
| 255 |
+
position: sticky;
|
| 256 |
+
top: 96px;
|
| 257 |
+
align-self: start;
|
| 258 |
+
display: grid;
|
| 259 |
+
gap: .2rem;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
.rail a {
|
| 263 |
+
padding: .65rem .8rem;
|
| 264 |
+
border-left: 2px solid transparent;
|
| 265 |
+
color: var(--muted);
|
| 266 |
+
font: 650 .78rem var(--mono);
|
| 267 |
+
text-decoration: none;
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
.rail a:hover, .rail a.active { border-left-color: var(--acid); color: var(--paper); background: rgba(201, 183, 135, .055); }
|
| 271 |
+
|
| 272 |
+
.canvas { min-width: 0; }
|
| 273 |
+
|
| 274 |
+
.panel {
|
| 275 |
+
margin: 0 0 1.25rem;
|
| 276 |
+
padding: clamp(1.2rem, 2.5vw, 2.2rem);
|
| 277 |
+
border: 1px solid var(--line);
|
| 278 |
+
border-radius: var(--radius);
|
| 279 |
+
background: linear-gradient(145deg, rgba(17, 24, 32, .93), rgba(9, 13, 18, .93));
|
| 280 |
+
scroll-margin-top: 96px;
|
| 281 |
+
}
|
| 282 |
+
|
| 283 |
+
.panel-head {
|
| 284 |
+
display: flex;
|
| 285 |
+
align-items: flex-start;
|
| 286 |
+
justify-content: space-between;
|
| 287 |
+
gap: 1.5rem;
|
| 288 |
+
margin-bottom: 1.6rem;
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
h2 { margin: 0; font-size: clamp(1.55rem, 3vw, 2.55rem); letter-spacing: -.045em; }
|
| 292 |
+
h3 { margin: .4rem 0 .6rem; font-size: 1.1rem; }
|
| 293 |
+
.as-of, .legend { color: var(--muted); font: .75rem var(--mono); text-align: right; }
|
| 294 |
+
.legend i { display: inline-block; width: .48rem; height: .48rem; margin: 0 .3rem 0 .8rem; border-radius: 50%; background: var(--muted); }
|
| 295 |
+
.legend i[data-state="OBSERVED"] { background: var(--acid); }
|
| 296 |
+
|
| 297 |
+
.command-grid {
|
| 298 |
+
display: grid;
|
| 299 |
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
| 300 |
+
gap: .75rem;
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
.state-card {
|
| 304 |
+
min-height: 230px;
|
| 305 |
+
padding: 1rem;
|
| 306 |
+
border: 1px solid var(--line);
|
| 307 |
+
border-radius: 13px;
|
| 308 |
+
background: rgba(5, 7, 10, .42);
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
.state-card p { min-height: 6.5em; color: var(--muted); font-size: .83rem; }
|
| 312 |
+
.card-index { color: var(--cyan); font: .7rem var(--mono); }
|
| 313 |
+
|
| 314 |
+
.table-wrap { overflow-x: auto; }
|
| 315 |
+
.table-wrap:focus-visible { outline: 3px solid var(--cyan); outline-offset: 4px; }
|
| 316 |
+
table { width: 100%; border-collapse: collapse; font-size: .84rem; }
|
| 317 |
+
th, td { padding: .9rem .75rem; border-bottom: 1px solid var(--line); text-align: left; vertical-align: middle; }
|
| 318 |
+
th { color: var(--muted); font: 650 .68rem var(--mono); letter-spacing: .07em; text-transform: uppercase; }
|
| 319 |
+
td:nth-child(1), td:nth-child(2), td:nth-child(4), td:nth-child(5) { font-family: var(--mono); }
|
| 320 |
+
td:last-child { color: var(--muted); font-size: .72rem; }
|
| 321 |
+
|
| 322 |
+
.proof-graph {
|
| 323 |
+
display: grid;
|
| 324 |
+
grid-template-columns: repeat(7, minmax(80px, 1fr));
|
| 325 |
+
align-items: center;
|
| 326 |
+
gap: .6rem;
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
.graph-node {
|
| 330 |
+
min-height: 132px;
|
| 331 |
+
padding: 1rem;
|
| 332 |
+
border: 1px solid var(--line);
|
| 333 |
+
border-radius: 12px;
|
| 334 |
+
background: var(--ink);
|
| 335 |
+
}
|
| 336 |
+
|
| 337 |
+
.graph-node span { display: block; margin-bottom: .7rem; color: var(--muted); font-size: .7rem; }
|
| 338 |
+
.graph-node strong { overflow-wrap: anywhere; font: .73rem var(--mono); }
|
| 339 |
+
.graph-node.observed { border-color: rgba(95, 179, 163, .65); }
|
| 340 |
+
.graph-node.reported { border-color: rgba(201, 183, 135, .7); }
|
| 341 |
+
.graph-node.unavailable { border-color: #596473; }
|
| 342 |
+
.graph-node.blocked { border-color: rgba(255, 114, 114, .7); }
|
| 343 |
+
.edge { position: relative; min-height: 44px; border-top: 1px dashed var(--muted); }
|
| 344 |
+
.edge span { position: absolute; top: .35rem; left: 50%; width: 100%; color: var(--muted); font: .68rem var(--mono); text-align: center; transform: translateX(-50%); }
|
| 345 |
+
.edge.blocked { border-color: var(--rose); }
|
| 346 |
+
|
| 347 |
+
.boundary-note {
|
| 348 |
+
margin: 1.4rem 0 0;
|
| 349 |
+
padding: .85rem 1rem;
|
| 350 |
+
border-left: 3px solid var(--amber);
|
| 351 |
+
color: #c9d0d8;
|
| 352 |
+
background: rgba(255, 196, 94, .05);
|
| 353 |
+
font: .74rem var(--mono);
|
| 354 |
+
overflow-wrap: anywhere;
|
| 355 |
+
}
|
| 356 |
+
|
| 357 |
+
.split-panel { display: grid; grid-template-columns: minmax(0, 1.2fr) minmax(280px, .8fr); gap: 2.5rem; }
|
| 358 |
+
.split-panel p:not(.eyebrow) { max-width: 68ch; color: var(--muted); }
|
| 359 |
+
.budget-list { margin: 0; }
|
| 360 |
+
.budget-list div { display: grid; grid-template-columns: 1fr auto; gap: 1rem; padding: .7rem 0; border-bottom: 1px solid var(--line); }
|
| 361 |
+
.budget-list dt { color: var(--muted); }
|
| 362 |
+
.budget-list dd { margin: 0; font: 700 .72rem var(--mono); }
|
| 363 |
+
|
| 364 |
+
.atelier-panel { background: linear-gradient(135deg, rgba(21, 13, 31, .9), rgba(9, 13, 18, .93)); }
|
| 365 |
+
.atelier-flow { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: .7rem; margin: 0; padding: 0; list-style: none; counter-reset: none; }
|
| 366 |
+
.atelier-flow li { display: flex; gap: .8rem; min-height: 170px; padding: 1rem; border: 1px solid var(--line); border-radius: 12px; }
|
| 367 |
+
.atelier-flow > li > span { color: var(--violet); font: .72rem var(--mono); }
|
| 368 |
+
.atelier-flow strong { display: block; font-size: .9rem; }
|
| 369 |
+
.atelier-flow p { color: var(--muted); font-size: .78rem; }
|
| 370 |
+
|
| 371 |
+
.text-link { color: var(--cyan); font: .75rem var(--mono); }
|
| 372 |
+
.proof-list { display: grid; gap: .55rem; margin: 0; padding: 0; list-style: none; }
|
| 373 |
+
.proof-list li { display: grid; grid-template-columns: minmax(110px, .7fr) minmax(190px, 1.6fr) minmax(130px, .8fr) auto; gap: 1rem; padding: .8rem .9rem; border: 1px solid var(--line); border-radius: 10px; font: .75rem var(--mono); }
|
| 374 |
+
.proof-list code { color: var(--cyan); overflow-wrap: anywhere; }
|
| 375 |
+
|
| 376 |
+
.truth-footer {
|
| 377 |
+
display: grid;
|
| 378 |
+
grid-template-columns: minmax(0, 2fr) minmax(220px, .7fr);
|
| 379 |
+
gap: 2rem;
|
| 380 |
+
padding: 1.4rem;
|
| 381 |
+
border: 1px solid var(--line);
|
| 382 |
+
border-radius: var(--radius);
|
| 383 |
+
color: var(--muted);
|
| 384 |
+
background: #070a0e;
|
| 385 |
+
font: .72rem var(--mono);
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
.truth-footer p { margin: 0; }
|
| 389 |
+
.truth-footer strong { color: var(--paper); }
|
| 390 |
+
#view-status { color: var(--acid); text-align: right; }
|
| 391 |
+
|
| 392 |
+
.noscript {
|
| 393 |
+
margin: 1rem;
|
| 394 |
+
padding: 1rem;
|
| 395 |
+
border: 1px solid var(--amber);
|
| 396 |
+
color: var(--paper);
|
| 397 |
+
background: var(--panel);
|
| 398 |
+
}
|
| 399 |
+
|
| 400 |
+
@media (max-width: 1180px) {
|
| 401 |
+
.metric-band { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
| 402 |
+
.metric-band article:nth-child(3) { border-right: 0; }
|
| 403 |
+
.metric-band article:nth-child(-n + 3) { border-bottom: 1px solid var(--line); }
|
| 404 |
+
.command-grid, .atelier-flow { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
| 405 |
+
.proof-graph { grid-template-columns: 1fr; }
|
| 406 |
+
.edge { min-height: 44px; width: 1px; margin: 0 auto; border-top: 0; border-left: 1px dashed var(--muted); }
|
| 407 |
+
.edge span { top: 50%; left: 1rem; width: max-content; transform: translateY(-50%); }
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
@media (max-width: 980px) {
|
| 411 |
+
.proof-list li { grid-template-columns: 1fr; }
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
@media (max-width: 820px) {
|
| 415 |
+
.topbar { grid-template-columns: 1fr auto; }
|
| 416 |
+
.mode-lock { grid-column: 1 / -1; grid-row: 2; }
|
| 417 |
+
.hero { grid-template-columns: 1fr; padding-top: 4rem; }
|
| 418 |
+
h1 { font-size: clamp(3rem, 16vw, 5.6rem); }
|
| 419 |
+
.workspace { grid-template-columns: 1fr; }
|
| 420 |
+
.rail { position: static; display: flex; overflow-x: auto; padding-bottom: .5rem; }
|
| 421 |
+
.rail a { flex: 0 0 auto; border-left: 0; border-bottom: 2px solid transparent; }
|
| 422 |
+
.rail a:hover, .rail a.active { border-left-color: transparent; border-bottom-color: var(--acid); }
|
| 423 |
+
.split-panel, .truth-footer { grid-template-columns: 1fr; }
|
| 424 |
+
#view-status { text-align: left; }
|
| 425 |
+
.proof-list li { grid-template-columns: 1fr; }
|
| 426 |
+
}
|
| 427 |
+
|
| 428 |
+
@media (max-width: 560px) {
|
| 429 |
+
.topbar { padding-inline: .8rem; }
|
| 430 |
+
.brand span:last-child { display: none; }
|
| 431 |
+
.quiet-button { padding-inline: .7rem; }
|
| 432 |
+
.hero { padding-inline: 1rem; }
|
| 433 |
+
.metric-band { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
| 434 |
+
.metric-band article:nth-child(2n) { border-right: 0; }
|
| 435 |
+
.metric-band article:nth-child(3) { border-right: 1px solid var(--line); }
|
| 436 |
+
.metric-band article:nth-child(-n + 4) { border-bottom: 1px solid var(--line); }
|
| 437 |
+
.command-grid, .atelier-flow { grid-template-columns: 1fr; }
|
| 438 |
+
.state-card, .atelier-flow li { min-height: auto; }
|
| 439 |
+
.panel-head { display: grid; }
|
| 440 |
+
.as-of, .legend { text-align: left; }
|
| 441 |
+
.identity-card div { grid-template-columns: 1fr; gap: .25rem; padding: .65rem 0; }
|
| 442 |
+
.identity-card dd { text-align: left; }
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
@media (forced-colors: active) {
|
| 446 |
+
h1 em {
|
| 447 |
+
color: CanvasText;
|
| 448 |
+
-webkit-text-stroke: 0;
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
.status,
|
| 452 |
+
.graph-node,
|
| 453 |
+
.panel,
|
| 454 |
+
.state-card {
|
| 455 |
+
forced-color-adjust: auto;
|
| 456 |
+
}
|
| 457 |
+
}
|
| 458 |
+
|
| 459 |
+
@media (prefers-reduced-motion: reduce) {
|
| 460 |
+
*, *::before, *::after {
|
| 461 |
+
scroll-behavior: auto !important;
|
| 462 |
+
transition-duration: .01ms !important;
|
| 463 |
+
animation-duration: .01ms !important;
|
| 464 |
+
animation-iteration-count: 1 !important;
|
| 465 |
+
}
|
| 466 |
+
}
|
routers/frontier_reads.py
CHANGED
|
@@ -16,7 +16,9 @@ this group, so it moves here with the routes. Registered BEFORE the /api/a11oy/
|
|
| 16 |
|
| 17 |
The additive Series-A controller is registered at this same pre-catch-all seam. It
|
| 18 |
keeps GET/HEAD read-only, uses explicit POSTs for refresh/evaluate/execute, and
|
| 19 |
-
fails one surface closed without taking down the existing frontier reads.
|
|
|
|
|
|
|
| 20 |
|
| 21 |
Signed-off-by: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
|
| 22 |
"""
|
|
@@ -101,15 +103,31 @@ def register(app) -> dict:
|
|
| 101 |
"effectors": [],
|
| 102 |
}
|
| 103 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
return {
|
| 105 |
"ok": True,
|
| 106 |
"ns": "a11oy",
|
| 107 |
"group": "frontier-reads",
|
| 108 |
"series_a": series_a,
|
|
|
|
| 109 |
"routes": [
|
| 110 |
"/api/a11oy/v1/forecast-baseline", "/v1/forecast-baseline",
|
| 111 |
"/api/a11oy/v1/vertical-packs", "/v1/vertical-packs",
|
| 112 |
"/api/a11oy/v1/observability/business", "/v1/observability/business",
|
| 113 |
"/series-a", "/api/a11oy/v1/series-a/status",
|
|
|
|
|
|
|
|
|
|
| 114 |
],
|
| 115 |
}
|
|
|
|
| 16 |
|
| 17 |
The additive Series-A controller is registered at this same pre-catch-all seam. It
|
| 18 |
keeps GET/HEAD read-only, uses explicit POSTs for refresh/evaluate/execute, and
|
| 19 |
+
fails one surface closed without taking down the existing frontier reads. Frontier
|
| 20 |
+
Now is a read-only projection over that controller: no second store, signer,
|
| 21 |
+
credential, scheduler, passport authority, or effector.
|
| 22 |
|
| 23 |
Signed-off-by: Stephen P. Lutar Jr. <stephenlutar2@gmail.com>
|
| 24 |
"""
|
|
|
|
| 103 |
"effectors": [],
|
| 104 |
}
|
| 105 |
|
| 106 |
+
try:
|
| 107 |
+
from routers import frontier_now_control_plane as _frontier_now
|
| 108 |
+
|
| 109 |
+
frontier_now = _frontier_now.register(app, ns="a11oy")
|
| 110 |
+
except Exception as exc: # one read projection must never take down A11oy
|
| 111 |
+
frontier_now = {
|
| 112 |
+
"ok": False,
|
| 113 |
+
"state": "UNAVAILABLE",
|
| 114 |
+
"reason": type(exc).__name__,
|
| 115 |
+
"effectors": [],
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
return {
|
| 119 |
"ok": True,
|
| 120 |
"ns": "a11oy",
|
| 121 |
"group": "frontier-reads",
|
| 122 |
"series_a": series_a,
|
| 123 |
+
"frontier_now": frontier_now,
|
| 124 |
"routes": [
|
| 125 |
"/api/a11oy/v1/forecast-baseline", "/v1/forecast-baseline",
|
| 126 |
"/api/a11oy/v1/vertical-packs", "/v1/vertical-packs",
|
| 127 |
"/api/a11oy/v1/observability/business", "/v1/observability/business",
|
| 128 |
"/series-a", "/api/a11oy/v1/series-a/status",
|
| 129 |
+
"/frontier-now", "/now",
|
| 130 |
+
"/api/a11oy/v1/frontier-now/summary",
|
| 131 |
+
"/api/a11oy/v1/frontier-now/inventory",
|
| 132 |
],
|
| 133 |
}
|