Spaces:
Running
Running
series-a: sync Command Center from merged a11oy#1484 (MEASURED inventory, not a Hub write)
Browse files- routers/series_a_web/app.js +275 -21
- routers/series_a_web/index.html +135 -28
- routers/series_a_web/styles.css +91 -1
routers/series_a_web/app.js
CHANGED
|
@@ -1,5 +1,264 @@
|
|
| 1 |
(() => {
|
| 2 |
"use strict";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
const API = "/api/a11oy/v1/series-a";
|
| 4 |
const EXECUTION_TIMEOUT_MS = 135000;
|
| 5 |
const DEFAULT_TARGETS = {
|
|
@@ -33,16 +292,11 @@
|
|
| 33 |
evaluationRevision += 1;
|
| 34 |
resetExecution();
|
| 35 |
};
|
| 36 |
-
const sha256 = async (text) => {
|
| 37 |
-
const bytes = new TextEncoder().encode(text);
|
| 38 |
-
const digest = await crypto.subtle.digest("SHA-256", bytes);
|
| 39 |
-
return [...new Uint8Array(digest)].map(value => value.toString(16).padStart(2, "0")).join("");
|
| 40 |
-
};
|
| 41 |
const request = async (path, options = {}, timeoutMs = 8000) => {
|
| 42 |
const controller = new AbortController();
|
| 43 |
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
| 44 |
try {
|
| 45 |
-
const response = await fetch(API + path, {cache: "no-store", ...options, signal: controller.signal});
|
| 46 |
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
| 47 |
return await response.json();
|
| 48 |
} finally { clearTimeout(timer); }
|
|
@@ -77,14 +331,14 @@
|
|
| 77 |
} : null;
|
| 78 |
document.getElementById("updated").textContent = status.observed_at ? `Observed ${status.observed_at}` : status.detail || "Terminal state reached";
|
| 79 |
const list = document.getElementById("receipts");
|
| 80 |
-
list.replaceChildren(...(receipts.items || []).slice(0, 8).map(item => {
|
| 81 |
const li = document.createElement("li");
|
| 82 |
li.textContent = `${item.kind} · ${item.receipt_hash.slice(0, 14)}… · ${item.envelope.signature_status}`;
|
| 83 |
return li;
|
| 84 |
}));
|
| 85 |
if (!list.children.length) list.innerHTML = "<li>OBSERVED · no receipts yet</li>";
|
| 86 |
} catch (error) {
|
| 87 |
-
["estate", "trust", "signer"].forEach(key => set(key, error.name === "AbortError" ? "TIMED_OUT" : "UNAVAILABLE"));
|
| 88 |
document.getElementById("updated").textContent = error.name === "AbortError" ? "Timed out after 8 seconds" : String(error.message || error);
|
| 89 |
}
|
| 90 |
};
|
|
@@ -98,7 +352,7 @@
|
|
| 98 |
}
|
| 99 |
const evaluated = await request("/passports/evaluate", {
|
| 100 |
method: "POST",
|
| 101 |
-
headers: {"content-type": "application/json"},
|
| 102 |
body: JSON.stringify({
|
| 103 |
principal_id: "series-a-ui",
|
| 104 |
action: {
|
|
@@ -107,7 +361,7 @@
|
|
| 107 |
impact: "MODERATE",
|
| 108 |
irreversible: false
|
| 109 |
},
|
| 110 |
-
evidence: [{...currentEvidence}],
|
| 111 |
expected_if_withheld: "Current estate observation remains unchanged",
|
| 112 |
expected_if_acted: "A bounded governed estate refresh completes or fails closed"
|
| 113 |
})
|
|
@@ -121,8 +375,8 @@
|
|
| 121 |
}
|
| 122 |
const value = await request("/passports/execute", {
|
| 123 |
method: "POST",
|
| 124 |
-
headers: {"content-type": "application/json"},
|
| 125 |
-
body: JSON.stringify({passport_digest: evaluated.passport_digest})
|
| 126 |
}, EXECUTION_TIMEOUT_MS);
|
| 127 |
if (value.outcome?.status !== "SUCCEEDED") {
|
| 128 |
throw new Error(
|
|
@@ -160,14 +414,14 @@
|
|
| 160 |
});
|
| 161 |
const evidence = (
|
| 162 |
selectedLabel === "OBSERVED" && currentEvidence
|
| 163 |
-
) ? [{...currentEvidence}] : [{
|
| 164 |
evidence_id: "ui-unverified",
|
| 165 |
label: "UNKNOWN",
|
| 166 |
content_digest: await sha256(evidenceStatement)
|
| 167 |
}];
|
| 168 |
const body = {
|
| 169 |
principal_id: "series-a-ui",
|
| 170 |
-
action: {type: form.get("type"), target: form.get("target"), impact: "MODERATE", irreversible: false},
|
| 171 |
evidence,
|
| 172 |
expected_if_withheld: "Current state persists",
|
| 173 |
expected_if_acted: "Bounded action completes or fails closed"
|
|
@@ -175,12 +429,12 @@
|
|
| 175 |
const output = document.getElementById("passport-result");
|
| 176 |
output.textContent = "EVALUATING";
|
| 177 |
try {
|
| 178 |
-
const value = await request("/passports/evaluate", {method: "POST", headers: {"content-type": "application/json"}, body: JSON.stringify(body)});
|
| 179 |
if (revision !== evaluationRevision) {
|
| 180 |
output.textContent = "STALE · form changed before evaluation completed";
|
| 181 |
return;
|
| 182 |
}
|
| 183 |
-
output.textContent = JSON.stringify({decision: value.passport.decision, reason_codes: value.passport.reason_codes, passport_digest: value.passport_digest, signature_status: value.decision_receipt.envelope.signature_status}, null, 2);
|
| 184 |
if (value.passport.decision === "ALLOW") {
|
| 185 |
executableDigest = value.passport_digest;
|
| 186 |
executeButton.disabled = false;
|
|
@@ -209,9 +463,9 @@
|
|
| 209 |
const value = await request(
|
| 210 |
`/passports/outcomes/${encodeURIComponent(passportDigest)}`
|
| 211 |
);
|
| 212 |
-
return {outcome: value.outcome, receipt: value.outcome_receipt};
|
| 213 |
} catch {}
|
| 214 |
-
await new Promise(resolve => setTimeout(resolve, 2000));
|
| 215 |
}
|
| 216 |
return null;
|
| 217 |
};
|
|
@@ -224,8 +478,8 @@
|
|
| 224 |
try {
|
| 225 |
const value = await request("/passports/execute", {
|
| 226 |
method: "POST",
|
| 227 |
-
headers: {"content-type": "application/json"},
|
| 228 |
-
body: JSON.stringify({passport_digest: passportDigest})
|
| 229 |
}, EXECUTION_TIMEOUT_MS);
|
| 230 |
renderOutcome(value.outcome, value.outcome_receipt);
|
| 231 |
} catch (error) {
|
|
@@ -251,7 +505,7 @@
|
|
| 251 |
};
|
| 252 |
if ("EventSource" in window) {
|
| 253 |
const source = new EventSource(API + "/events");
|
| 254 |
-
EVENT_KINDS.forEach(kind => source.addEventListener(kind, appendEvent));
|
| 255 |
source.addEventListener("open", () => {
|
| 256 |
if (eventRail.firstElementChild?.textContent === "CONNECTING") {
|
| 257 |
eventRail.firstElementChild.textContent = "CONNECTED · waiting for governed events";
|
|
|
|
| 1 |
(() => {
|
| 2 |
"use strict";
|
| 3 |
+
|
| 4 |
+
const VIEWS = ["command", "estate", "claims", "policy", "twin", "passport", "audit"];
|
| 5 |
+
const KEEP = [
|
| 6 |
+
{ id: "SZLHOLDINGS/README", role: "Org card", href: "https://huggingface.co/SZLHOLDINGS" },
|
| 7 |
+
{ id: "SZLHOLDINGS/a11oy", role: "Product Command Center", href: "https://a-11-oy.com" },
|
| 8 |
+
{ id: "SZLHOLDINGS/killinchu", role: "Defense vertical", href: "https://huggingface.co/spaces/SZLHOLDINGS/killinchu" },
|
| 9 |
+
{ id: "SZLHOLDINGS/immune", role: "Safety kernel", href: "https://huggingface.co/spaces/SZLHOLDINGS/immune" },
|
| 10 |
+
{ id: "SZLHOLDINGS/szl-khipu", role: "Model demo", href: "https://huggingface.co/spaces/SZLHOLDINGS/szl-khipu" },
|
| 11 |
+
{ id: "SZLHOLDINGS/szl-atelier", role: "Artifact walk", href: "https://huggingface.co/spaces/SZLHOLDINGS/szl-atelier" },
|
| 12 |
+
{ id: "SZLHOLDINGS/governed-receipt-verifier", role: "Receipt replay", href: "https://a11oy.net" }
|
| 13 |
+
];
|
| 14 |
+
const CLAIMS = [
|
| 15 |
+
["CLM-ORG-REPOS", "Public GitHub repositories in org szl-holdings", "98", "LIVE"],
|
| 16 |
+
["CLM-HF-MODELS", "Hugging Face models under SZLHOLDINGS", "43", "LIVE"],
|
| 17 |
+
["CLM-HF-SPACES", "Hugging Face Spaces under SZLHOLDINGS", "authenticated 7 including README card · unauth author-list 6 · 45 total", "MEASURED"],
|
| 18 |
+
["CLM-HF-DATASETS", "Hugging Face datasets under SZLHOLDINGS", "36", "LIVE"],
|
| 19 |
+
["CLM-KHIPU-DL", "SZL-Khipu-1.5B downloads", "502", "LIVE"],
|
| 20 |
+
["CLM-KHIPU-GGUF-DL", "SZL-Khipu-1.5B-GGUF downloads", "553", "LIVE"],
|
| 21 |
+
["CLM-FORGE-DL", "SZL-Forge-1.5B-ReceiptAgent downloads", "493", "LIVE"],
|
| 22 |
+
["CLM-NORM-DL", "szl-governed-norm downloads", "209", "SNAPSHOT"],
|
| 23 |
+
["CLM-LAMBDA-DL", "szl-lambda-gate downloads", "100", "SNAPSHOT"],
|
| 24 |
+
["CLM-TABLES-848", "Database tables (verified 2026-05-12)", "848", "SNAPSHOT"],
|
| 25 |
+
["CLM-ENDPOINTS-5524", "API endpoint declarations (verified 2026-05-12)", "5,524", "SNAPSHOT"],
|
| 26 |
+
["CLM-TESTS-1220", "Passing platform tests (verified 2026-05-12)", "1,220", "SNAPSHOT"],
|
| 27 |
+
["CLM-LAMBDA-MS", "Λ overhead median (verified 2026-05-12)", "≤0.59 ms", "SNAPSHOT"],
|
| 28 |
+
["CLM-DOCTRINE", "Doctrine lock", "v11 LOCKED", "LIVE"],
|
| 29 |
+
["CLM-LAMBDA", "Λ uniqueness", "Conjecture 1 — not a closed theorem", "LIVE"],
|
| 30 |
+
["CLM-LOCKED-8", "Locked-proven formulas", "8 · F1 F4 F7 F11 F12 F18 F19 F22", "LIVE"],
|
| 31 |
+
["CLM-LEAN-COUNTS", "lutar-lean pin (declarations / axioms / sorries)", "749 / 14 / 163", "LIVE"],
|
| 32 |
+
["CLM-TRUST-CEILING", "Trust ceiling claimed on README", "omitted from /honest", "SNAPSHOT"],
|
| 33 |
+
["CLM-SHARE-LINKS", "Four ChatGPT share-link transcripts", "unfetchable", "UNKNOWN"],
|
| 34 |
+
["CLM-HF-WRITE", "Hugging Face write from this surface", "not claimed here", "UNAVAILABLE"],
|
| 35 |
+
["CLM-BOSS", "boss.technologies identity", "BLOCKED_IDENTITY", "UNKNOWN"]
|
| 36 |
+
];
|
| 37 |
+
const CONTRADICTIONS = [
|
| 38 |
+
["CTR-KHIPU-DL", "BLOCKER", "Khipu download count", "Prior ~2.36k vs live 502. Retire 2.36k."],
|
| 39 |
+
["CTR-LEXICON", "HIGH", "Naming lexicon drift", "Canonical: a11oy — governed execution fabric. Product a-11-oy.com · proof a11oy.net · never a11oy.com."],
|
| 40 |
+
["CTR-STALE-METRICS", "HIGH", "May 12 platform metrics", "848 tables / 5,524 endpoints / 1,220 tests / ≤0.59 ms Λ stay SNAPSHOT."],
|
| 41 |
+
["CTR-SPACES", "MEDIUM", "Keep-set listings disagree", "Unauth author-list is 6. Authenticated recapture includes README card. This page does not rewrite the published atlas."],
|
| 42 |
+
["CTR-SPRAWL", "MEDIUM", "Repo sprawl vs canonical home", "98 repositories. Bind as packages. Do not mint a new flagship."],
|
| 43 |
+
["CTR-TRUST-CEILING", "LOW", "Trust ceiling missing from honest API", "Either emit it from /honest or stop putting it on the first fold."]
|
| 44 |
+
];
|
| 45 |
+
const TOOLS = [
|
| 46 |
+
["echo.ping", "NONE", "admitted"],
|
| 47 |
+
["receipt.inspect", "NONE", "admitted"],
|
| 48 |
+
["policy.propose", "NONE", "operator"],
|
| 49 |
+
["aql.query", "NONE", "admitted"],
|
| 50 |
+
["fixture.rollback", "REVERSIBLE", "operator"],
|
| 51 |
+
["prod.write", "IRREVERSIBLE", "prohibited"],
|
| 52 |
+
["shell.exec", "IRREVERSIBLE", "prohibited"]
|
| 53 |
+
];
|
| 54 |
+
const AUDIT = [
|
| 55 |
+
["B1", "LIVE", "Canonical home is szl-holdings/a11oy — no 20th repo minted this session"],
|
| 56 |
+
["B2", "LIVE", "Lexicon locked: a11oy — governed execution fabric"],
|
| 57 |
+
["B3", "LIVE", "Claims ledger exists; May 12 metrics degraded to SNAPSHOT"],
|
| 58 |
+
["B4", "LIVE", "Contradiction ledger scored separately from claims"],
|
| 59 |
+
["B5", "LIVE", "Vertical slice uses a fixture tool, never a production connector"],
|
| 60 |
+
["B6", "LIVE", "Receipts DEMO_SIGNED; DSSE UNAVAILABLE; PENDING_SYNC visible"],
|
| 61 |
+
["B7", "MEASURED", "This page does not claim a Hub write. Authenticated recapture includes the README card; unauth author-list omits it."],
|
| 62 |
+
["B8", "UNKNOWN", "ChatGPT share-link transcripts UNKNOWN — not fabricated"],
|
| 63 |
+
["B9", "MODELED", "Bricklayer IP-risk register populated before policy-enforcement code"],
|
| 64 |
+
["B10", "LIVE", "Calibration Plane proposal-only, outside TCB"]
|
| 65 |
+
];
|
| 66 |
+
|
| 67 |
+
const badgeClass = (state) => {
|
| 68 |
+
const key = String(state || "").toLowerCase();
|
| 69 |
+
if (key === "live" || key === "admitted" || key === "measured") return "badge live";
|
| 70 |
+
if (key === "snapshot" || key === "modeled") return "badge snapshot";
|
| 71 |
+
if (key === "blocker" || key === "prohibited") return "badge blocker";
|
| 72 |
+
return "badge unknown";
|
| 73 |
+
};
|
| 74 |
+
|
| 75 |
+
const showView = () => {
|
| 76 |
+
const raw = (location.hash || "#command").replace(/^#/, "");
|
| 77 |
+
const view = VIEWS.includes(raw) ? raw : "command";
|
| 78 |
+
document.querySelectorAll("[data-view]").forEach((el) => {
|
| 79 |
+
el.hidden = el.getAttribute("data-view") !== view;
|
| 80 |
+
});
|
| 81 |
+
document.querySelectorAll("[data-nav]").forEach((a) => {
|
| 82 |
+
if (a.getAttribute("data-nav") === view) a.setAttribute("aria-current", "page");
|
| 83 |
+
else a.removeAttribute("aria-current");
|
| 84 |
+
});
|
| 85 |
+
};
|
| 86 |
+
window.addEventListener("hashchange", showView);
|
| 87 |
+
showView();
|
| 88 |
+
|
| 89 |
+
const fillList = (id, rows, render) => {
|
| 90 |
+
const node = document.getElementById(id);
|
| 91 |
+
if (!node) return;
|
| 92 |
+
node.replaceChildren(...rows.map(render));
|
| 93 |
+
};
|
| 94 |
+
fillList("keep-list", KEEP, (item) => {
|
| 95 |
+
const li = document.createElement("li");
|
| 96 |
+
const a = document.createElement("a");
|
| 97 |
+
a.className = "id";
|
| 98 |
+
a.href = item.href;
|
| 99 |
+
a.textContent = item.id;
|
| 100 |
+
if (/^https?:/.test(item.href)) {
|
| 101 |
+
a.target = "_blank";
|
| 102 |
+
a.rel = "noopener";
|
| 103 |
+
}
|
| 104 |
+
const role = document.createElement("span");
|
| 105 |
+
role.className = "badge live";
|
| 106 |
+
role.textContent = item.role;
|
| 107 |
+
li.append(a, role);
|
| 108 |
+
return li;
|
| 109 |
+
});
|
| 110 |
+
const claimsBody = document.getElementById("claims-body");
|
| 111 |
+
if (claimsBody) {
|
| 112 |
+
claimsBody.replaceChildren(...CLAIMS.map(([id, statement, value, state]) => {
|
| 113 |
+
const tr = document.createElement("tr");
|
| 114 |
+
const cells = [id, statement, value, state];
|
| 115 |
+
cells.forEach((text, index) => {
|
| 116 |
+
const td = document.createElement("td");
|
| 117 |
+
if (index === 3) {
|
| 118 |
+
const span = document.createElement("span");
|
| 119 |
+
span.className = badgeClass(state);
|
| 120 |
+
span.textContent = state;
|
| 121 |
+
td.append(span);
|
| 122 |
+
} else {
|
| 123 |
+
td.textContent = text;
|
| 124 |
+
}
|
| 125 |
+
tr.append(td);
|
| 126 |
+
});
|
| 127 |
+
return tr;
|
| 128 |
+
}));
|
| 129 |
+
}
|
| 130 |
+
fillList("ctr-list", CONTRADICTIONS, ([id, sev, title, remedy]) => {
|
| 131 |
+
const li = document.createElement("li");
|
| 132 |
+
const name = document.createElement("span");
|
| 133 |
+
name.className = "id";
|
| 134 |
+
name.textContent = `${id} · ${title}`;
|
| 135 |
+
const note = document.createElement("span");
|
| 136 |
+
note.textContent = remedy;
|
| 137 |
+
note.style.color = "var(--muted)";
|
| 138 |
+
note.style.flex = "1";
|
| 139 |
+
const badge = document.createElement("span");
|
| 140 |
+
badge.className = badgeClass(sev);
|
| 141 |
+
badge.textContent = sev;
|
| 142 |
+
li.append(name, note, badge);
|
| 143 |
+
return li;
|
| 144 |
+
});
|
| 145 |
+
fillList("tools-list", TOOLS, ([name, cls, status]) => {
|
| 146 |
+
const li = document.createElement("li");
|
| 147 |
+
const id = document.createElement("span");
|
| 148 |
+
id.className = "id";
|
| 149 |
+
id.textContent = `${name} · ${cls}`;
|
| 150 |
+
const badge = document.createElement("span");
|
| 151 |
+
badge.className = badgeClass(status);
|
| 152 |
+
badge.textContent = status;
|
| 153 |
+
li.append(id, badge);
|
| 154 |
+
return li;
|
| 155 |
+
});
|
| 156 |
+
fillList("audit-list", AUDIT, ([id, state, item]) => {
|
| 157 |
+
const li = document.createElement("li");
|
| 158 |
+
const idEl = document.createElement("span");
|
| 159 |
+
idEl.className = "id";
|
| 160 |
+
idEl.textContent = `${id} · ${item}`;
|
| 161 |
+
const badge = document.createElement("span");
|
| 162 |
+
badge.className = badgeClass(state);
|
| 163 |
+
badge.textContent = state;
|
| 164 |
+
li.append(idEl, badge);
|
| 165 |
+
return li;
|
| 166 |
+
});
|
| 167 |
+
|
| 168 |
+
const encoder = new TextEncoder();
|
| 169 |
+
const sha256 = async (text) => {
|
| 170 |
+
const digest = await crypto.subtle.digest("SHA-256", encoder.encode(text));
|
| 171 |
+
return [...new Uint8Array(digest)].map((value) => value.toString(16).padStart(2, "0")).join("");
|
| 172 |
+
};
|
| 173 |
+
const hmacHex = async (keyRaw, msg) => {
|
| 174 |
+
const key = await crypto.subtle.importKey(
|
| 175 |
+
"raw",
|
| 176 |
+
encoder.encode(keyRaw),
|
| 177 |
+
{ name: "HMAC", hash: "SHA-256" },
|
| 178 |
+
false,
|
| 179 |
+
["sign"]
|
| 180 |
+
);
|
| 181 |
+
const sig = await crypto.subtle.sign("HMAC", key, encoder.encode(msg));
|
| 182 |
+
return [...new Uint8Array(sig)].map((value) => value.toString(16).padStart(2, "0")).join("");
|
| 183 |
+
};
|
| 184 |
+
const getDemoKey = async () => {
|
| 185 |
+
const existing = localStorage.getItem("a11oy.demo-key");
|
| 186 |
+
if (existing) return existing;
|
| 187 |
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
| 188 |
+
const key = [...bytes].map((b) => b.toString(16).padStart(2, "0")).join("");
|
| 189 |
+
localStorage.setItem("a11oy.demo-key", key);
|
| 190 |
+
return key;
|
| 191 |
+
};
|
| 192 |
+
const FIXTURE = {
|
| 193 |
+
id: "acc-fixture-v1",
|
| 194 |
+
version: "1.0.0",
|
| 195 |
+
expiresAt: "2026-11-27T16:00:00Z",
|
| 196 |
+
prohibited: ["shell.exec", "prod.write", "unsloth.codex"],
|
| 197 |
+
tools: {
|
| 198 |
+
"echo.ping": { allowed: true, cls: "NONE" },
|
| 199 |
+
"receipt.inspect": { allowed: true, cls: "NONE" },
|
| 200 |
+
"policy.propose": { allowed: true, cls: "NONE" },
|
| 201 |
+
"shell.exec": { allowed: false, cls: "IRREVERSIBLE" },
|
| 202 |
+
"prod.write": { allowed: false, cls: "IRREVERSIBLE" }
|
| 203 |
+
}
|
| 204 |
+
};
|
| 205 |
+
const twinForm = document.getElementById("twin-form");
|
| 206 |
+
if (twinForm) {
|
| 207 |
+
twinForm.addEventListener("submit", async (event) => {
|
| 208 |
+
event.preventDefault();
|
| 209 |
+
const tool = document.getElementById("twin-tool").value;
|
| 210 |
+
const arg = document.getElementById("twin-arg").value;
|
| 211 |
+
const spec = FIXTURE.tools[tool];
|
| 212 |
+
const expired = Date.parse(FIXTURE.expiresAt) < Date.now();
|
| 213 |
+
let decision = "ALLOW";
|
| 214 |
+
let reason = "Constitution admits the fixture.";
|
| 215 |
+
if (expired) {
|
| 216 |
+
decision = "DENY";
|
| 217 |
+
reason = "Constitution expired. Authority that cannot go stale cannot be audited.";
|
| 218 |
+
} else if (!spec) {
|
| 219 |
+
decision = "DENY";
|
| 220 |
+
reason = `Unknown tool ${tool}. Deny by default.`;
|
| 221 |
+
} else if (!spec.allowed || FIXTURE.prohibited.includes(tool)) {
|
| 222 |
+
decision = "DENY";
|
| 223 |
+
reason = `${tool} is prohibited. Not in the trusted computing base of this slice.`;
|
| 224 |
+
}
|
| 225 |
+
let payload;
|
| 226 |
+
if (decision === "ALLOW") {
|
| 227 |
+
if (tool === "echo.ping") payload = { pong: arg || "ok", ts: new Date().toISOString() };
|
| 228 |
+
else if (tool === "receipt.inspect") payload = { target: arg, intact: true };
|
| 229 |
+
else payload = { proposal: arg, executed: false, note: "Propose never execute." };
|
| 230 |
+
} else {
|
| 231 |
+
payload = { denied: tool, reason };
|
| 232 |
+
}
|
| 233 |
+
const payloadStr = JSON.stringify(payload);
|
| 234 |
+
const payloadHash = await sha256(payloadStr);
|
| 235 |
+
const body = JSON.stringify({
|
| 236 |
+
tool,
|
| 237 |
+
decision,
|
| 238 |
+
constitutionId: FIXTURE.id,
|
| 239 |
+
constitutionVersion: FIXTURE.version,
|
| 240 |
+
payloadHash
|
| 241 |
+
});
|
| 242 |
+
const receiptHash = await sha256(body);
|
| 243 |
+
const signature = await hmacHex(await getDemoKey(), receiptHash);
|
| 244 |
+
document.getElementById("twin-result").textContent = JSON.stringify({
|
| 245 |
+
tool,
|
| 246 |
+
decision,
|
| 247 |
+
reason,
|
| 248 |
+
payload,
|
| 249 |
+
payloadHash,
|
| 250 |
+
receiptHash,
|
| 251 |
+
signature,
|
| 252 |
+
signatureState: "DEMO_SIGNED",
|
| 253 |
+
dsseEnvelope: "UNAVAILABLE",
|
| 254 |
+
flightStatus: "LOCAL",
|
| 255 |
+
blastRadius: spec && spec.cls === "NONE"
|
| 256 |
+
? "In-memory fixture only. No network, no disk, no prod."
|
| 257 |
+
: "Would touch production. Refused in this slice."
|
| 258 |
+
}, null, 2);
|
| 259 |
+
});
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
const API = "/api/a11oy/v1/series-a";
|
| 263 |
const EXECUTION_TIMEOUT_MS = 135000;
|
| 264 |
const DEFAULT_TARGETS = {
|
|
|
|
| 292 |
evaluationRevision += 1;
|
| 293 |
resetExecution();
|
| 294 |
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
const request = async (path, options = {}, timeoutMs = 8000) => {
|
| 296 |
const controller = new AbortController();
|
| 297 |
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
| 298 |
try {
|
| 299 |
+
const response = await fetch(API + path, { cache: "no-store", ...options, signal: controller.signal });
|
| 300 |
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
| 301 |
return await response.json();
|
| 302 |
} finally { clearTimeout(timer); }
|
|
|
|
| 331 |
} : null;
|
| 332 |
document.getElementById("updated").textContent = status.observed_at ? `Observed ${status.observed_at}` : status.detail || "Terminal state reached";
|
| 333 |
const list = document.getElementById("receipts");
|
| 334 |
+
list.replaceChildren(...(receipts.items || []).slice(0, 8).map((item) => {
|
| 335 |
const li = document.createElement("li");
|
| 336 |
li.textContent = `${item.kind} · ${item.receipt_hash.slice(0, 14)}… · ${item.envelope.signature_status}`;
|
| 337 |
return li;
|
| 338 |
}));
|
| 339 |
if (!list.children.length) list.innerHTML = "<li>OBSERVED · no receipts yet</li>";
|
| 340 |
} catch (error) {
|
| 341 |
+
["estate", "trust", "signer"].forEach((key) => set(key, error.name === "AbortError" ? "TIMED_OUT" : "UNAVAILABLE"));
|
| 342 |
document.getElementById("updated").textContent = error.name === "AbortError" ? "Timed out after 8 seconds" : String(error.message || error);
|
| 343 |
}
|
| 344 |
};
|
|
|
|
| 352 |
}
|
| 353 |
const evaluated = await request("/passports/evaluate", {
|
| 354 |
method: "POST",
|
| 355 |
+
headers: { "content-type": "application/json" },
|
| 356 |
body: JSON.stringify({
|
| 357 |
principal_id: "series-a-ui",
|
| 358 |
action: {
|
|
|
|
| 361 |
impact: "MODERATE",
|
| 362 |
irreversible: false
|
| 363 |
},
|
| 364 |
+
evidence: [{ ...currentEvidence }],
|
| 365 |
expected_if_withheld: "Current estate observation remains unchanged",
|
| 366 |
expected_if_acted: "A bounded governed estate refresh completes or fails closed"
|
| 367 |
})
|
|
|
|
| 375 |
}
|
| 376 |
const value = await request("/passports/execute", {
|
| 377 |
method: "POST",
|
| 378 |
+
headers: { "content-type": "application/json" },
|
| 379 |
+
body: JSON.stringify({ passport_digest: evaluated.passport_digest })
|
| 380 |
}, EXECUTION_TIMEOUT_MS);
|
| 381 |
if (value.outcome?.status !== "SUCCEEDED") {
|
| 382 |
throw new Error(
|
|
|
|
| 414 |
});
|
| 415 |
const evidence = (
|
| 416 |
selectedLabel === "OBSERVED" && currentEvidence
|
| 417 |
+
) ? [{ ...currentEvidence }] : [{
|
| 418 |
evidence_id: "ui-unverified",
|
| 419 |
label: "UNKNOWN",
|
| 420 |
content_digest: await sha256(evidenceStatement)
|
| 421 |
}];
|
| 422 |
const body = {
|
| 423 |
principal_id: "series-a-ui",
|
| 424 |
+
action: { type: form.get("type"), target: form.get("target"), impact: "MODERATE", irreversible: false },
|
| 425 |
evidence,
|
| 426 |
expected_if_withheld: "Current state persists",
|
| 427 |
expected_if_acted: "Bounded action completes or fails closed"
|
|
|
|
| 429 |
const output = document.getElementById("passport-result");
|
| 430 |
output.textContent = "EVALUATING";
|
| 431 |
try {
|
| 432 |
+
const value = await request("/passports/evaluate", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
|
| 433 |
if (revision !== evaluationRevision) {
|
| 434 |
output.textContent = "STALE · form changed before evaluation completed";
|
| 435 |
return;
|
| 436 |
}
|
| 437 |
+
output.textContent = JSON.stringify({ decision: value.passport.decision, reason_codes: value.passport.reason_codes, passport_digest: value.passport_digest, signature_status: value.decision_receipt.envelope.signature_status }, null, 2);
|
| 438 |
if (value.passport.decision === "ALLOW") {
|
| 439 |
executableDigest = value.passport_digest;
|
| 440 |
executeButton.disabled = false;
|
|
|
|
| 463 |
const value = await request(
|
| 464 |
`/passports/outcomes/${encodeURIComponent(passportDigest)}`
|
| 465 |
);
|
| 466 |
+
return { outcome: value.outcome, receipt: value.outcome_receipt };
|
| 467 |
} catch {}
|
| 468 |
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
| 469 |
}
|
| 470 |
return null;
|
| 471 |
};
|
|
|
|
| 478 |
try {
|
| 479 |
const value = await request("/passports/execute", {
|
| 480 |
method: "POST",
|
| 481 |
+
headers: { "content-type": "application/json" },
|
| 482 |
+
body: JSON.stringify({ passport_digest: passportDigest })
|
| 483 |
}, EXECUTION_TIMEOUT_MS);
|
| 484 |
renderOutcome(value.outcome, value.outcome_receipt);
|
| 485 |
} catch (error) {
|
|
|
|
| 505 |
};
|
| 506 |
if ("EventSource" in window) {
|
| 507 |
const source = new EventSource(API + "/events");
|
| 508 |
+
EVENT_KINDS.forEach((kind) => source.addEventListener(kind, appendEvent));
|
| 509 |
source.addEventListener("open", () => {
|
| 510 |
if (eventRail.firstElementChild?.textContent === "CONNECTING") {
|
| 511 |
eventRail.firstElementChild.textContent = "CONNECTED · waiting for governed events";
|
routers/series_a_web/index.html
CHANGED
|
@@ -3,56 +3,163 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="utf-8">
|
| 5 |
<meta name="viewport" content="width=device-width,initial-scale=1">
|
| 6 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
<link rel="stylesheet" href="/series-a/styles.css?v=__STYLE_ASSET_DIGEST__">
|
| 8 |
</head>
|
| 9 |
<body>
|
| 10 |
-
<a class="skip" href="#main">Skip to
|
| 11 |
-
<header>
|
| 12 |
-
<
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
</header>
|
|
|
|
| 16 |
<main id="main" tabindex="-1">
|
| 17 |
-
<section class="toolbar" aria-label="
|
| 18 |
<button id="refresh" type="button">Run governed refresh</button>
|
| 19 |
<span id="updated" aria-live="polite">Not observed yet</span>
|
| 20 |
</section>
|
| 21 |
-
|
|
|
|
| 22 |
<article><h2>Estate</h2><strong data-key="estate">CHECKING</strong><p>Signed current observation.</p></article>
|
| 23 |
<article><h2>GitHub repos</h2><strong data-key="repos">—</strong><p>Complete paginated census.</p></article>
|
| 24 |
<article><h2>Open PRs</h2><strong data-key="prs">—</strong><p>Current public queue.</p></article>
|
| 25 |
-
<article><h2>HF Spaces</h2><strong data-key="spaces">—</strong><p>
|
| 26 |
<article><h2>Models</h2><strong data-key="models">—</strong><p>Official Hub listing.</p></article>
|
| 27 |
<article><h2>Datasets</h2><strong data-key="datasets">—</strong><p>Official Hub listing.</p></article>
|
| 28 |
<article><h2>Trust factor</h2><strong data-key="trust">CHECKING</strong><p>Derived from signed local decisions.</p></article>
|
| 29 |
<article><h2>Receipt signer</h2><strong data-key="signer">CHECKING</strong><p>Persistent P‑256 preferred.</p></article>
|
| 30 |
</section>
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
<
|
| 34 |
-
|
| 35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
</label>
|
| 37 |
-
<label>
|
| 38 |
-
<
|
| 39 |
-
<button type="submit">Evaluate passport</button>
|
| 40 |
-
<button id="execute" type="button" disabled>Execute authorized action</button>
|
| 41 |
</form>
|
| 42 |
-
<pre id="
|
| 43 |
-
<pre id="execution-result" aria-live="polite">No authorized execution attempted.</pre>
|
| 44 |
-
<p>Execution is bounded to one attempt and is enabled only for an ALLOW passport.</p>
|
| 45 |
</section>
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
</section>
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
<
|
|
|
|
|
|
|
| 53 |
</section>
|
| 54 |
</main>
|
| 55 |
-
<footer>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
<script src="/series-a/app.js?v=__APP_ASSET_DIGEST__" defer></script>
|
| 57 |
</body>
|
| 58 |
</html>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="utf-8">
|
| 5 |
<meta name="viewport" content="width=device-width,initial-scale=1">
|
| 6 |
+
<meta name="theme-color" content="#080c14">
|
| 7 |
+
<meta name="color-scheme" content="dark">
|
| 8 |
+
<title>a11oy Series-A Command Center</title>
|
| 9 |
+
<meta name="description" content="Control before action. Evidence after. Series-A command center on a-11-oy.com — keep-7 Hub estate, claims ledger, fixture constitution, signed passports. Proof lives at a11oy.net.">
|
| 10 |
+
<link rel="canonical" href="https://a-11-oy.com/series-a">
|
| 11 |
<link rel="stylesheet" href="/series-a/styles.css?v=__STYLE_ASSET_DIGEST__">
|
| 12 |
</head>
|
| 13 |
<body>
|
| 14 |
+
<a class="skip" href="#main">Skip to command center</a>
|
| 15 |
+
<header class="topbar">
|
| 16 |
+
<div class="wrap nav">
|
| 17 |
+
<a class="wordmark" href="https://a-11-oy.com/">
|
| 18 |
+
<span class="glyph" aria-hidden="true">Λ</span>
|
| 19 |
+
<span class="scope"><span class="scope-name">A11OY</span><span class="scope-sep">/</span><span class="scope-role">SERIES-A</span></span>
|
| 20 |
+
</a>
|
| 21 |
+
<div class="nav-chips">
|
| 22 |
+
<span class="chip live"><span class="dot"></span>PRODUCT</span>
|
| 23 |
+
<span class="chip honesty"><span class="dot"></span>DEMO_SIGNED · fixture</span>
|
| 24 |
+
</div>
|
| 25 |
+
<nav class="tabs" aria-label="Command views">
|
| 26 |
+
<a href="#command" data-nav="command" aria-current="page">Command</a>
|
| 27 |
+
<a href="#estate" data-nav="estate">Estate</a>
|
| 28 |
+
<a href="#claims" data-nav="claims">Claims</a>
|
| 29 |
+
<a href="#policy" data-nav="policy">Policy</a>
|
| 30 |
+
<a href="#twin" data-nav="twin">Twin</a>
|
| 31 |
+
<a href="#passport" data-nav="passport">Passport</a>
|
| 32 |
+
<a href="#audit" data-nav="audit">Audit</a>
|
| 33 |
+
</nav>
|
| 34 |
+
<span class="origin-switch" aria-label="Origins">
|
| 35 |
+
<a class="origin-product" href="https://a-11-oy.com/" aria-current="true">Product</a>
|
| 36 |
+
<span class="origin-sep" aria-hidden="true">|</span>
|
| 37 |
+
<a href="https://a11oy.net/" target="_blank" rel="noopener">Proof ↗</a>
|
| 38 |
+
</span>
|
| 39 |
+
</div>
|
| 40 |
</header>
|
| 41 |
+
|
| 42 |
<main id="main" tabindex="-1">
|
| 43 |
+
<section class="toolbar wrap" aria-label="Live observation">
|
| 44 |
<button id="refresh" type="button">Run governed refresh</button>
|
| 45 |
<span id="updated" aria-live="polite">Not observed yet</span>
|
| 46 |
</section>
|
| 47 |
+
|
| 48 |
+
<section class="grid wrap" id="cards" aria-label="Live status">
|
| 49 |
<article><h2>Estate</h2><strong data-key="estate">CHECKING</strong><p>Signed current observation.</p></article>
|
| 50 |
<article><h2>GitHub repos</h2><strong data-key="repos">—</strong><p>Complete paginated census.</p></article>
|
| 51 |
<article><h2>Open PRs</h2><strong data-key="prs">—</strong><p>Current public queue.</p></article>
|
| 52 |
+
<article><h2>HF Spaces</h2><strong data-key="spaces">—</strong><p>Org census from signed observation.</p></article>
|
| 53 |
<article><h2>Models</h2><strong data-key="models">—</strong><p>Official Hub listing.</p></article>
|
| 54 |
<article><h2>Datasets</h2><strong data-key="datasets">—</strong><p>Official Hub listing.</p></article>
|
| 55 |
<article><h2>Trust factor</h2><strong data-key="trust">CHECKING</strong><p>Derived from signed local decisions.</p></article>
|
| 56 |
<article><h2>Receipt signer</h2><strong data-key="signer">CHECKING</strong><p>Persistent P‑256 preferred.</p></article>
|
| 57 |
</section>
|
| 58 |
+
|
| 59 |
+
<section class="view wrap" data-view="command">
|
| 60 |
+
<p class="eyebrow">Ninety seconds · Series‑A Live Control Plane</p>
|
| 61 |
+
<h1>Control before action. <span class="muted">Evidence after.</span></h1>
|
| 62 |
+
<p class="lede">Operators, security, and compliance who cannot take a model’s word for what it did. Four primitives sit in the path: Capability Constitution, Assurance Query Language, Operational Twin, Policy-to-Evidence Coverage Graph.</p>
|
| 63 |
+
<dl class="facts">
|
| 64 |
+
<div><dt>What is live</dt><dd>This origin is the product. Proof is a11oy.net. Receipts on the Twin tab from the fixture are DEMO_SIGNED. Passports below are the live Series-A controller. This page does not write the Hub and does not rewrite the published atlas keep-set.</dd></div>
|
| 65 |
+
<div><dt>OSS vs product</dt><dd>Source github.com/szl-holdings/a11oy (Apache-2.0). Hugging Face is the artifact registry, not the front door.</dd></div>
|
| 66 |
+
<div><dt>Why now</dt><dd>Agents are being handed tools. Ungoverned tool authority is the incident. Governance has to live in the path, not in a slide.</dd></div>
|
| 67 |
+
</dl>
|
| 68 |
+
</section>
|
| 69 |
+
|
| 70 |
+
<section class="view wrap" data-view="estate" hidden>
|
| 71 |
+
<p class="eyebrow">Hub inventory · MEASURED</p>
|
| 72 |
+
<h1>Operator keep-set. This page does not write the Hub.</h1>
|
| 73 |
+
<p class="lede">Product lives here. Proof lives at a11oy.net. Archive means pause and private — never delete. Authenticated recapture includes the org README card. Unauthenticated author-list omits README. This surface does not rewrite the published atlas keep-set.</p>
|
| 74 |
+
<ul class="keep" id="keep-list"></ul>
|
| 75 |
+
<p class="bound">amaru / sentra / vessels / rosie do not exist as Spaces. Collection: canonical-public-spaces-7. Live totals come from the signed observation above, not from a Hub write on this page.</p>
|
| 76 |
+
</section>
|
| 77 |
+
|
| 78 |
+
<section class="view wrap" data-view="claims" hidden>
|
| 79 |
+
<p class="eyebrow">P0 · Claims ledger</p>
|
| 80 |
+
<h1>Every public number has a home.</h1>
|
| 81 |
+
<p class="lede">Marketing copy reads this ledger. Default is UNKNOWN. Stale May 12 metrics stay SNAPSHOT.</p>
|
| 82 |
+
<div class="table-wrap">
|
| 83 |
+
<table class="ledger">
|
| 84 |
+
<thead><tr><th>ID</th><th>Statement</th><th>Value</th><th>State</th></tr></thead>
|
| 85 |
+
<tbody id="claims-body"></tbody>
|
| 86 |
+
</table>
|
| 87 |
+
</div>
|
| 88 |
+
<h2 class="sub">Contradictions</h2>
|
| 89 |
+
<ul class="keep" id="ctr-list"></ul>
|
| 90 |
+
</section>
|
| 91 |
+
|
| 92 |
+
<section class="view wrap" data-view="policy" hidden>
|
| 93 |
+
<p class="eyebrow">acc-fixture-v1 · expires 2026-11-27</p>
|
| 94 |
+
<h1>Authority that cannot expire cannot be audited.</h1>
|
| 95 |
+
<p class="lede">Two-person mode. Writes per run: 0. Prohibited: shell.exec, prod.write, unsloth.codex. This constitution is the fixture slice, not a production MCP gateway.</p>
|
| 96 |
+
<ul class="keep" id="tools-list"></ul>
|
| 97 |
+
</section>
|
| 98 |
+
|
| 99 |
+
<section class="view wrap" data-view="twin" hidden>
|
| 100 |
+
<p class="eyebrow">Operational Twin · fixture</p>
|
| 101 |
+
<h1>Preview the blast radius. Then maybe act.</h1>
|
| 102 |
+
<p class="lede">Safe fixture only. Signatures here are DEMO_SIGNED HMAC in the browser. DSSE is UNAVAILABLE. The live passport on the next tab is the product controller.</p>
|
| 103 |
+
<form id="twin-form" class="twin">
|
| 104 |
+
<label>Tool
|
| 105 |
+
<select id="twin-tool" name="tool">
|
| 106 |
+
<option value="echo.ping">echo.ping · NONE · admitted</option>
|
| 107 |
+
<option value="receipt.inspect">receipt.inspect · NONE · admitted</option>
|
| 108 |
+
<option value="policy.propose">policy.propose · NONE · operator</option>
|
| 109 |
+
<option value="shell.exec">shell.exec · IRREVERSIBLE · prohibited</option>
|
| 110 |
+
<option value="prod.write">prod.write · IRREVERSIBLE · prohibited</option>
|
| 111 |
+
</select>
|
| 112 |
</label>
|
| 113 |
+
<label>Ping / proposal <input id="twin-arg" name="arg" value="fabric-ok"></label>
|
| 114 |
+
<button type="submit">Execute fixture</button>
|
|
|
|
|
|
|
| 115 |
</form>
|
| 116 |
+
<pre id="twin-result" aria-live="polite">No fixture receipt yet.</pre>
|
|
|
|
|
|
|
| 117 |
</section>
|
| 118 |
+
|
| 119 |
+
<section class="view wrap" data-view="passport" hidden>
|
| 120 |
+
<div class="panel">
|
| 121 |
+
<h2>Counterfactual Action Passport</h2>
|
| 122 |
+
<p>Live product controller. GET never mutates. Refresh, evaluate, and execute are explicit POSTs. One attempt. Fail closed.</p>
|
| 123 |
+
<form id="passport">
|
| 124 |
+
<label>Action
|
| 125 |
+
<select name="type"><option value="estate.refresh">Refresh estate truth</option><option value="probe.public_surface">Probe public surface</option></select>
|
| 126 |
+
</label>
|
| 127 |
+
<label>Target <input name="target" value="szl://estate/current" required></label>
|
| 128 |
+
<label>Evidence label <select name="label"><option value="OBSERVED">OBSERVED · server-signed snapshot</option><option value="UNKNOWN">UNKNOWN · fail-closed demo</option></select></label>
|
| 129 |
+
<button type="submit">Evaluate passport</button>
|
| 130 |
+
<button id="execute" type="button" disabled>Execute authorized action</button>
|
| 131 |
+
</form>
|
| 132 |
+
<pre id="passport-result" aria-live="polite">No passport evaluated.</pre>
|
| 133 |
+
<pre id="execution-result" aria-live="polite">No authorized execution attempted.</pre>
|
| 134 |
+
<p>Execution is bounded to one attempt and is enabled only for an ALLOW passport.</p>
|
| 135 |
+
</div>
|
| 136 |
+
<div class="panel">
|
| 137 |
+
<h2>Live event rail</h2>
|
| 138 |
+
<ol id="events" aria-live="polite"><li>CONNECTING</li></ol>
|
| 139 |
+
</div>
|
| 140 |
+
<div class="panel">
|
| 141 |
+
<h2>Latest signed receipts</h2>
|
| 142 |
+
<ol id="receipts"><li>CHECKING</li></ol>
|
| 143 |
+
</div>
|
| 144 |
</section>
|
| 145 |
+
|
| 146 |
+
<section class="view wrap" data-view="audit" hidden>
|
| 147 |
+
<p class="eyebrow">FRONTIER_BASELINE_AUDIT</p>
|
| 148 |
+
<h1>Inventory before abstraction.</h1>
|
| 149 |
+
<ul class="keep" id="audit-list"></ul>
|
| 150 |
</section>
|
| 151 |
</main>
|
| 152 |
+
<footer>
|
| 153 |
+
<div class="wrap footer">
|
| 154 |
+
<p>MEASURED · REPORTED · MODELED · UNKNOWN · UNAVAILABLE · no private reasoning collected. Never a11oy.com.</p>
|
| 155 |
+
<div class="footer-links">
|
| 156 |
+
<a href="https://a-11-oy.com/console">Console</a>
|
| 157 |
+
<a href="https://a-11-oy.com/api/a11oy/v1/honest">/honest</a>
|
| 158 |
+
<a href="https://a11oy.net/estate/">Proof estate</a>
|
| 159 |
+
<a href="https://github.com/szl-holdings/a11oy">Source</a>
|
| 160 |
+
</div>
|
| 161 |
+
</div>
|
| 162 |
+
</footer>
|
| 163 |
<script src="/series-a/app.js?v=__APP_ASSET_DIGEST__" defer></script>
|
| 164 |
</body>
|
| 165 |
</html>
|
routers/series_a_web/styles.css
CHANGED
|
@@ -1 +1,91 @@
|
|
| 1 |
-
:root{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:root{
|
| 2 |
+
color-scheme:dark;
|
| 3 |
+
--void:#080c14;
|
| 4 |
+
--deep:#0a1019;
|
| 5 |
+
--surface:#0e1626;
|
| 6 |
+
--card:#121d30;
|
| 7 |
+
--border:#1c2942;
|
| 8 |
+
--ink:#eef4fb;
|
| 9 |
+
--muted:#aebccf;
|
| 10 |
+
--ghost:#7f90a6;
|
| 11 |
+
--proof:#3af4c8;
|
| 12 |
+
--lattice:#5b8dee;
|
| 13 |
+
--gold:#d7b96b;
|
| 14 |
+
--down:#e8746e;
|
| 15 |
+
--sans:"Space Grotesk",-apple-system,BlinkMacSystemFont,"Segoe UI",Inter,sans-serif;
|
| 16 |
+
--mono:"JetBrains Mono","SF Mono",ui-monospace,Menlo,Consolas,monospace;
|
| 17 |
+
}
|
| 18 |
+
*{box-sizing:border-box}
|
| 19 |
+
html,body{margin:0;min-height:100%;background:var(--void);color:var(--ink);font:16px/1.5 var(--sans)}
|
| 20 |
+
a{color:var(--proof);text-decoration:none}
|
| 21 |
+
a:hover{text-decoration:underline}
|
| 22 |
+
.skip{position:absolute;left:-9999px}
|
| 23 |
+
.skip:focus{left:1rem;top:1rem;background:var(--proof);color:var(--void);padding:.7rem;z-index:9}
|
| 24 |
+
.wrap{width:min(1180px,calc(100% - 2rem));margin-inline:auto}
|
| 25 |
+
.topbar{position:sticky;top:0;z-index:10;border-bottom:1px solid var(--border);background:rgba(8,12,20,.92);backdrop-filter:blur(10px)}
|
| 26 |
+
.nav{display:flex;flex-wrap:wrap;gap:.75rem 1rem;align-items:center;padding:.75rem 0}
|
| 27 |
+
.wordmark{display:inline-flex;align-items:center;gap:.6rem;color:var(--ink);font-weight:700}
|
| 28 |
+
.glyph{width:26px;height:26px;border-radius:7px;border:1px solid var(--border);display:grid;place-items:center;color:var(--ghost);font-family:var(--mono)}
|
| 29 |
+
.scope-role{font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;color:var(--ghost)}
|
| 30 |
+
.scope-sep{color:var(--ghost);padding:0 .35rem}
|
| 31 |
+
.nav-chips{display:flex;gap:.5rem;flex-wrap:wrap}
|
| 32 |
+
.chip{display:inline-flex;align-items:center;gap:7px;padding:5px 11px;border-radius:999px;font:600 11px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase;border:1px solid var(--border);color:var(--ghost)}
|
| 33 |
+
.chip .dot{width:7px;height:7px;border-radius:50%;background:currentColor}
|
| 34 |
+
.chip.live{color:var(--proof);border-color:rgba(58,244,200,.32)}
|
| 35 |
+
.chip.honesty{color:var(--ghost)}
|
| 36 |
+
.tabs{display:flex;gap:.2rem;flex-wrap:wrap;flex:1}
|
| 37 |
+
.tabs a{color:var(--muted);padding:.55rem .7rem;border-radius:8px;min-height:44px;display:inline-flex;align-items:center}
|
| 38 |
+
.tabs a[aria-current="page"]{color:var(--ink);background:var(--card)}
|
| 39 |
+
.origin-switch{display:inline-flex;align-items:center;gap:7px;padding-left:12px;border-left:1px solid var(--border);font-family:var(--mono);font-size:12px}
|
| 40 |
+
.origin-product{color:var(--proof);font-weight:700}
|
| 41 |
+
.origin-sep{color:var(--ghost)}
|
| 42 |
+
.toolbar{display:flex;gap:1rem;align-items:center;justify-content:space-between;margin:1.2rem auto}
|
| 43 |
+
.grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1rem}
|
| 44 |
+
.grid article,.panel{background:linear-gradient(180deg,rgba(18,34,57,.96),rgba(10,22,38,.96));border:1px solid var(--border);border-radius:16px;padding:1.1rem}
|
| 45 |
+
.grid h2,.panel h2{font-size:.92rem;color:var(--muted);margin:0 0 .5rem;font-weight:600}
|
| 46 |
+
.grid strong{font-size:1.55rem;color:var(--proof);font-variant-numeric:tabular-nums}
|
| 47 |
+
.grid p,.panel>p,.lede,.bound,.muted{color:var(--muted)}
|
| 48 |
+
.view{padding:1.5rem 0 3rem}
|
| 49 |
+
.view[hidden]{display:none!important}
|
| 50 |
+
.view[data-view="passport"]:not([hidden]){display:grid;gap:1rem}
|
| 51 |
+
.eyebrow{font:600 11px/1 var(--mono);letter-spacing:.16em;text-transform:uppercase;color:var(--ghost);margin:0 0 .6rem}
|
| 52 |
+
h1{font-size:clamp(2rem,5vw,3.4rem);line-height:1.08;margin:.2rem 0 1rem;letter-spacing:-.02em}
|
| 53 |
+
.lede{max-width:44rem;font-size:1.05rem}
|
| 54 |
+
.facts{display:grid;gap:1.1rem;margin:2rem 0 0}
|
| 55 |
+
.facts dt{font:600 11px/1 var(--mono);letter-spacing:.12em;text-transform:uppercase;color:var(--ghost)}
|
| 56 |
+
.facts dd{margin:.4rem 0 0}
|
| 57 |
+
.keep{list-style:none;padding:0;margin:1.2rem 0;display:grid;gap:.55rem}
|
| 58 |
+
.keep li{border:1px solid var(--border);border-radius:12px;padding:.85rem 1rem;display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;align-items:center;min-height:44px}
|
| 59 |
+
.keep .id{font-family:var(--mono);font-size:.92rem}
|
| 60 |
+
.badge{font:600 10px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase;border:1px solid var(--border);padding:.3rem .45rem;border-radius:4px;color:var(--ghost)}
|
| 61 |
+
.badge.live{color:var(--proof);border-color:rgba(58,244,200,.3)}
|
| 62 |
+
.badge.snapshot{color:var(--gold);border-color:rgba(215,185,107,.35)}
|
| 63 |
+
.badge.unknown{color:var(--ghost)}
|
| 64 |
+
.badge.blocker{color:var(--down);border-color:rgba(232,116,110,.4)}
|
| 65 |
+
.table-wrap{overflow-x:auto;border:1px solid var(--border);border-radius:14px}
|
| 66 |
+
.ledger{width:100%;min-width:640px;border-collapse:collapse;font-size:.92rem}
|
| 67 |
+
.ledger th{text-align:left;font:600 11px/1 var(--mono);letter-spacing:.08em;text-transform:uppercase;color:var(--ghost);padding:.8rem;background:var(--card)}
|
| 68 |
+
.ledger td{padding:.8rem;border-top:1px solid var(--border);vertical-align:top}
|
| 69 |
+
.sub{margin:2rem 0 .8rem;font-size:1.2rem}
|
| 70 |
+
.twin,.panel form{display:grid;grid-template-columns:1fr 2fr auto;gap:.8rem;align-items:end}
|
| 71 |
+
label{display:grid;gap:.35rem;color:var(--muted);font-size:.92rem}
|
| 72 |
+
input,select,button{font:inherit;border-radius:10px;border:1px solid var(--border);padding:.75rem .85rem;background:var(--deep);color:var(--ink);min-height:44px}
|
| 73 |
+
button{background:var(--proof);color:var(--void);font-weight:800;cursor:pointer}
|
| 74 |
+
button:disabled{opacity:.55;cursor:not-allowed}
|
| 75 |
+
pre{white-space:pre-wrap;overflow-wrap:anywhere;background:var(--deep);border-radius:12px;padding:1rem;border:1px solid var(--border);font:13px/1.45 var(--mono)}
|
| 76 |
+
#events,#receipts{display:grid;gap:.55rem;padding-left:1.4rem}
|
| 77 |
+
#events li,#receipts li{overflow-wrap:anywhere}
|
| 78 |
+
.footer{display:flex;justify-content:space-between;gap:1rem;flex-wrap:wrap;padding:2rem 0 4rem;color:var(--muted);font-size:.9rem}
|
| 79 |
+
.footer-links{display:flex;gap:1rem;flex-wrap:wrap}
|
| 80 |
+
@media(max-width:900px){
|
| 81 |
+
.grid{grid-template-columns:repeat(2,minmax(0,1fr))}
|
| 82 |
+
.twin,.panel form{grid-template-columns:1fr}
|
| 83 |
+
.origin-switch{border-left:0;padding-left:0;width:100%}
|
| 84 |
+
}
|
| 85 |
+
@media(max-width:560px){
|
| 86 |
+
.grid{grid-template-columns:1fr}
|
| 87 |
+
.tabs a{flex:1;justify-content:center}
|
| 88 |
+
}
|
| 89 |
+
@media (prefers-reduced-motion:reduce){
|
| 90 |
+
*{animation:none!important;transition:none!important}
|
| 91 |
+
}
|