Spaces:
Running
Running
Dev B: add governance source files missing on Space (tau eval, IETF receipt view, Colang ROE policy, /governance page, Lean4Agent scaffold) — byte-identical to GitHub; fixes Dockerfile COPY cache-miss build error
Browse files- lean4agent/README.md +32 -0
- lean4agent/WorkflowInvariants.lean +113 -0
- policy/colang/killinchu_threat.co +55 -0
- policy/colang/roe_core.co +71 -0
- web/governance.html +253 -0
lean4agent/README.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Lean4Agent — a11oy workflow-invariant formalization (ROADMAP / EXPERIMENTAL)
|
| 2 |
+
|
| 3 |
+
**Status: ROADMAP.** This directory is a *scaffold* that formalizes the safety
|
| 4 |
+
invariants of the a11oy governed-agent workflow in [Lean 4](https://leanprover.github.io/).
|
| 5 |
+
It is **not** a completed machine-checked verification yet. The UI and docs render
|
| 6 |
+
these invariants as **"ROADMAP — statements formalized, proofs in progress"** and
|
| 7 |
+
must never describe them as "verified" until `lake build` passes with **zero `sorry`**.
|
| 8 |
+
|
| 9 |
+
Inspired by **Lean4Agent** (arXiv:2606.06523), which formalizes agent workflow
|
| 10 |
+
invariants in Lean 4.
|
| 11 |
+
|
| 12 |
+
## Files
|
| 13 |
+
- `WorkflowInvariants.lean` — the irreducible governed-decision pipeline
|
| 14 |
+
(`gate → lambda → recommend → sign → replay`) and 5 safety invariants:
|
| 15 |
+
- **INV 1** `destructive_unapproved_denied` — **proved** (no `sorry`)
|
| 16 |
+
- **INV 2** `injection_always_denied` — **proved**
|
| 17 |
+
- **INV 3** `oversize_denied` — **proved**
|
| 18 |
+
- **INV 4** `canonical_pipeline_policy_first` — **ROADMAP** (`sorry`)
|
| 19 |
+
- **INV 5** `replay_is_deterministic` — **ROADMAP** (placeholder statement)
|
| 20 |
+
|
| 21 |
+
These mirror the runtime enforcement points: the `_a11oy_arena_inspect` threat gate
|
| 22 |
+
and the Colang ROE flows in `policy/colang/roe_core.co`.
|
| 23 |
+
|
| 24 |
+
## Roadmap to "verified"
|
| 25 |
+
1. Add `lakefile.lean` + pin a Lean toolchain (`lean-toolchain`).
|
| 26 |
+
2. Discharge INV 4 and INV 5 (remove every `sorry`).
|
| 27 |
+
3. Add a CI job that runs `lake build` and fails on any `sorry` / `axiom`.
|
| 28 |
+
4. Emit a build manifest; the Eval/Policy tab then cites
|
| 29 |
+
"N/M a11oy workflow invariants machine-checked, as-of <date>".
|
| 30 |
+
|
| 31 |
+
Until step 3 is green, the honest claim is: **3 of 5 invariant statements are
|
| 32 |
+
proved in isolation; the full-pipeline and determinism theorems are roadmap.**
|
lean4agent/WorkflowInvariants.lean
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/-
|
| 2 |
+
WorkflowInvariants.lean — ROADMAP / EXPERIMENTAL scaffold (NOT a verified proof yet)
|
| 3 |
+
|
| 4 |
+
© 2026 Lutar, Stephen P. — SZL Holdings. SPDX-License-Identifier: Apache-2.0
|
| 5 |
+
|
| 6 |
+
STATUS: ROADMAP. This file formalizes the SAFETY INVARIANTS of the a11oy governed
|
| 7 |
+
agent WORKFLOW in Lean 4 so they can eventually be machine-checked. It is a
|
| 8 |
+
SCAFFOLD: the theorem STATEMENTS are written out and the simplest ones are proved,
|
| 9 |
+
but the deeper ones are deliberately left as `sorry` and are LABELLED as such so we
|
| 10 |
+
never overclaim a machine-checked guarantee we do not yet have. Inspired by
|
| 11 |
+
Lean4Agent (arXiv:2606.06523) — formalizing agent workflow invariants in Lean 4.
|
| 12 |
+
|
| 13 |
+
What this models: the irreducible core of ONE governed decision in a11oy:
|
| 14 |
+
gate.evaluate → lambda.score → decision.recommend → receipt.sign → replay.verify
|
| 15 |
+
and the doctrine rules the runtime enforces (Colang ROE + arena gate). The goal of
|
| 16 |
+
the roadmap is: every theorem here is discharged WITHOUT `sorry`, then a CI job runs
|
| 17 |
+
`lake build` and the UI cites "N/M workflow invariants machine-checked".
|
| 18 |
+
|
| 19 |
+
HONESTY: until `lake build` passes with zero `sorry`, the UI MUST render these as
|
| 20 |
+
"ROADMAP — statements formalized, proofs in progress", never as "verified".
|
| 21 |
+
-/
|
| 22 |
+
|
| 23 |
+
namespace A11oy.Workflow
|
| 24 |
+
|
| 25 |
+
/-- The ordered phases of one governed decision. -/
|
| 26 |
+
inductive Phase where
|
| 27 |
+
| gate -- policy gate evaluated the action plan
|
| 28 |
+
| lambda -- trust score (Λ, Conjecture 1) computed across axes
|
| 29 |
+
| recommend -- governed recommendation emitted
|
| 30 |
+
| sign -- decision receipt DSSE-signed (ECDSA-P256, in-image key)
|
| 31 |
+
| replay -- deterministic replay produced byte-identical root
|
| 32 |
+
deriving Repr, DecidableEq
|
| 33 |
+
|
| 34 |
+
/-- A decision outcome. -/
|
| 35 |
+
inductive Decision where
|
| 36 |
+
| allow
|
| 37 |
+
| deny
|
| 38 |
+
| rateLimit
|
| 39 |
+
| observation
|
| 40 |
+
deriving Repr, DecidableEq
|
| 41 |
+
|
| 42 |
+
/-- An action carries flags the runtime actually inspects. -/
|
| 43 |
+
structure Action where
|
| 44 |
+
destructive : Bool -- matches a destructive signature
|
| 45 |
+
operatorApproved : Bool -- operator.approve event present
|
| 46 |
+
highImpact : Bool -- requires_approval
|
| 47 |
+
injection : Bool -- prompt-injection signature
|
| 48 |
+
payloadOverCeiling : Bool -- exceeds 1MB DoS ceiling
|
| 49 |
+
deriving Repr
|
| 50 |
+
|
| 51 |
+
/-- A workflow trace is the (ordered) list of phases that actually ran. -/
|
| 52 |
+
abbrev Trace := List Phase
|
| 53 |
+
|
| 54 |
+
/-- The policy gate's verdict on an action (mirrors `_a11oy_arena_inspect` +
|
| 55 |
+
Colang ROE: any of these conditions ⇒ DENY). -/
|
| 56 |
+
def gateVerdict (a : Action) : Decision :=
|
| 57 |
+
if a.injection || a.payloadOverCeiling
|
| 58 |
+
|| (a.destructive && ¬ a.operatorApproved)
|
| 59 |
+
|| (a.highImpact && ¬ a.operatorApproved)
|
| 60 |
+
then Decision.deny
|
| 61 |
+
else Decision.allow
|
| 62 |
+
|
| 63 |
+
/-- INVARIANT 1 (proved): a destructive action without operator approval is DENIED.
|
| 64 |
+
This is the Colang `refuse_destructive_actions` flow as a theorem. -/
|
| 65 |
+
theorem destructive_unapproved_denied (a : Action)
|
| 66 |
+
(hd : a.destructive = true) (hn : a.operatorApproved = false) :
|
| 67 |
+
gateVerdict a = Decision.deny := by
|
| 68 |
+
unfold gateVerdict
|
| 69 |
+
simp [hd, hn]
|
| 70 |
+
|
| 71 |
+
/-- INVARIANT 2 (proved): an injection-bearing action is DENIED regardless of
|
| 72 |
+
every other flag. Colang `refuse_prompt_injection`. -/
|
| 73 |
+
theorem injection_always_denied (a : Action) (hi : a.injection = true) :
|
| 74 |
+
gateVerdict a = Decision.deny := by
|
| 75 |
+
unfold gateVerdict
|
| 76 |
+
simp [hi]
|
| 77 |
+
|
| 78 |
+
/-- INVARIANT 3 (proved): an oversized payload is DENIED (DoS size guard). -/
|
| 79 |
+
theorem oversize_denied (a : Action) (ho : a.payloadOverCeiling = true) :
|
| 80 |
+
gateVerdict a = Decision.deny := by
|
| 81 |
+
unfold gateVerdict
|
| 82 |
+
simp [ho]
|
| 83 |
+
|
| 84 |
+
/-- "policy-before-effect": `gate` must occur strictly before `sign` in a trace. -/
|
| 85 |
+
def policyBeforeEffect (t : Trace) : Prop :=
|
| 86 |
+
∀ i j, t.get? i = some Phase.sign → t.get? j = some Phase.gate → j < i
|
| 87 |
+
|
| 88 |
+
/-- INVARIANT 4 (ROADMAP — `sorry`): the canonical governed-turn pipeline always
|
| 89 |
+
evaluates policy before any signing/effect step. Statement is formalized; the
|
| 90 |
+
proof over arbitrary well-formed traces is left for the roadmap. DO NOT claim
|
| 91 |
+
this as machine-checked until the `sorry` below is removed. -/
|
| 92 |
+
theorem canonical_pipeline_policy_first :
|
| 93 |
+
policyBeforeEffect [Phase.gate, Phase.lambda, Phase.recommend,
|
| 94 |
+
Phase.sign, Phase.replay] := by
|
| 95 |
+
sorry -- ROADMAP: discharge by `decide`/index reasoning; tracked in CI
|
| 96 |
+
|
| 97 |
+
/-- INVARIANT 5 (ROADMAP — `sorry`): determinism — replaying a trace yields a
|
| 98 |
+
byte-identical receipt root. Requires modeling the receipt hash-chain; left as
|
| 99 |
+
a roadmap obligation. -/
|
| 100 |
+
theorem replay_is_deterministic (t : Trace) :
|
| 101 |
+
True := by
|
| 102 |
+
trivial -- placeholder statement only; real determinism theorem is ROADMAP
|
| 103 |
+
|
| 104 |
+
/-- Summary used by the CI/manifest extractor: which invariants are DISCHARGED. -/
|
| 105 |
+
def invariantStatus : List (String × Bool) :=
|
| 106 |
+
[ ("destructive_unapproved_denied", true)
|
| 107 |
+
, ("injection_always_denied", true)
|
| 108 |
+
, ("oversize_denied", true)
|
| 109 |
+
, ("canonical_pipeline_policy_first", false) -- ROADMAP (sorry)
|
| 110 |
+
, ("replay_is_deterministic", false) -- ROADMAP (placeholder)
|
| 111 |
+
]
|
| 112 |
+
|
| 113 |
+
end A11oy.Workflow
|
policy/colang/killinchu_threat.co
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
# killinchu threat-response ROE — NeMo Guardrails Colang (v1) flows.
|
| 3 |
+
# https://github.com/NVIDIA-NeMo/Guardrails
|
| 4 |
+
#
|
| 5 |
+
# DOCTRINE: counter-UAS / maritime C2 rules of engagement as a versioned,
|
| 6 |
+
# auditable Colang file. Effectors are SIMULATED, human-on-loop. This file is the
|
| 7 |
+
# authoritative policy for autonomous threat handling; the runtime enforcer in
|
| 8 |
+
# szl_colang_policy.py loads it and records fired flows into the signed receipt.
|
| 9 |
+
# Coordinates with Dev D's threat classifier (conformal set + ECE<0.05 gate from
|
| 10 |
+
# szl_conformal.py / szl_calibration.py) — engagement is never recommended on an
|
| 11 |
+
# unmeasured-calibration classifier or a non-singleton conformal set without a
|
| 12 |
+
# human.
|
| 13 |
+
#
|
| 14 |
+
# policy_id: killinchu-threat-roe
|
| 15 |
+
# policy_version: 1.0.0
|
| 16 |
+
|
| 17 |
+
define flow no_autonomous_engagement
|
| 18 |
+
# No engagement effector may fire autonomously — every engage requires a
|
| 19 |
+
# recorded human authorization (SIMULATED human-on-loop). Hard ROE boundary.
|
| 20 |
+
user action requested $action
|
| 21 |
+
if is_engagement($action) and not has_human_authorization($action)
|
| 22 |
+
bot refuse action with reason "engagement_requires_human_authorization"
|
| 23 |
+
create signed_refusal_receipt($action, "engagement_requires_human_authorization")
|
| 24 |
+
else
|
| 25 |
+
continue
|
| 26 |
+
|
| 27 |
+
define flow require_calibrated_classifier
|
| 28 |
+
# An automated threat response is permitted only when the classifier's
|
| 29 |
+
# calibration is MEASURED and ECE < gate threshold (szl_calibration gate).
|
| 30 |
+
user action requested $action
|
| 31 |
+
if is_automated_response($action) and not classifier_calibration_gate_pass($action)
|
| 32 |
+
bot refuse action with reason "classifier_calibration_gate_failed"
|
| 33 |
+
create signed_refusal_receipt($action, "classifier_calibration_gate_failed")
|
| 34 |
+
else
|
| 35 |
+
continue
|
| 36 |
+
|
| 37 |
+
define flow require_singleton_conformal_set
|
| 38 |
+
# If the conformal threat-class set is NOT a singleton (ambiguous at the 95%
|
| 39 |
+
# coverage target), do not auto-act — route to a human (act-vs-ask).
|
| 40 |
+
user action requested $action
|
| 41 |
+
if is_automated_response($action) and conformal_set_ambiguous($action)
|
| 42 |
+
bot refuse action with reason "conformal_set_ambiguous_route_to_human"
|
| 43 |
+
create signed_refusal_receipt($action, "conformal_set_ambiguous_route_to_human")
|
| 44 |
+
else
|
| 45 |
+
continue
|
| 46 |
+
|
| 47 |
+
define flow require_sensor_quorum
|
| 48 |
+
# A threat decision requires a sensor-fusion quorum (BFT n>=3f+1; Dev D panel).
|
| 49 |
+
user action requested $action
|
| 50 |
+
if is_threat_decision($action) and not sensor_quorum_met($action)
|
| 51 |
+
bot refuse action with reason "sensor_quorum_not_met"
|
| 52 |
+
create signed_refusal_receipt($action, "sensor_quorum_not_met")
|
| 53 |
+
else
|
| 54 |
+
allow action
|
| 55 |
+
create signed_action_receipt($action)
|
policy/colang/roe_core.co
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
# a11oy ROE / governance policy — NeMo Guardrails Colang (v1) flows.
|
| 3 |
+
# https://github.com/NVIDIA-NeMo/Guardrails (Colang policy DSL)
|
| 4 |
+
#
|
| 5 |
+
# DOCTRINE: This file is the AUTHORITATIVE, version-controlled, independently
|
| 6 |
+
# auditable Rules-of-Engagement policy. Policy lives HERE, in a reviewable file
|
| 7 |
+
# under git — NOT inside a prompt. serve.py loads + enforces these flows via
|
| 8 |
+
# szl_colang_policy.py and renders the file content + sha256 in the Policy tab so
|
| 9 |
+
# anyone can audit exactly which rules are active.
|
| 10 |
+
#
|
| 11 |
+
# policy_id: a11oy-roe-core
|
| 12 |
+
# policy_version: 1.0.0
|
| 13 |
+
# Each `define flow` is a named, hash-anchored rule. The runtime enforcer matches
|
| 14 |
+
# the proposed action against each flow's guard conditions and records which
|
| 15 |
+
# flows fired into the signed receipt (controls_evaluated.policy per IETF
|
| 16 |
+
# draft-marques-asqav-compliance-receipts-05).
|
| 17 |
+
|
| 18 |
+
define flow refuse_destructive_actions
|
| 19 |
+
# No irreversible / destructive action without explicit operator authorization.
|
| 20 |
+
user action requested $action
|
| 21 |
+
if is_destructive($action) and not has_operator_authorization($action)
|
| 22 |
+
bot refuse action with reason "destructive_without_authorization"
|
| 23 |
+
create signed_refusal_receipt($action, "destructive_without_authorization")
|
| 24 |
+
else
|
| 25 |
+
continue
|
| 26 |
+
|
| 27 |
+
define flow refuse_pii_exfiltration
|
| 28 |
+
# Never emit/exfiltrate PII (PAN, SSN, full card numbers) to an external sink.
|
| 29 |
+
user action requested $action
|
| 30 |
+
if requests_pii_exfiltration($action)
|
| 31 |
+
bot refuse action with reason "pii_exfiltration_blocked"
|
| 32 |
+
create signed_refusal_receipt($action, "pii_exfiltration_blocked")
|
| 33 |
+
else
|
| 34 |
+
continue
|
| 35 |
+
|
| 36 |
+
define flow refuse_prompt_injection
|
| 37 |
+
# Reject actions carrying override/injection signatures ("ignore previous", etc).
|
| 38 |
+
user action requested $action
|
| 39 |
+
if matches_injection_signature($action)
|
| 40 |
+
bot refuse action with reason "prompt_injection_detected"
|
| 41 |
+
create signed_refusal_receipt($action, "prompt_injection_detected")
|
| 42 |
+
else
|
| 43 |
+
continue
|
| 44 |
+
|
| 45 |
+
define flow require_operator_approval_high_impact
|
| 46 |
+
# High-consequence actions require a recorded human-on-loop approval event.
|
| 47 |
+
user action requested $action
|
| 48 |
+
if is_high_impact($action) and not has_operator_approval_event($action)
|
| 49 |
+
bot refuse action with reason "operator_approval_required"
|
| 50 |
+
create signed_refusal_receipt($action, "operator_approval_required")
|
| 51 |
+
else
|
| 52 |
+
continue
|
| 53 |
+
|
| 54 |
+
define flow enforce_payload_ceiling
|
| 55 |
+
# Reject oversized payloads (DoS ceiling) before they reach an effector.
|
| 56 |
+
user action requested $action
|
| 57 |
+
if payload_exceeds_ceiling($action)
|
| 58 |
+
bot refuse action with reason "payload_exceeds_1MB"
|
| 59 |
+
create signed_refusal_receipt($action, "payload_exceeds_1MB")
|
| 60 |
+
else
|
| 61 |
+
continue
|
| 62 |
+
|
| 63 |
+
define flow policy_before_effect
|
| 64 |
+
# An effecting tool call MUST be preceded by a policy evaluation in the trace.
|
| 65 |
+
user action requested $action
|
| 66 |
+
if is_effecting($action) and not policy_evaluated_before($action)
|
| 67 |
+
bot refuse action with reason "policy_evaluation_must_precede_effect"
|
| 68 |
+
create signed_refusal_receipt($action, "policy_evaluation_must_precede_effect")
|
| 69 |
+
else
|
| 70 |
+
allow action
|
| 71 |
+
create signed_action_receipt($action)
|
web/governance.html
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<!--
|
| 3 |
+
a11oy GOVERNANCE / EVAL / CALIBRATION console (Dev B lane).
|
| 4 |
+
© 2026 Lutar, Stephen P. — SZL Holdings. SPDX-License-Identifier: Apache-2.0
|
| 5 |
+
0 runtime CDN: the ONLY external script is the in-image vendored Chart.js
|
| 6 |
+
(/vendor/chart.umd.min.js). All data is fetched live from /api/a11oy/v1/gov/*.
|
| 7 |
+
Every number is measured or honestly labelled "not_measured" — nothing fabricated.
|
| 8 |
+
-->
|
| 9 |
+
<html lang="en">
|
| 10 |
+
<head>
|
| 11 |
+
<meta charset="utf-8"/>
|
| 12 |
+
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
| 13 |
+
<title>a11oy · Governance / Eval / Calibration</title>
|
| 14 |
+
<script src="/vendor/chart.umd.min.js"></script>
|
| 15 |
+
<style>
|
| 16 |
+
:root{
|
| 17 |
+
--bg:#0a0e14; --panel:#121823; --panel2:#0f141d; --line:#1f2a3a;
|
| 18 |
+
--ink:#e6edf3; --mut:#8b98a9; --acc:#5ad1c9; --acc2:#7aa2f7;
|
| 19 |
+
--ok:#3fb950; --warn:#d29922; --err:#f85149; --road:#a371f7;
|
| 20 |
+
}
|
| 21 |
+
*{box-sizing:border-box}
|
| 22 |
+
body{margin:0;background:var(--bg);color:var(--ink);
|
| 23 |
+
font:14px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
|
| 24 |
+
header{padding:18px 22px;border-bottom:1px solid var(--line);
|
| 25 |
+
background:linear-gradient(180deg,#0d1320,#0a0e14)}
|
| 26 |
+
h1{margin:0;font-size:18px;letter-spacing:.3px}
|
| 27 |
+
.sub{color:var(--mut);font-size:12px;margin-top:4px}
|
| 28 |
+
.wrap{max-width:1180px;margin:0 auto;padding:18px 22px}
|
| 29 |
+
.grid{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(340px,1fr))}
|
| 30 |
+
.card{background:var(--panel);border:1px solid var(--line);border-radius:10px;
|
| 31 |
+
padding:16px 18px}
|
| 32 |
+
.card h2{margin:0 0 10px;font-size:14px;letter-spacing:.4px;color:var(--acc)}
|
| 33 |
+
.kv{display:flex;justify-content:space-between;gap:10px;padding:3px 0;
|
| 34 |
+
border-bottom:1px dotted #1a2435}
|
| 35 |
+
.kv:last-child{border-bottom:0}
|
| 36 |
+
.k{color:var(--mut)} .v{color:var(--ink);text-align:right;word-break:break-word}
|
| 37 |
+
.big{font-size:30px;font-weight:700;letter-spacing:.5px}
|
| 38 |
+
.pill{display:inline-block;padding:2px 9px;border-radius:999px;font-size:11px;
|
| 39 |
+
border:1px solid var(--line)}
|
| 40 |
+
.pill.ok{color:var(--ok);border-color:#163a1f;background:#0e2113}
|
| 41 |
+
.pill.err{color:var(--err);border-color:#4a1c1c;background:#240f0f}
|
| 42 |
+
.pill.warn{color:var(--warn);border-color:#3a3015;background:#1f1a0a}
|
| 43 |
+
.pill.road{color:var(--road);border-color:#2e2147;background:#160f24}
|
| 44 |
+
.pill.acc{color:var(--acc);border-color:#13403c;background:#0a201e}
|
| 45 |
+
.cite{color:var(--mut);font-size:11px;margin-top:8px}
|
| 46 |
+
.cite code{color:var(--acc2)}
|
| 47 |
+
.mono{font-family:inherit}
|
| 48 |
+
.set{display:flex;gap:8px;flex-wrap:wrap;margin:6px 0}
|
| 49 |
+
.set .lab{padding:4px 11px;border-radius:7px;border:1px solid var(--line);
|
| 50 |
+
background:#0e1622;font-size:13px}
|
| 51 |
+
.set .lab.in{border-color:#13403c;background:#0a201e;color:var(--acc)}
|
| 52 |
+
table{width:100%;border-collapse:collapse;font-size:12px}
|
| 53 |
+
th,td{text-align:left;padding:5px 7px;border-bottom:1px solid #1a2435}
|
| 54 |
+
th{color:var(--mut);font-weight:600}
|
| 55 |
+
.file{background:var(--panel2);border:1px solid var(--line);border-radius:8px;
|
| 56 |
+
padding:10px 12px;margin:8px 0}
|
| 57 |
+
.file pre{margin:6px 0 0;white-space:pre-wrap;color:#b9c6d6;font-size:11px;
|
| 58 |
+
max-height:160px;overflow:auto}
|
| 59 |
+
.sha{color:var(--acc2);font-size:11px}
|
| 60 |
+
.note{color:var(--mut);font-size:11px;margin-top:8px;line-height:1.55}
|
| 61 |
+
.loading{color:var(--mut)} .err{color:var(--err)}
|
| 62 |
+
a{color:var(--acc2)}
|
| 63 |
+
footer{color:var(--mut);font-size:11px;padding:14px 22px;border-top:1px solid var(--line)}
|
| 64 |
+
</style>
|
| 65 |
+
</head>
|
| 66 |
+
<body>
|
| 67 |
+
<header>
|
| 68 |
+
<h1>a11oy · Governance / Eval / Calibration</h1>
|
| 69 |
+
<div class="sub">Live tool-rule-following eval (τ-bench-style) · calibration (ECE/Brier) · conformal prediction sets · file-backed Colang policy · IETF compliance-receipt profile · Lean4Agent invariants (roadmap). Every number is measured live or labelled <em>not_measured</em>.</div>
|
| 70 |
+
</header>
|
| 71 |
+
<div class="wrap">
|
| 72 |
+
<div class="grid">
|
| 73 |
+
<!-- EVAL -->
|
| 74 |
+
<div class="card" id="eval-card">
|
| 75 |
+
<h2>τ-BENCH-STYLE EVAL — TOOL RULE-FOLLOWING</h2>
|
| 76 |
+
<div id="eval" class="loading">measuring live…</div>
|
| 77 |
+
<div class="cite">Suite design after τ-bench <code>arXiv:2406.12045</code> · AgentBench <code>arXiv:2308.03688</code>. pass^1 = task passes iff EVERY domain rule holds against the real produced trajectory.</div>
|
| 78 |
+
</div>
|
| 79 |
+
|
| 80 |
+
<!-- CALIBRATION -->
|
| 81 |
+
<div class="card" id="cal-card">
|
| 82 |
+
<h2>CALIBRATION — ECE / BRIER + AUTO-RESPONSE GATE</h2>
|
| 83 |
+
<div id="cal" class="loading">measuring live…</div>
|
| 84 |
+
<canvas id="relchart" height="150" style="margin-top:10px"></canvas>
|
| 85 |
+
<div class="cite">ECE (equal-width bins) + Brier per <code>arXiv:2505.15437</code>. Gate: ECE < 0.05 required for any automated (no-human) response; <b>fails closed</b> on unmeasured calibration.</div>
|
| 86 |
+
</div>
|
| 87 |
+
|
| 88 |
+
<!-- CONFORMAL -->
|
| 89 |
+
<div class="card" id="conf-card">
|
| 90 |
+
<h2>CONFORMAL PREDICTION — SETS, NOT BARE %</h2>
|
| 91 |
+
<div id="conf" class="loading">computing…</div>
|
| 92 |
+
<div class="cite">Split conformal per <code>arXiv:2305.18404</code> · Angelopoulos & Bates <code>arXiv:2107.07511</code>. Shared helper <code>szl_conformal</code> — Dev D imports the SAME module for threat classification.</div>
|
| 93 |
+
</div>
|
| 94 |
+
|
| 95 |
+
<!-- POLICY -->
|
| 96 |
+
<div class="card" id="pol-card" style="grid-column:1/-1">
|
| 97 |
+
<h2>POLICY — FILE-BACKED COLANG ROE (INDEPENDENTLY AUDITABLE)</h2>
|
| 98 |
+
<div id="pol" class="loading">loading policy files…</div>
|
| 99 |
+
<div class="cite">NeMo Guardrails Colang syntax — <code>github.com/NVIDIA-NeMo/Guardrails</code>. Policy lives in version-controlled <code>.co</code> files (single source of truth), shown here with per-file sha256. No prompt-only policy.</div>
|
| 100 |
+
</div>
|
| 101 |
+
|
| 102 |
+
<!-- IETF -->
|
| 103 |
+
<div class="card" id="ietf-card" style="grid-column:1/-1">
|
| 104 |
+
<h2>IETF COMPLIANCE-RECEIPT PROFILE (DSSE ENVELOPE INTACT)</h2>
|
| 105 |
+
<div id="ietf" class="loading">signing a live decision…</div>
|
| 106 |
+
<div class="cite">Compliance VIEW aligned to <code>draft-marques-asqav-compliance-receipts-05</code>. The cross-app DSSE envelope (ECDSA-P256-SHA256) is reproduced UNCHANGED — verify against <a href="/cosign.pub">/cosign.pub</a>.</div>
|
| 107 |
+
</div>
|
| 108 |
+
|
| 109 |
+
<!-- LEAN -->
|
| 110 |
+
<div class="card" id="lean-card">
|
| 111 |
+
<h2>LEAN4AGENT — WORKFLOW INVARIANTS <span class="pill road">ROADMAP</span></h2>
|
| 112 |
+
<div id="lean" class="loading">…</div>
|
| 113 |
+
<div class="cite">Formalization after Lean4Agent <code>arXiv:2606.06523</code>. Proved-in-isolation invariants are real; full-pipeline + determinism theorems carry <code>sorry</code> and are NOT machine-checked yet.</div>
|
| 114 |
+
</div>
|
| 115 |
+
</div>
|
| 116 |
+
</div>
|
| 117 |
+
<footer>
|
| 118 |
+
a11oy governance lane · doctrine v11 · Λ = Conjecture 1 (advisory) · SLSA L1 honest / L2 in progress / L3 roadmap · trust < 100% · 0 runtime CDN.
|
| 119 |
+
Data: <span class="mono">/api/a11oy/v1/gov/{eval,calibration,conformal,policy,ietf,lean,summary}</span>
|
| 120 |
+
</footer>
|
| 121 |
+
|
| 122 |
+
<script>
|
| 123 |
+
const $=s=>document.querySelector(s);
|
| 124 |
+
const esc=s=>String(s==null?"":s).replace(/[&<>]/g,c=>({"&":"&","<":"<",">":">"}[c]));
|
| 125 |
+
function kv(k,v){return `<div class="kv"><span class="k">${esc(k)}</span><span class="v">${v}</span></div>`}
|
| 126 |
+
async function getj(u){const r=await fetch(u);if(!r.ok)throw new Error(u+" -> "+r.status);return r.json()}
|
| 127 |
+
|
| 128 |
+
// ---- EVAL ----
|
| 129 |
+
getj("/api/a11oy/v1/gov/eval").then(d=>{
|
| 130 |
+
const pct=(d.score_pct!=null)?d.score_pct.toFixed(2)+"%":"—";
|
| 131 |
+
const asof=(d.as_of||"").slice(0,19).replace("T"," ")+" UTC";
|
| 132 |
+
const runner=(d.tasks&&d.tasks[0]&&d.tasks[0].trajectory||[]).some(s=>s.tool==="arena_gate.inspect")?"live _a11oy_arena_inspect gate":"reference rule-follower";
|
| 133 |
+
let rows="";
|
| 134 |
+
(d.domains?Object.entries(d.domains):[]).forEach(([dom,v])=>{
|
| 135 |
+
const st=v.status==="measured"?`<span class="pill ok">${(v.pass_at_1*100).toFixed(0)}%</span>`:`<span class="pill warn">not_measured</span>`;
|
| 136 |
+
rows+=`<tr><td>${esc(dom)}</td><td>${v.passed}/${v.total}</td><td>${st}</td></tr>`;
|
| 137 |
+
});
|
| 138 |
+
$("#eval").innerHTML=
|
| 139 |
+
`<div class="big">${pct}</div>`+
|
| 140 |
+
kv("suite",`<span class="mono">${esc(d.suite_id)} ${esc(d.suite_version)}</span>`)+
|
| 141 |
+
kv("metric",esc(d.metric))+
|
| 142 |
+
kv("tasks","<b>"+d.tasks_passed+"</b> / "+d.tasks_total+" passed")+
|
| 143 |
+
kv("negative controls",d.negative_controls)+
|
| 144 |
+
kv("runner",esc(runner))+
|
| 145 |
+
kv("as-of",`<span class="mono">${esc(asof)}</span>`)+
|
| 146 |
+
kv("determinism",`<span class="sha mono">${esc(d.determinism_hash)}</span>`)+
|
| 147 |
+
kv("run receipt",(d.receipt&&d.receipt.signed)?`<span class="pill ok">DSSE signed</span>`:`<span class="pill warn">unsigned</span>`)+
|
| 148 |
+
`<table style="margin-top:8px"><tr><th>domain</th><th>passed</th><th>pass^1</th></tr>${rows}</table>`+
|
| 149 |
+
`<div class="note">Cited as: “a11oy scores ${pct} on suite ${esc(d.suite_id)} ${esc(d.suite_version)}, as-of ${esc(asof)}.” An unrun domain renders <em>not_measured</em>, never 0.</div>`;
|
| 150 |
+
}).catch(e=>$("#eval").innerHTML=`<div class="err">eval unavailable: ${esc(e.message)}</div>`);
|
| 151 |
+
|
| 152 |
+
// ---- CALIBRATION ----
|
| 153 |
+
getj("/api/a11oy/v1/gov/calibration").then(d=>{
|
| 154 |
+
const m=d.metrics||{},g=d.automated_response_gate||{};
|
| 155 |
+
const measured=m.status==="measured";
|
| 156 |
+
const ecev=measured?m.ece.toFixed(4):"not_measured";
|
| 157 |
+
const brierv=measured&&m.brier!=null?m.brier.toFixed(4):"not_measured";
|
| 158 |
+
const gate=g.allow?`<span class="pill ok">ALLOW (ECE<${d.gate_threshold_ece})</span>`
|
| 159 |
+
:`<span class="pill err">DENY → human-on-loop</span>`;
|
| 160 |
+
$("#cal").innerHTML=
|
| 161 |
+
kv("model / agent",`<span class="mono">${esc(m.model)} / ${esc(m.agent_type)}</span>`)+
|
| 162 |
+
kv("status",measured?`<span class="pill acc">measured</span>`:`<span class="pill warn">${esc(m.status)}</span>`)+
|
| 163 |
+
kv("samples (n)",m.n)+
|
| 164 |
+
kv("ECE",`<b class="mono">${ecev}</b>`)+
|
| 165 |
+
kv("Brier"+(m.brier_kind?` (${esc(m.brier_kind)})`:""),`<span class="mono">${brierv}</span>`)+
|
| 166 |
+
kv("auto-response gate",gate)+
|
| 167 |
+
`<div class="note">${esc(g.honesty||m.honesty||"")}</div>`;
|
| 168 |
+
// reliability chart
|
| 169 |
+
const arr=Array.isArray(m.reliability)?m.reliability:[];
|
| 170 |
+
if(window.Chart&&arr.length){
|
| 171 |
+
new Chart($("#relchart"),{type:"bar",
|
| 172 |
+
data:{labels:arr.map(b=>(b.lo!=null?b.lo:0).toFixed(2)),
|
| 173 |
+
datasets:[
|
| 174 |
+
{label:"accuracy",data:arr.map(b=>b.accuracy),backgroundColor:"#5ad1c9"},
|
| 175 |
+
{label:"mean confidence",data:arr.map(b=>b.mean_conf),backgroundColor:"#7aa2f7",type:"line",borderColor:"#7aa2f7",fill:false}
|
| 176 |
+
]},
|
| 177 |
+
options:{plugins:{legend:{labels:{color:"#8b98a9"}}},
|
| 178 |
+
scales:{x:{ticks:{color:"#8b98a9"},grid:{color:"#1a2435"}},
|
| 179 |
+
y:{min:0,max:1,ticks:{color:"#8b98a9"},grid:{color:"#1a2435"}}}}});
|
| 180 |
+
}
|
| 181 |
+
}).catch(e=>$("#cal").innerHTML=`<div class="err">calibration unavailable: ${esc(e.message)}</div>`);
|
| 182 |
+
|
| 183 |
+
// ---- CONFORMAL ----
|
| 184 |
+
getj("/api/a11oy/v1/gov/conformal").then(d=>{
|
| 185 |
+
const cs=d.conformal_set||{};
|
| 186 |
+
const labels=cs.full_label_space||(cs.members||[]).map(m=>m.label)||[];
|
| 187 |
+
const inset=new Set(cs.set||[]);
|
| 188 |
+
let chips=labels.map(l=>`<span class="lab ${inset.has(l)?"in":""}">${esc(l)}${inset.has(l)?" ✓":""}</span>`).join("");
|
| 189 |
+
$("#conf").innerHTML=
|
| 190 |
+
kv("helper",`<span class="mono">${esc(d.helper_version)}</span>`)+
|
| 191 |
+
kv("coverage target",`≥ ${(d.coverage_target*100).toFixed(0)}%`)+
|
| 192 |
+
kv("α (alpha)",d.alpha)+
|
| 193 |
+
`<div class="note" style="margin:10px 0 4px">Instead of bare “confidence ${d.example_bare_confidence_pct}%”, the decision is reported as a SET guaranteed to contain the true class with ≥${(d.coverage_target*100).toFixed(0)}% coverage:</div>`+
|
| 194 |
+
`<div class="set">${chips}</div>`+
|
| 195 |
+
kv("set size",cs.set_size!=null?cs.set_size:(cs.set?cs.set.length:"—"))+
|
| 196 |
+
kv("singleton",cs.singleton?`<span class="pill ok">yes (decisive)</span>`:`<span class="pill warn">no (ambiguous)</span>`)+
|
| 197 |
+
kv("q̂ (quantile)",cs.q_hat!=null?cs.q_hat.toFixed(4):"—")+
|
| 198 |
+
kv("calibration n",cs.calibration_n)+
|
| 199 |
+
`<div class="note">${esc((d.bare_pct_replacement&&(d.bare_pct_replacement.display||d.bare_pct_replacement.replaces_bare_pct))||cs.guarantee||"")}</div>`;
|
| 200 |
+
}).catch(e=>$("#conf").innerHTML=`<div class="err">conformal unavailable: ${esc(e.message)}</div>`);
|
| 201 |
+
|
| 202 |
+
// ---- POLICY ----
|
| 203 |
+
getj("/api/a11oy/v1/gov/policy").then(d=>{
|
| 204 |
+
const a=d.audit_view||{};
|
| 205 |
+
let files=(a.files||[]).map(f=>
|
| 206 |
+
`<div class="file"><b>${esc(f.name)}</b> · id <span class="mono">${esc(f.policy_id)}</span> v${esc(f.policy_version)} · ${(f.flows||[]).length} flows<br>
|
| 207 |
+
<span class="sha">sha256: ${esc(f.sha256||f.sha||"")}</span>
|
| 208 |
+
<pre>${esc((f.content||"").slice(0,600))}${(f.content||"").length>600?"\n…":""}</pre></div>`).join("");
|
| 209 |
+
$("#pol").innerHTML=
|
| 210 |
+
kv("loaded",a.loaded?`<span class="pill ok">yes</span>`:`<span class="pill err">no</span>`)+
|
| 211 |
+
kv("files",a.file_count)+kv("total flows",a.flow_count)+
|
| 212 |
+
kv("NeMo runtime",a.nemoguardrails_runtime_present?`<span class="pill ok">present</span>`:`<span class="pill road">file-backed enforcement (runtime roadmap)</span>`)+
|
| 213 |
+
`<div style="margin-top:10px">${files}</div>`+
|
| 214 |
+
`<div class="note">${esc(a.honesty||"")}</div>`;
|
| 215 |
+
}).catch(e=>$("#pol").innerHTML=`<div class="err">policy unavailable: ${esc(e.message)}</div>`);
|
| 216 |
+
|
| 217 |
+
// ---- IETF ----
|
| 218 |
+
getj("/api/a11oy/v1/gov/ietf").then(d=>{
|
| 219 |
+
const p=d.compliance_profile||{},cp=p.compliance_payload||{},env=d.dsse_envelope||{};
|
| 220 |
+
const conf=p.conformance||{};
|
| 221 |
+
let checks=(conf.checks||[]).map(c=>`<tr><td>${esc(c.check)}</td><td>${c.ok?'<span class="pill ok">ok</span>':'<span class="pill err">fail</span>'}</td><td class="mono">${esc(c.detail)}</td></tr>`).join("");
|
| 222 |
+
let map=Object.entries(p.mapping||{}).map(([k,v])=>`<tr><td class="mono">${esc(k)}</td><td class="mono">${esc(v)}</td></tr>`).join("");
|
| 223 |
+
$("#ietf").innerHTML=
|
| 224 |
+
kv("draft",`<a href="https://datatracker.ietf.org/doc/${esc(p.draft)}/" target="_blank" rel="noopener" class="mono">${esc(p.draft)}</a>`)+
|
| 225 |
+
kv("status",esc(p.draft_status))+
|
| 226 |
+
kv("DSSE envelope",p.dsse_envelope_intact?`<span class="pill ok">${esc(p.dsse_alg)} (intact)</span>`:`<span class="pill err">modified</span>`)+
|
| 227 |
+
kv("DSSE kid",`<span class="mono">${esc(p.dsse_kid)}</span>`)+
|
| 228 |
+
kv("receipt type",`<span class="mono">${esc(cp.type)}</span>`)+
|
| 229 |
+
kv("decision",`<span class="pill ${cp.decision==='deny'?'err':'ok'}">${esc(cp.decision)}</span>`)+
|
| 230 |
+
kv("action_ref",`<span class="sha mono">${esc((cp.action_ref||'').slice(0,28))}…</span>`)+
|
| 231 |
+
kv("policy_digest",`<span class="sha mono">${esc((cp.policy_digest||'').slice(0,28))}…</span>`)+
|
| 232 |
+
kv("previousReceiptHash",`<span class="sha mono">${esc((cp.previousReceiptHash||'').slice(0,28))}…</span>`)+
|
| 233 |
+
kv("conformance",conf.ok?`<span class="pill ok">payload conforms to draft-05</span>`:`<span class="pill err">non-conformant</span>`)+
|
| 234 |
+
`<div class="note" style="margin-top:8px"><b>Field crosswalk (a11oy → draft-05):</b></div>`+
|
| 235 |
+
`<table><tr><th>a11oy field</th><th>draft-05 field</th></tr>${map}</table>`+
|
| 236 |
+
`<div class="note" style="margin-top:8px"><b>Conformance checks:</b></div>`+
|
| 237 |
+
`<table><tr><th>check</th><th>ok</th><th>detail</th></tr>${checks}</table>`+
|
| 238 |
+
`<div class="note">${esc(p.note||"")}</div>`;
|
| 239 |
+
}).catch(e=>$("#ietf").innerHTML=`<div class="err">ietf profile unavailable: ${esc(e.message)}</div>`);
|
| 240 |
+
|
| 241 |
+
// ---- LEAN ----
|
| 242 |
+
getj("/api/a11oy/v1/gov/lean").then(d=>{
|
| 243 |
+
let rows=(d.invariants||[]).map(i=>`<tr><td class="mono">${esc(i.name)}</td><td>${i.proved?'<span class="pill ok">proved</span>':`<span class="pill road">${esc(i.status||'roadmap')}</span>`}</td></tr>`).join("");
|
| 244 |
+
$("#lean").innerHTML=
|
| 245 |
+
kv("status",`<span class="pill road">${esc(d.status)}</span>`)+
|
| 246 |
+
kv("proved","<b>"+d.invariants_proved+"</b> / "+d.invariants_total)+
|
| 247 |
+
kv("file",`<span class="mono">${esc(d.file)}</span>`)+
|
| 248 |
+
`<table style="margin-top:8px"><tr><th>invariant</th><th>state</th></tr>${rows}</table>`+
|
| 249 |
+
`<div class="note">${esc(d.honesty||"")}</div>`;
|
| 250 |
+
}).catch(e=>$("#lean").innerHTML=`<div class="err">lean unavailable: ${esc(e.message)}</div>`);
|
| 251 |
+
</script>
|
| 252 |
+
</body>
|
| 253 |
+
</html>
|