Spaces:
Running
Running
I5: GRC alignment (coverage matrix, 13 Lambda->NIST mapping, OPA/Rego, OSCAL, DSSE schema) + shared platform-dynamics math. ALIGNS WITH, not certified.
Browse files- Dockerfile +13 -0
- a11oy_grc.py +346 -0
- a11oy_grc_data.py +382 -0
- compliance/oscal/a11oy-component-definition.json +138 -0
- compliance/rego/classification_boundary.rego +18 -0
- compliance/rego/deployment_readiness.rego +14 -0
- compliance/rego/human_override_required.rego +16 -0
- compliance/rego/manifest.json +36 -0
- serve.py +28 -0
- szl_cuas_formulas.py +244 -1
Dockerfile
CHANGED
|
@@ -764,6 +764,19 @@ COPY scripts/check_tau_eval.py ./scripts/check_tau_eval.py
|
|
| 764 |
COPY lean4agent/WorkflowInvariants.lean ./lean4agent/WorkflowInvariants.lean
|
| 765 |
COPY lean4agent/README.md ./lean4agent/README.md
|
| 766 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 767 |
CMD ["python", "serve.py"]
|
| 768 |
|
| 769 |
|
|
|
|
| 764 |
COPY lean4agent/WorkflowInvariants.lean ./lean4agent/WorkflowInvariants.lean
|
| 765 |
COPY lean4agent/README.md ./lean4agent/README.md
|
| 766 |
|
| 767 |
+
# GRC ALIGNMENT surface (Lane I5) — in-product ISO 42001 / NIST AI RMF / 800-53 /
|
| 768 |
+
# EU AI Act coverage matrix, 13 Λ→NIST mapping, OPA/Rego gates, OSCAL component-def,
|
| 769 |
+
# DSSE Receipt Schema v2. Explicit per-file COPY (this Dockerfile never uses COPY . .).
|
| 770 |
+
# serve.py imports a11oy_grc which imports a11oy_grc_data; the OSCAL JSON + Rego bundle
|
| 771 |
+
# ship in the image for audit. szl_cuas_formulas.py (shared, byte-identical w/ killinchu)
|
| 772 |
+
# is already COPY'd above for the active-flux router + platform-dynamics math.
|
| 773 |
+
COPY a11oy_grc.py a11oy_grc_data.py ./
|
| 774 |
+
COPY compliance/oscal/a11oy-component-definition.json ./compliance/oscal/a11oy-component-definition.json
|
| 775 |
+
COPY compliance/rego/classification_boundary.rego ./compliance/rego/classification_boundary.rego
|
| 776 |
+
COPY compliance/rego/human_override_required.rego ./compliance/rego/human_override_required.rego
|
| 777 |
+
COPY compliance/rego/deployment_readiness.rego ./compliance/rego/deployment_readiness.rego
|
| 778 |
+
COPY compliance/rego/manifest.json ./compliance/rego/manifest.json
|
| 779 |
+
|
| 780 |
CMD ["python", "serve.py"]
|
| 781 |
|
| 782 |
|
a11oy_grc.py
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
# © 2026 Lutar, Stephen P. Jr. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11
|
| 3 |
+
"""a11oy_grc.py — in-product GRC ALIGNMENT surface (Lane I5).
|
| 4 |
+
|
| 5 |
+
Mounts a11oy's Governance / Compliance surface:
|
| 6 |
+
* GET /api/a11oy/v1/grc/matrix — honest ISO 42001 / NIST AI RMF / 800-53 / EU AI Act
|
| 7 |
+
coverage matrix (COVERED / PARTIAL / ROADMAP / NA).
|
| 8 |
+
* GET /api/a11oy/v1/grc/mapping — 13 Λ axes → NIST AI RMF MEASURE 2 (+ Credo AI labels),
|
| 9 |
+
the Rego policy gates, the version-locked bundle digest,
|
| 10 |
+
and the DSSE Receipt Schema v2 (field → control IDs).
|
| 11 |
+
* GET /api/a11oy/v1/grc/oscal — OSCAL component-definition JSON (also published to the
|
| 12 |
+
repo at compliance/oscal/a11oy-component-definition.json).
|
| 13 |
+
* GET /api/a11oy/v1/grc/info — capability descriptor.
|
| 14 |
+
* GET /grc (a.k.a. /compliance) — self-contained, 0-CDN "Compliance / GRC" page.
|
| 15 |
+
|
| 16 |
+
Routes are DUAL-REGISTERED at both /api/a11oy/v1/... AND /v1/... (the HF proxy strips the
|
| 17 |
+
/api/a11oy prefix — same convention Dev E's active-flux router uses). A11oy-styled page;
|
| 18 |
+
shared scripts vendored at /static/shared/. Nav link is injected by this module's OWN
|
| 19 |
+
idempotent BaseHTTPMiddleware (mirroring serve.py's _OperatorWidgetInjector) — the console
|
| 20 |
+
SPA source is NOT edited, and the injector NEVER clobbers other devs' nav items.
|
| 21 |
+
|
| 22 |
+
HONEST (Doctrine v11): a11oy ALIGNS WITH / MAPS TO frameworks — NEVER "certified" or
|
| 23 |
+
"compliant". No third-party certification obtained. Gaps shown honestly. Λ = Conjecture 1;
|
| 24 |
+
locked-proven = 8 @ c7c0ba17; trust never 100%; 0 runtime CDN. Adds NOTHING to the locked-8.
|
| 25 |
+
"""
|
| 26 |
+
from __future__ import annotations
|
| 27 |
+
|
| 28 |
+
import json
|
| 29 |
+
from typing import Any, Dict, List
|
| 30 |
+
|
| 31 |
+
import a11oy_grc_data as _grc
|
| 32 |
+
|
| 33 |
+
SOURCES = _grc.SOURCES
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
def info(ns: str = "a11oy") -> Dict[str, Any]:
|
| 37 |
+
return {
|
| 38 |
+
"capability": "GRC Alignment — ISO 42001 / NIST AI RMF / 800-53 / EU AI Act",
|
| 39 |
+
"ns": ns,
|
| 40 |
+
"summary": ("In-product, HONEST governance coverage matrix; 13 Λ axes mapped to NIST AI "
|
| 41 |
+
"RMF MEASURE 2; policy gates as OPA/Rego with a version-locked bundle digest; "
|
| 42 |
+
"OSCAL component-definition published to the repo; DSSE Receipt Schema v2 cites "
|
| 43 |
+
"control IDs. ALIGNS WITH / MAPS TO — never certified."),
|
| 44 |
+
"endpoints": {
|
| 45 |
+
"matrix": f"/api/{ns}/v1/grc/matrix",
|
| 46 |
+
"mapping": f"/api/{ns}/v1/grc/mapping",
|
| 47 |
+
"oscal": f"/api/{ns}/v1/grc/oscal",
|
| 48 |
+
"page": "/grc",
|
| 49 |
+
},
|
| 50 |
+
"oscal_artifact": "compliance/oscal/a11oy-component-definition.json",
|
| 51 |
+
"doctrine": {"locked_proven": 8, "kernel_commit": _grc.KERNEL_COMMIT,
|
| 52 |
+
"lambda": "Conjecture 1", "khipu_bft": "Conjecture 2",
|
| 53 |
+
"trust": "never 100%", "framing": "aligns with / maps to (NOT certified)"},
|
| 54 |
+
"sources": SOURCES, "honest": _grc.HONEST_DISCLAIMER,
|
| 55 |
+
"status": "ALIGNMENT (no third-party certification)",
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
_COV_COLOR = {"COVERED": "#39d3c4", "PARTIAL": "#e8c074", "ROADMAP": "#6fb1ff", "NA": "#6f8190"}
|
| 60 |
+
_COV_GLYPH = {"COVERED": "●", "PARTIAL": "◐", "ROADMAP": "○", "NA": "—"}
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
def _matrix_rows_html() -> str:
|
| 64 |
+
rows = []
|
| 65 |
+
for r in _grc.COVERAGE_MATRIX:
|
| 66 |
+
col = _COV_COLOR.get(r["coverage"], "#9fb1bf")
|
| 67 |
+
g = _COV_GLYPH.get(r["coverage"], "·")
|
| 68 |
+
rows.append(
|
| 69 |
+
f'<tr><td class="ctl">{r["control"]}</td><td>{r["framework"]}</td>'
|
| 70 |
+
f'<td>{r["title"]}</td><td class="mech">{r["mechanism"]}</td>'
|
| 71 |
+
f'<td style="color:{col};white-space:nowrap">{g} {r["coverage"]}</td></tr>')
|
| 72 |
+
return "".join(rows)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def _axes_rows_html() -> str:
|
| 76 |
+
rows = []
|
| 77 |
+
for a in _grc.LAMBDA_AXES:
|
| 78 |
+
col = _COV_COLOR.get(a["coverage"], "#9fb1bf")
|
| 79 |
+
rows.append(
|
| 80 |
+
f'<tr><td class="ctl">Λ{a["axis"]}</td><td>{a["lambda_axis"]}</td>'
|
| 81 |
+
f'<td>{a["nist_measure"]}</td><td>{a["credo_dimension"]}</td>'
|
| 82 |
+
f'<td class="mech">{a["mechanism"]}</td>'
|
| 83 |
+
f'<td style="color:{col}">{a["coverage"]}</td></tr>')
|
| 84 |
+
return "".join(rows)
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def _page_html(ns: str) -> str:
|
| 88 |
+
summ = _grc.coverage_summary()
|
| 89 |
+
digest = _grc.policy_bundle_digest()
|
| 90 |
+
summ_html = " · ".join(
|
| 91 |
+
f'<span style="color:{_COV_COLOR.get(k,"#9fb1bf")}">{_COV_GLYPH.get(k,"·")} {k}={v}</span>'
|
| 92 |
+
for k, v in sorted(summ.items()))
|
| 93 |
+
return r"""<!DOCTYPE html><html lang="en"><head><meta charset="utf-8">
|
| 94 |
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 95 |
+
<title>Compliance / GRC Alignment — a11oy</title>
|
| 96 |
+
<style>
|
| 97 |
+
:root{--bg:#070b10;--panel:#0d141c;--line:#1d2a36;--teal:#39d3c4;--gold:#e8c074;--cream:#eef3f6;--para:#9fb1bf;}
|
| 98 |
+
*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--cream);font:14px/1.5 ui-sans-serif,system-ui,Segoe UI,Roboto,Arial}
|
| 99 |
+
a{color:var(--teal);text-decoration:none}
|
| 100 |
+
header{padding:14px 18px;border-bottom:1px solid var(--line);background:linear-gradient(180deg,#0a1119,#070b10)}
|
| 101 |
+
h1{font-size:18px;margin:0 0 2px}.sub{color:var(--para);font-size:12.5px;max-width:1040px}
|
| 102 |
+
.badge{display:inline-block;font-size:10.5px;padding:2px 7px;border-radius:6px;border:1px solid var(--line);margin-right:6px;color:var(--gold);background:#10171f;vertical-align:middle}
|
| 103 |
+
.wrap{max-width:1080px;margin:0 auto;padding:16px}
|
| 104 |
+
.panel{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:14px;margin-bottom:14px}
|
| 105 |
+
.panel h2{font-size:14px;margin:0 0 8px}.pp{color:var(--para);font-size:12px;margin:0 0 10px}
|
| 106 |
+
table{width:100%;border-collapse:collapse;font-size:12px}
|
| 107 |
+
th,td{text-align:left;padding:6px 8px;border-bottom:1px solid #131e27;vertical-align:top}
|
| 108 |
+
th{color:var(--gold);font-weight:600;position:sticky;top:0;background:#0d141c}
|
| 109 |
+
td.ctl{color:var(--teal);font-variant-numeric:tabular-nums;white-space:nowrap;font-family:ui-monospace,monospace}
|
| 110 |
+
td.mech{color:var(--para)}
|
| 111 |
+
.scroll{max-height:420px;overflow:auto;border:1px solid var(--line);border-radius:8px}
|
| 112 |
+
.disc{font-size:11.5px;color:var(--gold);background:#171206;border:1px solid #3a2e10;border-radius:8px;padding:10px;margin-bottom:14px;line-height:1.6}
|
| 113 |
+
.crosslinks a{margin-right:14px}
|
| 114 |
+
.out{white-space:pre-wrap;font:11px ui-monospace,monospace;color:#bfe;background:#06090d;border:1px solid var(--line);border-radius:7px;padding:8px;max-height:240px;overflow:auto}
|
| 115 |
+
.src{font-size:11px;color:var(--para);margin-top:10px;line-height:1.7}.src a{color:var(--teal)}
|
| 116 |
+
footer{padding:12px 18px;border-top:1px solid var(--line);color:var(--para);font-size:11px}
|
| 117 |
+
code{color:var(--teal);font-family:ui-monospace,monospace}
|
| 118 |
+
</style></head><body>
|
| 119 |
+
<header><h1>Compliance / GRC Alignment
|
| 120 |
+
<span class="badge">ALIGNS WITH · NOT CERTIFIED</span><span class="badge">Λ = Conjecture 1</span>
|
| 121 |
+
<span class="badge">0 runtime CDN</span></h1>
|
| 122 |
+
<div class="sub">a11oy's mechanisms cross-referenced to <b>ISO/IEC 42001:2023</b>, <b>NIST AI RMF 1.0</b>,
|
| 123 |
+
<b>NIST SP 800-53 Rev 5</b>, and the <b>EU AI Act</b>. The 13 Λ trust axes map to NIST AI RMF
|
| 124 |
+
MEASURE 2; policy gates are published as OPA/Rego; a machine-readable OSCAL component-definition
|
| 125 |
+
is committed to the repo. <a href="/">← a11oy console</a></div></header>
|
| 126 |
+
<div class="wrap">
|
| 127 |
+
<div class="disc">__DISC__</div>
|
| 128 |
+
|
| 129 |
+
<div class="panel">
|
| 130 |
+
<h2>Coverage matrix — __SUMM__</h2>
|
| 131 |
+
<p class="pp">Honest per-control state. <code>COVERED</code> = a specific testable mechanism;
|
| 132 |
+
<code>PARTIAL</code> = mechanism exists but incomplete; <code>ROADMAP</code> = planned;
|
| 133 |
+
<code>N/A</code> = out of scope (with reason). EU AI Act self-classification:
|
| 134 |
+
<b>High-Risk</b> (defense-tech agentic orchestrator).</p>
|
| 135 |
+
<div class="scroll"><table>
|
| 136 |
+
<thead><tr><th>Control</th><th>Framework</th><th>Title</th><th>a11oy mechanism</th><th>Coverage</th></tr></thead>
|
| 137 |
+
<tbody>__MATRIX__</tbody></table></div>
|
| 138 |
+
</div>
|
| 139 |
+
|
| 140 |
+
<div class="panel">
|
| 141 |
+
<h2>13 Λ axes → NIST AI RMF MEASURE 2 (+ Credo AI / MIT taxonomy)</h2>
|
| 142 |
+
<p class="pp">Each proprietary Λ axis gets an industry-standard referent so external evaluators
|
| 143 |
+
recognise it without a custom glossary.</p>
|
| 144 |
+
<div class="scroll"><table>
|
| 145 |
+
<thead><tr><th>Λ axis</th><th>Trust dimension</th><th>NIST AI RMF</th><th>Credo AI / MIT</th><th>Mechanism</th><th>State</th></tr></thead>
|
| 146 |
+
<tbody>__AXES__</tbody></table></div>
|
| 147 |
+
</div>
|
| 148 |
+
|
| 149 |
+
<div class="panel">
|
| 150 |
+
<h2>Policy gates as OPA/Rego + DSSE Receipt Schema v2</h2>
|
| 151 |
+
<p class="pp">Gates are published policy-as-code; the bundle is version-locked by a SHA-256
|
| 152 |
+
digest that every DSSE receipt cites, so a receipt proves WHICH policy version made the
|
| 153 |
+
decision. Each receipt field maps to specific control IDs (800-53 AU/CM/RA family,
|
| 154 |
+
EU AI Act Art. 12/14, ISO 42001 A.x). Receipts are ECDSA-P256/DSSE signed; re-verify at
|
| 155 |
+
<a href="/cosign.pub">/cosign.pub</a>.</p>
|
| 156 |
+
<div class="pp">policy bundle digest: <code>__DIGEST__</code></div>
|
| 157 |
+
<details><summary style="cursor:pointer;color:var(--teal)">raw /grc/mapping (Λ→NIST, Rego, DSSE schema)</summary>
|
| 158 |
+
<div class="out" id="raw-map">loading…</div></details>
|
| 159 |
+
</div>
|
| 160 |
+
|
| 161 |
+
<div class="panel">
|
| 162 |
+
<h2>OSCAL component-definition</h2>
|
| 163 |
+
<p class="pp">Machine-readable OSCAL (control source = usnistgov/oscal-content SP 800-53 Rev 5
|
| 164 |
+
catalog), committed to the repo at
|
| 165 |
+
<code>compliance/oscal/a11oy-component-definition.json</code> and served live below.
|
| 166 |
+
ALIGNMENT only — never a certification artifact.</p>
|
| 167 |
+
<div class="crosslinks pp">
|
| 168 |
+
<a href="/api/__NS__/v1/grc/matrix" target="_blank">matrix JSON</a>
|
| 169 |
+
<a href="/api/__NS__/v1/grc/mapping" target="_blank">mapping JSON</a>
|
| 170 |
+
<a href="/api/__NS__/v1/grc/oscal" target="_blank">OSCAL JSON</a></div>
|
| 171 |
+
<details><summary style="cursor:pointer;color:var(--teal)">raw /grc/oscal (component-definition)</summary>
|
| 172 |
+
<div class="out" id="raw-oscal">loading…</div></details>
|
| 173 |
+
</div>
|
| 174 |
+
|
| 175 |
+
<div class="src">Adopted & cited — sources:
|
| 176 |
+
<a href="https://www.iso.org/standard/81230.html" target="_blank" rel="noopener">ISO/IEC 42001:2023</a> ·
|
| 177 |
+
<a href="https://airc.nist.gov/airmf-resources/airmf/5-sec-core/" target="_blank" rel="noopener">NIST AI RMF 1.0</a> ·
|
| 178 |
+
<a href="https://github.com/usnistgov/OSCAL" target="_blank" rel="noopener">OSCAL (usnistgov)</a> ·
|
| 179 |
+
<a href="https://github.com/usnistgov/oscal-content" target="_blank" rel="noopener">oscal-content</a> ·
|
| 180 |
+
<a href="https://www.openpolicyagent.org/docs/latest/policy-language/" target="_blank" rel="noopener">OPA / Rego</a> ·
|
| 181 |
+
<a href="https://airisk.mit.edu/" target="_blank" rel="noopener">MIT AI Risk Repository (Credo AI taxonomy)</a> ·
|
| 182 |
+
<a href="https://artificialintelligenceact.eu/high-level-summary/" target="_blank" rel="noopener">EU AI Act</a>.</div>
|
| 183 |
+
</div>
|
| 184 |
+
<footer>Doctrine v11 · locked = 8 @ c7c0ba17 · Λ = Conjecture 1 · Khipu BFT = Conjecture 2 ·
|
| 185 |
+
<b>GRC ALIGNMENT — aligns with / maps to, NOT certified</b> · 0 runtime CDN · trust < 100%.</footer>
|
| 186 |
+
<script src="/static/shared/szl_label_engine.js" defer></script>
|
| 187 |
+
<script src="/static/shared/szl_receipt_cosign.js" defer></script>
|
| 188 |
+
<script src="/static/shared/szl_codename_sanitizer.js" defer></script>
|
| 189 |
+
<script>
|
| 190 |
+
"use strict";
|
| 191 |
+
const API="/api/__NS__/v1/grc";
|
| 192 |
+
async function load(){
|
| 193 |
+
try{const m=await (await fetch(API+"/mapping")).json();
|
| 194 |
+
document.getElementById("raw-map").textContent=JSON.stringify(m,null,1);
|
| 195 |
+
}catch(e){document.getElementById("raw-map").textContent="endpoint unreachable: "+e;}
|
| 196 |
+
try{const o=await (await fetch(API+"/oscal")).json();
|
| 197 |
+
document.getElementById("raw-oscal").textContent=JSON.stringify(o,null,1);
|
| 198 |
+
}catch(e){document.getElementById("raw-oscal").textContent="endpoint unreachable: "+e;}
|
| 199 |
+
}
|
| 200 |
+
load();
|
| 201 |
+
</script></body></html>""" \
|
| 202 |
+
.replace("__DISC__", _grc.HONEST_DISCLAIMER) \
|
| 203 |
+
.replace("__SUMM__", summ_html) \
|
| 204 |
+
.replace("__MATRIX__", _matrix_rows_html()) \
|
| 205 |
+
.replace("__AXES__", _axes_rows_html()) \
|
| 206 |
+
.replace("__DIGEST__", digest) \
|
| 207 |
+
.replace("__NS__", ns)
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
# ── idempotent nav-link injection middleware (mirrors serve.py _OperatorWidgetInjector) ──
|
| 211 |
+
_NAV_MARKER = b'data-view-grc="grc"'
|
| 212 |
+
# inject a nav-item linking to the standalone /grc page; placed right AFTER the existing
|
| 213 |
+
# "Readiness & Compliance" (govern) nav-item if present, else before the first nav-group,
|
| 214 |
+
# else just before </body>. NEVER edits other devs' nav items.
|
| 215 |
+
_NAV_LINK = (b'<div class="nav-item" data-view-grc="grc" '
|
| 216 |
+
b'onclick="location.href=\'/grc\'" style="cursor:pointer">'
|
| 217 |
+
b'<span class="ico">\xe2\x9a\x96</span>Compliance / GRC</div>')
|
| 218 |
+
_GOVERN_ANCHOR = b'Readiness & Compliance</div>'
|
| 219 |
+
_GROUP_ANCHOR = b'<div class="nav-group">'
|
| 220 |
+
|
| 221 |
+
|
| 222 |
+
def _make_injector():
|
| 223 |
+
from starlette.middleware.base import BaseHTTPMiddleware
|
| 224 |
+
from starlette.responses import Response
|
| 225 |
+
|
| 226 |
+
class _GrcNavInjector(BaseHTTPMiddleware):
|
| 227 |
+
async def dispatch(self, request, call_next):
|
| 228 |
+
resp = await call_next(request)
|
| 229 |
+
try:
|
| 230 |
+
ct = (resp.headers.get("content-type") or "").lower()
|
| 231 |
+
if "text/html" not in ct:
|
| 232 |
+
return resp
|
| 233 |
+
p = request.url.path
|
| 234 |
+
if (p.startswith("/api/") or p.startswith("/v1/") or p.startswith("/vendor/")
|
| 235 |
+
or p.startswith("/assets/") or p.startswith("/static/") or p == "/grc"):
|
| 236 |
+
return resp
|
| 237 |
+
body = b""
|
| 238 |
+
async for chunk in resp.body_iterator:
|
| 239 |
+
body += chunk if isinstance(chunk, (bytes, bytearray)) else str(chunk).encode()
|
| 240 |
+
if _NAV_MARKER in body: # idempotent
|
| 241 |
+
new_body = body
|
| 242 |
+
elif _GOVERN_ANCHOR in body: # after Readiness & Compliance
|
| 243 |
+
new_body = body.replace(_GOVERN_ANCHOR, _GOVERN_ANCHOR + _NAV_LINK, 1)
|
| 244 |
+
elif _GROUP_ANCHOR in body: # before the first nav-group
|
| 245 |
+
new_body = body.replace(_GROUP_ANCHOR, _NAV_LINK + _GROUP_ANCHOR, 1)
|
| 246 |
+
elif b"</body>" in body:
|
| 247 |
+
new_body = body.replace(b"</body>", _NAV_LINK + b"</body>", 1)
|
| 248 |
+
else:
|
| 249 |
+
return resp
|
| 250 |
+
headers = dict(resp.headers)
|
| 251 |
+
headers.pop("content-length", None)
|
| 252 |
+
return Response(content=new_body, status_code=resp.status_code,
|
| 253 |
+
headers=headers, media_type="text/html")
|
| 254 |
+
except Exception:
|
| 255 |
+
return resp
|
| 256 |
+
|
| 257 |
+
return _GrcNavInjector
|
| 258 |
+
|
| 259 |
+
|
| 260 |
+
def register(app, ns: str = "a11oy") -> Dict[str, Any]:
|
| 261 |
+
"""Attach the GRC alignment surface. ADDITIVE; BEFORE the SPA/proxy catch-all. Pure
|
| 262 |
+
stdlib + a11oy_grc_data. 0 CDN. Routes dual-registered at /api/<ns>/v1/grc and /v1/grc."""
|
| 263 |
+
from starlette.responses import HTMLResponse, JSONResponse
|
| 264 |
+
registered: List[str] = []
|
| 265 |
+
|
| 266 |
+
def _matrix():
|
| 267 |
+
return JSONResponse(_grc.build_matrix())
|
| 268 |
+
|
| 269 |
+
def _mapping():
|
| 270 |
+
return JSONResponse(_grc.build_mapping())
|
| 271 |
+
|
| 272 |
+
def _oscal():
|
| 273 |
+
return JSONResponse(_grc.build_oscal())
|
| 274 |
+
|
| 275 |
+
for prefix in (f"/api/{ns}/v1/grc", "/v1/grc"):
|
| 276 |
+
app.add_api_route(f"{prefix}/matrix", _matrix, methods=["GET"])
|
| 277 |
+
app.add_api_route(f"{prefix}/mapping", _mapping, methods=["GET"])
|
| 278 |
+
app.add_api_route(f"{prefix}/oscal", _oscal, methods=["GET"])
|
| 279 |
+
app.add_api_route(f"{prefix}/info", lambda: JSONResponse(info(ns)), methods=["GET"])
|
| 280 |
+
registered.append(f"GET {prefix}/matrix")
|
| 281 |
+
|
| 282 |
+
_html = _page_html(ns)
|
| 283 |
+
|
| 284 |
+
async def _page():
|
| 285 |
+
return HTMLResponse(_html)
|
| 286 |
+
app.add_api_route("/grc", _page, methods=["GET"])
|
| 287 |
+
app.add_api_route("/compliance", _page, methods=["GET"])
|
| 288 |
+
registered.append("GET /grc")
|
| 289 |
+
registered.append("GET /compliance")
|
| 290 |
+
|
| 291 |
+
try:
|
| 292 |
+
app.add_middleware(_make_injector())
|
| 293 |
+
registered.append("MIDDLEWARE grc nav-link injector")
|
| 294 |
+
except Exception:
|
| 295 |
+
pass
|
| 296 |
+
|
| 297 |
+
return {"registered": registered, "count": len(registered),
|
| 298 |
+
"capability": "GRC Alignment", "data_label": "ALIGNMENT"}
|
| 299 |
+
|
| 300 |
+
|
| 301 |
+
def _selftest() -> None:
|
| 302 |
+
from fastapi import FastAPI
|
| 303 |
+
from fastapi.responses import HTMLResponse
|
| 304 |
+
from fastapi.testclient import TestClient
|
| 305 |
+
app = FastAPI()
|
| 306 |
+
st = register(app, ns="a11oy")
|
| 307 |
+
assert st["count"] >= 5
|
| 308 |
+
|
| 309 |
+
@app.get("/console", response_class=HTMLResponse)
|
| 310 |
+
def _c():
|
| 311 |
+
return ('<html><body><div class="nav-group">Operate</div>'
|
| 312 |
+
'<div class="nav-item" data-view="govern" onclick="go(\'govern\')">'
|
| 313 |
+
'<span class="ico">x</span>Readiness & Compliance</div>'
|
| 314 |
+
'</body></html>')
|
| 315 |
+
|
| 316 |
+
c = TestClient(app)
|
| 317 |
+
for ep in ["/api/a11oy/v1/grc/matrix", "/api/a11oy/v1/grc/mapping",
|
| 318 |
+
"/api/a11oy/v1/grc/oscal", "/api/a11oy/v1/grc/info",
|
| 319 |
+
"/v1/grc/matrix", "/grc", "/compliance"]:
|
| 320 |
+
r = c.get(ep)
|
| 321 |
+
assert r.status_code == 200, (ep, r.status_code)
|
| 322 |
+
# honesty checks on the page
|
| 323 |
+
page = c.get("/grc").text
|
| 324 |
+
assert "ALIGNS WITH" in page and "NOT CERTIFIED" in page
|
| 325 |
+
assert "certified against" not in page.lower()
|
| 326 |
+
# nav injection idempotent + placed after govern anchor
|
| 327 |
+
h1 = c.get("/console").text
|
| 328 |
+
h2 = c.get("/console").text
|
| 329 |
+
assert h1.count('data-view-grc="grc"') == 1, "nav must inject exactly once"
|
| 330 |
+
assert h2.count('data-view-grc="grc"') == 1, "nav must be idempotent"
|
| 331 |
+
assert "Readiness & Compliance</div><div class=\"nav-item\" data-view-grc" in h1, "must place after govern"
|
| 332 |
+
# OSCAL endpoint must be valid OSCAL component-definition
|
| 333 |
+
o = c.get("/api/a11oy/v1/grc/oscal").json()
|
| 334 |
+
assert "component-definition" in o and o["component-definition"]["components"]
|
| 335 |
+
# matrix honesty: must contain at least one PARTIAL and one ROADMAP (shows gaps)
|
| 336 |
+
mx = c.get("/api/a11oy/v1/grc/matrix").json()
|
| 337 |
+
assert mx["summary"].get("PARTIAL", 0) > 0 and mx["summary"].get("ROADMAP", 0) > 0
|
| 338 |
+
# 0 CDN: page must only reference /static/shared and same-origin
|
| 339 |
+
import re
|
| 340 |
+
ext = re.findall(r'src="(https?://[^"]+)"', page)
|
| 341 |
+
assert not ext, "no external script src allowed: %s" % ext
|
| 342 |
+
print("a11oy_grc: ALL OK (%d routes; nav idempotent; honest; OSCAL valid; 0 CDN)" % st["count"])
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
if __name__ == "__main__":
|
| 346 |
+
_selftest()
|
a11oy_grc_data.py
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# SPDX-License-Identifier: Apache-2.0
|
| 2 |
+
# © 2026 Lutar, Stephen P. Jr. — SZL Holdings · ORCID 0009-0001-0110-4173 · Doctrine v11
|
| 3 |
+
"""a11oy_grc_data.py — GRC ALIGNMENT content (Lane I5).
|
| 4 |
+
|
| 5 |
+
The HONEST, machine-readable substrate for a11oy's in-product Governance/Compliance
|
| 6 |
+
surface. This module holds NO web framework code — it is the pure data + builders that
|
| 7 |
+
a11oy_grc.py (routes/page/nav) and the published OSCAL artifact both consume, so the
|
| 8 |
+
matrix, the Λ→NIST mapping, the Rego bundle metadata, and the OSCAL component-definition
|
| 9 |
+
are all derived from a SINGLE source of truth and can never drift.
|
| 10 |
+
|
| 11 |
+
DOCTRINE / FRAMING (critical — never overclaim):
|
| 12 |
+
* a11oy "aligns with" / "maps to" / "provides evidence for" — NEVER "certified against"
|
| 13 |
+
or "compliant with". No third-party certification has been obtained for ANY framework
|
| 14 |
+
as of Doctrine v11. Coverage = a11oy's INTERNAL analysis of its mechanisms vs published
|
| 15 |
+
framework control text. Gaps are shown HONESTLY (more credible than overclaiming).
|
| 16 |
+
* Coverage states are HONEST: COVERED (specific testable mechanism), PARTIAL (mechanism
|
| 17 |
+
exists but incomplete), ROADMAP (planned, target version), NA (out of scope w/ reason).
|
| 18 |
+
* Λ = Conjecture 1 (NOT a closed theorem); Khipu BFT = Conjecture 2; locked-proven = 8
|
| 19 |
+
@ c7c0ba17; trust never 100%. This surface adds NOTHING to the locked-8.
|
| 20 |
+
|
| 21 |
+
SOURCES (cited; adopted, NOT reclaimed as SZL theorems):
|
| 22 |
+
- ISO/IEC 42001:2023 (AI management system) — 38 controls / 9 objectives A.2–A.10.
|
| 23 |
+
- NIST AI RMF 1.0 — 72 subcategories across GOVERN(19)/MAP(18)/MEASURE(19)/MANAGE(17).
|
| 24 |
+
- NIST SP 800-53 Rev 5 + usnistgov/OSCAL + usnistgov/oscal-content (catalog source).
|
| 25 |
+
- Open Policy Agent / Rego (policy-as-code).
|
| 26 |
+
- Credo AI 10-dimension risk taxonomy (derives from the MIT AI Risk Repository).
|
| 27 |
+
- EU AI Act (a11oy self-classifies as High-Risk, defense-tech) Art. 9 / Art. 12 / Art. 14.
|
| 28 |
+
"""
|
| 29 |
+
from __future__ import annotations
|
| 30 |
+
|
| 31 |
+
import hashlib
|
| 32 |
+
import json
|
| 33 |
+
from typing import Any, Dict, List
|
| 34 |
+
|
| 35 |
+
DOCTRINE_VERSION = "v11"
|
| 36 |
+
KERNEL_COMMIT = "c7c0ba17"
|
| 37 |
+
|
| 38 |
+
SOURCES: Dict[str, str] = {
|
| 39 |
+
"ISO/IEC 42001:2023 (AI management system)": "https://www.iso.org/standard/81230.html",
|
| 40 |
+
"ISO 42001 Annex A control list (reference)": "https://mindsetcyber.com.au/iso-42001-controls-list/",
|
| 41 |
+
"NIST AI RMF 1.0 Core": "https://airc.nist.gov/airmf-resources/airmf/5-sec-core/",
|
| 42 |
+
"NIST AI RMF Playbook (subcategory detail)": "https://airc.nist.gov/docs/AI_RMF_Playbook.pdf",
|
| 43 |
+
"NIST SP 800-53 Rev 5 catalog (OSCAL JSON)":
|
| 44 |
+
"https://raw.githubusercontent.com/usnistgov/oscal-content/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_catalog.json",
|
| 45 |
+
"OSCAL (usnistgov/OSCAL)": "https://github.com/usnistgov/OSCAL",
|
| 46 |
+
"OSCAL content (usnistgov/oscal-content)": "https://github.com/usnistgov/oscal-content",
|
| 47 |
+
"Open Policy Agent / Rego": "https://www.openpolicyagent.org/docs/latest/policy-language/",
|
| 48 |
+
"Credo AI risk taxonomy / MIT AI Risk Repository": "https://airisk.mit.edu/",
|
| 49 |
+
"EU AI Act high-level summary": "https://artificialintelligenceact.eu/high-level-summary/",
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
HONEST_DISCLAIMER = (
|
| 53 |
+
"Coverage assessments reflect a11oy's INTERNAL analysis of its mechanisms against "
|
| 54 |
+
"published framework control text. a11oy ALIGNS WITH / MAPS TO these frameworks; it "
|
| 55 |
+
"does NOT claim certification. No third-party certification has been obtained for any "
|
| 56 |
+
"framework as of Doctrine " + DOCTRINE_VERSION + ". Gaps are shown honestly. "
|
| 57 |
+
"Λ = Conjecture 1; locked-proven = 8 @ " + KERNEL_COMMIT + "; trust never 100%."
|
| 58 |
+
)
|
| 59 |
+
|
| 60 |
+
# ───────────────────────────────────────────────────────────────────────────
|
| 61 |
+
# 13 Λ axes → NIST AI RMF MEASURE 2 subcategories (+ Credo AI / MIT taxonomy label)
|
| 62 |
+
# a11oy's Λ trust score has 13 axes. The first 10 map 1:1 to NIST AI RMF MEASURE 2.1–2.10;
|
| 63 |
+
# the remaining 3 are governance/autonomy axes that map to GOVERN/MAP subcategories. Every
|
| 64 |
+
# row carries the industry-standard Credo AI dimension name so external evaluators recognise
|
| 65 |
+
# the axis without a custom glossary. (UPGRADE #1 + #5 of GRC_ONETRUST_RESEARCH.)
|
| 66 |
+
# ───────────────────────────────────────────────────────────────────────────
|
| 67 |
+
LAMBDA_AXES: List[Dict[str, Any]] = [
|
| 68 |
+
{"axis": 1, "lambda_axis": "scoring methodology / documentation",
|
| 69 |
+
"nist_measure": "MEASURE 2.1", "nist_text": "Test methods and metrics for AI risk",
|
| 70 |
+
"credo_dimension": "Information Integrity (methodology)",
|
| 71 |
+
"mechanism": "Λ 13-axis scoring rubric documented + exposed in every DSSE receipt", "coverage": "COVERED"},
|
| 72 |
+
{"axis": 2, "lambda_axis": "factual accuracy / hallucination rate",
|
| 73 |
+
"nist_measure": "MEASURE 2.2", "nist_text": "Evaluating AI systems for accuracy, interpretability",
|
| 74 |
+
"credo_dimension": "Information Integrity",
|
| 75 |
+
"mechanism": "Lean-proven formula verification; factuality axis scored per inference", "coverage": "COVERED"},
|
| 76 |
+
{"axis": 3, "lambda_axis": "robustness / adversarial resistance",
|
| 77 |
+
"nist_measure": "MEASURE 2.3", "nist_text": "Evaluating for reliability / robustness",
|
| 78 |
+
"credo_dimension": "Security (adversarial resistance)",
|
| 79 |
+
"mechanism": "Red-team / prompt-injection resistance score feeds the robustness axis", "coverage": "PARTIAL"},
|
| 80 |
+
{"axis": 4, "lambda_axis": "operational resilience",
|
| 81 |
+
"nist_measure": "MEASURE 2.4", "nist_text": "Evaluating for resilience",
|
| 82 |
+
"credo_dimension": "Security (resilience)",
|
| 83 |
+
"mechanism": "Resilience axis from szl_resilience degradation/fallback telemetry", "coverage": "PARTIAL"},
|
| 84 |
+
{"axis": 5, "lambda_axis": "safety / harm avoidance",
|
| 85 |
+
"nist_measure": "MEASURE 2.5", "nist_text": "Evaluating for safety",
|
| 86 |
+
"credo_dimension": "Harmful Content Generation",
|
| 87 |
+
"mechanism": "Output content-safety classifier feeds the safety axis; gate halts on DENY", "coverage": "COVERED"},
|
| 88 |
+
{"axis": 6, "lambda_axis": "fairness / demographic parity",
|
| 89 |
+
"nist_measure": "MEASURE 2.6", "nist_text": "Evaluating for fairness / bias",
|
| 90 |
+
"credo_dimension": "Fairness and Bias",
|
| 91 |
+
"mechanism": "Statistical bias detection on outputs feeds the fairness axis", "coverage": "PARTIAL"},
|
| 92 |
+
{"axis": 7, "lambda_axis": "privacy / data minimization",
|
| 93 |
+
"nist_measure": "MEASURE 2.7", "nist_text": "Evaluating for privacy",
|
| 94 |
+
"credo_dimension": "Privacy",
|
| 95 |
+
"mechanism": "PII detection on inputs/outputs feeds the privacy axis", "coverage": "PARTIAL"},
|
| 96 |
+
{"axis": 8, "lambda_axis": "transparency / explainability",
|
| 97 |
+
"nist_measure": "MEASURE 2.8", "nist_text": "Evaluating for transparency / explainability",
|
| 98 |
+
"credo_dimension": "Information Integrity (transparency)",
|
| 99 |
+
"mechanism": "Lean-proven formula output exposed in the DSSE receipt for every decision", "coverage": "COVERED"},
|
| 100 |
+
{"axis": 9, "lambda_axis": "security posture score",
|
| 101 |
+
"nist_measure": "MEASURE 2.9", "nist_text": "Evaluating for security",
|
| 102 |
+
"credo_dimension": "Security",
|
| 103 |
+
"mechanism": "SLSA build posture + signed deployment digest + sentinel rules score", "coverage": "PARTIAL"},
|
| 104 |
+
{"axis": 10, "lambda_axis": "societal impact / mission alignment",
|
| 105 |
+
"nist_measure": "MEASURE 2.10", "nist_text": "Evaluating impacts / risks across the lifecycle",
|
| 106 |
+
"credo_dimension": "Societal Harm",
|
| 107 |
+
"mechanism": "Authorization-boundary + human-override gate firing rate feeds the impact axis", "coverage": "PARTIAL"},
|
| 108 |
+
{"axis": 11, "lambda_axis": "autonomy scope / action class",
|
| 109 |
+
"nist_measure": "MAP 2.1", "nist_text": "AI system categorization — type, capabilities, scope",
|
| 110 |
+
"credo_dimension": "AI Agency and Autonomy",
|
| 111 |
+
"mechanism": "Action-class gate thresholds bound autonomous actions; irreversible → human override", "coverage": "COVERED"},
|
| 112 |
+
{"axis": 12, "lambda_axis": "third-party / vendor risk",
|
| 113 |
+
"nist_measure": "GOVERN 6.1", "nist_text": "Policies for third-party / supply-chain AI risk",
|
| 114 |
+
"credo_dimension": "Third-Party and Vendor Risk",
|
| 115 |
+
"mechanism": "Third-party model attestation + vendor DSSE receipt verification", "coverage": "PARTIAL"},
|
| 116 |
+
{"axis": 13, "lambda_axis": "malicious-use / intent classification",
|
| 117 |
+
"nist_measure": "MEASURE 2.5", "nist_text": "Evaluating for safety (misuse intent)",
|
| 118 |
+
"credo_dimension": "Malicious Use",
|
| 119 |
+
"mechanism": "Use-case intent classifier + policy gate; DENY on prohibited use class", "coverage": "PARTIAL"},
|
| 120 |
+
]
|
| 121 |
+
|
| 122 |
+
# ───────────────────────────────────────────────────────────────────────────
|
| 123 |
+
# Honest in-product COVERAGE MATRIX — ISO 42001 / NIST AI RMF / NIST 800-53 / EU AI Act.
|
| 124 |
+
# Each row: control id, framework, the concrete a11oy mechanism, and an HONEST state.
|
| 125 |
+
# (UPGRADE #3 of GRC_ONETRUST_RESEARCH.) States: COVERED / PARTIAL / ROADMAP / NA.
|
| 126 |
+
# ───────────────────────────────────────────────────────────────────────────
|
| 127 |
+
COVERAGE_MATRIX: List[Dict[str, str]] = [
|
| 128 |
+
# ISO 42001
|
| 129 |
+
{"control": "A.2.2", "framework": "ISO 42001", "title": "AI policy",
|
| 130 |
+
"mechanism": "Doctrine v11 is the published AI policy; versioned + change-controlled", "coverage": "COVERED"},
|
| 131 |
+
{"control": "A.3.2", "framework": "ISO 42001", "title": "AI roles & responsibilities",
|
| 132 |
+
"mechanism": "Operator role + clearance captured in every DSSE receipt (AC-2/AC-3)", "coverage": "COVERED"},
|
| 133 |
+
{"control": "A.3.3", "framework": "ISO 42001", "title": "AI risk reporting",
|
| 134 |
+
"mechanism": "Λ score reported per-inference; no formal periodic risk REPORT output yet", "coverage": "PARTIAL"},
|
| 135 |
+
{"control": "A.4.6", "framework": "ISO 42001", "title": "Human oversight & monitoring",
|
| 136 |
+
"mechanism": "human_override_required Rego gate fires before irreversible actions / low Λ", "coverage": "COVERED"},
|
| 137 |
+
{"control": "A.5.4", "framework": "ISO 42001", "title": "AI system risk management",
|
| 138 |
+
"mechanism": "13-axis Λ score computed per inference; sealed into the DSSE receipt", "coverage": "COVERED"},
|
| 139 |
+
{"control": "A.6.4", "framework": "ISO 42001", "title": "Data provenance",
|
| 140 |
+
"mechanism": "Input hash + model version + lineage recorded in the receipt", "coverage": "COVERED"},
|
| 141 |
+
{"control": "A.6.6", "framework": "ISO 42001", "title": "AI system verification",
|
| 142 |
+
"mechanism": "Output hash + Lean-verified formula path; locked-proven = 8 @ c7c0ba17", "coverage": "PARTIAL"},
|
| 143 |
+
{"control": "A.9.3", "framework": "ISO 42001", "title": "Human oversight (use)",
|
| 144 |
+
"mechanism": "Human-override gate; irreversible actions require human confirmation", "coverage": "COVERED"},
|
| 145 |
+
{"control": "A.9.4", "framework": "ISO 42001", "title": "Incident management",
|
| 146 |
+
"mechanism": "Incident receipt + tamper-evident re-verification at /cosign.pub", "coverage": "PARTIAL"},
|
| 147 |
+
{"control": "A.10.4", "framework": "ISO 42001", "title": "Supplier monitoring",
|
| 148 |
+
"mechanism": "Third-party model attestation; vendor DSSE receipt verification", "coverage": "PARTIAL"},
|
| 149 |
+
# NIST AI RMF
|
| 150 |
+
{"control": "GOVERN 1.1", "framework": "NIST AI RMF", "title": "AI policies & processes",
|
| 151 |
+
"mechanism": "Doctrine v11 + policy-gate configuration inventory", "coverage": "COVERED"},
|
| 152 |
+
{"control": "MAP 2.3", "framework": "NIST AI RMF", "title": "AI capability characterization",
|
| 153 |
+
"mechanism": "Λ scoring methodology + model registry classification", "coverage": "COVERED"},
|
| 154 |
+
{"control": "MEASURE 2.8", "framework": "NIST AI RMF", "title": "Transparency / explainability",
|
| 155 |
+
"mechanism": "Lean-proven formula output exposed in the receipt", "coverage": "COVERED"},
|
| 156 |
+
{"control": "MEASURE 3.1", "framework": "NIST AI RMF", "title": "Risk tracking over time",
|
| 157 |
+
"mechanism": "Continuous Λ score with a timestamp chain of receipts", "coverage": "PARTIAL"},
|
| 158 |
+
{"control": "GOVERN 3.2", "framework": "NIST AI RMF", "title": "Workforce DEI",
|
| 159 |
+
"mechanism": "Out of scope for an orchestration layer (organizational control)", "coverage": "NA"},
|
| 160 |
+
{"control": "MANAGE 4.1", "framework": "NIST AI RMF", "title": "Post-incident after-action",
|
| 161 |
+
"mechanism": "Incident receipt replay + independent re-verification", "coverage": "PARTIAL"},
|
| 162 |
+
{"control": "MEASURE 4.2", "framework": "NIST AI RMF", "title": "Measurement-effectiveness feedback",
|
| 163 |
+
"mechanism": "Λ-score calibration feedback loop", "coverage": "ROADMAP"},
|
| 164 |
+
# NIST 800-53 Rev 5
|
| 165 |
+
{"control": "AU-2", "framework": "NIST 800-53r5", "title": "Event logging",
|
| 166 |
+
"mechanism": "DSSE-signed audit event per inference (verdict + rule ID)", "coverage": "COVERED"},
|
| 167 |
+
{"control": "AU-3", "framework": "NIST 800-53r5", "title": "Content of audit records",
|
| 168 |
+
"mechanism": "Timestamp + input/output hash in every receipt", "coverage": "COVERED"},
|
| 169 |
+
{"control": "AU-9", "framework": "NIST 800-53r5", "title": "Protection of audit information",
|
| 170 |
+
"mechanism": "Records sealed in DSSE envelopes signed by ECDSA-P256; tamper-detectable", "coverage": "COVERED"},
|
| 171 |
+
{"control": "CM-8", "framework": "NIST 800-53r5", "title": "System component inventory",
|
| 172 |
+
"mechanism": "Model ID + version + digest recorded per inference", "coverage": "COVERED"},
|
| 173 |
+
{"control": "RA-3", "framework": "NIST 800-53r5", "title": "Risk assessment",
|
| 174 |
+
"mechanism": "13-axis Λ trust score is the per-inference risk assessment", "coverage": "COVERED"},
|
| 175 |
+
{"control": "SI-10", "framework": "NIST 800-53r5", "title": "Information input validation",
|
| 176 |
+
"mechanism": "Input hash + classification-boundary gate", "coverage": "PARTIAL"},
|
| 177 |
+
# EU AI Act
|
| 178 |
+
{"control": "Article 12", "framework": "EU AI Act", "title": "Record-keeping / logging",
|
| 179 |
+
"mechanism": "Immutable DSSE receipt per inference satisfies automatic logging", "coverage": "COVERED"},
|
| 180 |
+
{"control": "Article 14", "framework": "EU AI Act", "title": "Human oversight",
|
| 181 |
+
"mechanism": "Human-in-the-loop override gate; human-on-loop for SIMULATED effectors", "coverage": "COVERED"},
|
| 182 |
+
{"control": "Article 9", "framework": "EU AI Act", "title": "Risk management system (High-Risk)",
|
| 183 |
+
"mechanism": "Λ-gated policy enforcement; no formal QMS document yet", "coverage": "ROADMAP"},
|
| 184 |
+
]
|
| 185 |
+
|
| 186 |
+
# ───────────────────────────────────────────────────────────────────────────
|
| 187 |
+
# Policy gates expressed as OPA / Rego (UPGRADE #2). Each gate carries the controls
|
| 188 |
+
# it satisfies; the bundle is version-locked by a SHA-256 digest that every DSSE receipt
|
| 189 |
+
# cites — so a receipt proves WHICH policy version made the decision.
|
| 190 |
+
# ──────────────────────────────��────────────────────────────────────────────
|
| 191 |
+
REGO_GATES: List[Dict[str, Any]] = [
|
| 192 |
+
{
|
| 193 |
+
"name": "classification_boundary",
|
| 194 |
+
"package": "a11oy.gates.classification_boundary",
|
| 195 |
+
"controls": ["ISO42001/A.9.6", "NIST80053/AC-3", "EUAIAct/Art.14"],
|
| 196 |
+
"rego": (
|
| 197 |
+
"package a11oy.gates.classification_boundary\n\n"
|
| 198 |
+
"# DENY when output classification exceeds the operator's clearance level.\n"
|
| 199 |
+
"default allow := false\n\n"
|
| 200 |
+
"deny[msg] {\n"
|
| 201 |
+
" input.output_classification > input.user_clearance_level\n"
|
| 202 |
+
" msg := sprintf(\"output classification %v exceeds user clearance %v\",\n"
|
| 203 |
+
" [input.output_classification, input.user_clearance_level])\n"
|
| 204 |
+
"}\n\n"
|
| 205 |
+
"allow {\n count(deny) == 0\n}\n"
|
| 206 |
+
),
|
| 207 |
+
},
|
| 208 |
+
{
|
| 209 |
+
"name": "human_override_required",
|
| 210 |
+
"package": "a11oy.gates.human_override_required",
|
| 211 |
+
"controls": ["ISO42001/A.9.3", "ISO42001/A.4.6", "NIST80053/AU-2", "EUAIAct/Art.14"],
|
| 212 |
+
"rego": (
|
| 213 |
+
"package a11oy.gates.human_override_required\n\n"
|
| 214 |
+
"# Require a human override for irreversible actions or when Λ < threshold.\n"
|
| 215 |
+
"default require_human := false\n\n"
|
| 216 |
+
"require_human {\n input.action_class == \"irreversible\"\n}\n\n"
|
| 217 |
+
"require_human {\n input.lambda_score < input.lambda_halt_threshold\n}\n"
|
| 218 |
+
),
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
"name": "deployment_readiness",
|
| 222 |
+
"package": "a11oy.gates.deployment_readiness",
|
| 223 |
+
"controls": ["ISO27001/8.25", "NIST80053/CM-3", "ISO42001/A.6.7"],
|
| 224 |
+
"rego": (
|
| 225 |
+
"package a11oy.gates.deployment_readiness\n\n"
|
| 226 |
+
"# Block model promotion unless the signed package digest + Λ floor are met.\n"
|
| 227 |
+
"default promote := false\n\n"
|
| 228 |
+
"promote {\n"
|
| 229 |
+
" input.package_signed == true\n"
|
| 230 |
+
" input.slsa_level >= 2\n"
|
| 231 |
+
" input.lambda_score >= input.lambda_promote_floor\n"
|
| 232 |
+
"}\n"
|
| 233 |
+
),
|
| 234 |
+
},
|
| 235 |
+
]
|
| 236 |
+
|
| 237 |
+
|
| 238 |
+
def policy_bundle_digest() -> str:
|
| 239 |
+
"""Deterministic SHA-256 over the canonical Rego bundle — the version-lock that every
|
| 240 |
+
DSSE receipt cites (UPGRADE #2/#4). Stable across calls for a given bundle content."""
|
| 241 |
+
canon = json.dumps([{ "name": g["name"], "package": g["package"], "rego": g["rego"]}
|
| 242 |
+
for g in REGO_GATES], sort_keys=True).encode()
|
| 243 |
+
return "sha256:" + hashlib.sha256(canon).hexdigest()
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
# ───────────────────────────────────────────────────────────────────────────
|
| 247 |
+
# DSSE Receipt Schema v2 — each field cites the control(s) it provides evidence for
|
| 248 |
+
# (UPGRADE #4). This is a SCHEMA (field→control map), not a fabricated receipt.
|
| 249 |
+
# ───────────────────────────────────────────────────────────────────────────
|
| 250 |
+
DSSE_RECEIPT_SCHEMA_V2: List[Dict[str, Any]] = [
|
| 251 |
+
{"field": "inference_timestamp_utc", "controls": ["NIST80053/AU-3", "EUAIAct/Art.12", "ISO42001/A.6.5"]},
|
| 252 |
+
{"field": "model_id_version_digest", "controls": ["NIST80053/CM-8", "NIST80053/CM-2", "EUAIAct/Art.12", "ISO42001/A.6.6"]},
|
| 253 |
+
{"field": "policy_bundle_digest", "controls": ["NIST80053/CM-3", "EUAIAct/Art.9", "ISO42001/A.9.2"]},
|
| 254 |
+
{"field": "input_hash_sha256", "controls": ["NIST80053/AU-3", "NIST80053/SI-10", "EUAIAct/Art.12", "ISO42001/A.7.2"]},
|
| 255 |
+
{"field": "output_hash_sha256", "controls": ["NIST80053/AU-3", "NIST80053/SI-7", "EUAIAct/Art.12", "ISO42001/A.6.6"]},
|
| 256 |
+
{"field": "policy_gate_verdict_and_rule_id", "controls": ["NIST80053/AU-2", "EUAIAct/Art.9", "EUAIAct/Art.14", "ISO42001/A.9.3"]},
|
| 257 |
+
{"field": "lambda_score_13axis", "controls": ["NIST80053/RA-3", "EUAIAct/Art.9", "ISO42001/A.5.4"]},
|
| 258 |
+
{"field": "operator_role_clearance", "controls": ["NIST80053/AC-2", "NIST80053/AC-3", "EUAIAct/Art.14", "ISO42001/A.3.2"]},
|
| 259 |
+
{"field": "ecdsa_p256_signature", "controls": ["NIST80053/AU-9", "ISO42001/A.4.2"]},
|
| 260 |
+
{"field": "reverification_endpoint", "controls": ["NIST80053/AU-6", "EUAIAct/Art.12", "ISO42001/A.8.2"]},
|
| 261 |
+
]
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
def coverage_summary() -> Dict[str, int]:
|
| 265 |
+
out: Dict[str, int] = {}
|
| 266 |
+
for r in COVERAGE_MATRIX:
|
| 267 |
+
out[r["coverage"]] = out.get(r["coverage"], 0) + 1
|
| 268 |
+
return out
|
| 269 |
+
|
| 270 |
+
|
| 271 |
+
def build_matrix() -> Dict[str, Any]:
|
| 272 |
+
return {
|
| 273 |
+
"doctrine": DOCTRINE_VERSION,
|
| 274 |
+
"kernel_commit": KERNEL_COMMIT,
|
| 275 |
+
"matrix": COVERAGE_MATRIX,
|
| 276 |
+
"summary": coverage_summary(),
|
| 277 |
+
"frameworks": sorted({r["framework"] for r in COVERAGE_MATRIX}),
|
| 278 |
+
"eu_ai_act_self_classification": "High-Risk (defense-tech agentic orchestrator)",
|
| 279 |
+
"honest": HONEST_DISCLAIMER,
|
| 280 |
+
"framing": "aligns with / maps to — NOT certified / compliant",
|
| 281 |
+
"status": "ALIGNMENT (no third-party certification)",
|
| 282 |
+
"sources": SOURCES,
|
| 283 |
+
}
|
| 284 |
+
|
| 285 |
+
|
| 286 |
+
def build_mapping() -> Dict[str, Any]:
|
| 287 |
+
return {
|
| 288 |
+
"doctrine": DOCTRINE_VERSION,
|
| 289 |
+
"lambda_axes": LAMBDA_AXES,
|
| 290 |
+
"axis_count": len(LAMBDA_AXES),
|
| 291 |
+
"primary_target": "NIST AI RMF MEASURE 2 (10 subcategories) + GOVERN/MAP for governance axes",
|
| 292 |
+
"taxonomy_alignment": "Credo AI 10-dimension (derives from MIT AI Risk Repository)",
|
| 293 |
+
"dsse_receipt_schema_v2": DSSE_RECEIPT_SCHEMA_V2,
|
| 294 |
+
"policy_bundle_digest": policy_bundle_digest(),
|
| 295 |
+
"rego_gates": [{"name": g["name"], "package": g["package"], "controls": g["controls"], "rego": g["rego"]}
|
| 296 |
+
for g in REGO_GATES],
|
| 297 |
+
"honest": HONEST_DISCLAIMER,
|
| 298 |
+
"status": "ALIGNMENT",
|
| 299 |
+
"sources": SOURCES,
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
|
| 303 |
+
def build_oscal() -> Dict[str, Any]:
|
| 304 |
+
"""OSCAL Component Definition (UPGRADE #7) derived from the SAME coverage matrix +
|
| 305 |
+
Rego gates, so the published artifact and the live matrix can never diverge. Control
|
| 306 |
+
source = usnistgov/oscal-content SP 800-53 Rev 5 catalog. Honest: alignment, not cert."""
|
| 307 |
+
import datetime
|
| 308 |
+
src = SOURCES["NIST SP 800-53 Rev 5 catalog (OSCAL JSON)"]
|
| 309 |
+
# implemented-requirements from the 800-53 rows of the coverage matrix
|
| 310 |
+
impl: List[Dict[str, Any]] = []
|
| 311 |
+
for r in COVERAGE_MATRIX:
|
| 312 |
+
if r["framework"] != "NIST 800-53r5":
|
| 313 |
+
continue
|
| 314 |
+
impl.append({
|
| 315 |
+
"uuid": "ir-" + hashlib.sha256(r["control"].encode()).hexdigest()[:8],
|
| 316 |
+
"control-id": r["control"].lower().replace(" ", "-"),
|
| 317 |
+
"description": f"[{r['coverage']}] {r['mechanism']} (a11oy {r['title']}).",
|
| 318 |
+
"props": [{"name": "coverage", "ns": "https://szlholdings.ai/ns/oscal", "value": r["coverage"]}],
|
| 319 |
+
})
|
| 320 |
+
rego_statements = [{
|
| 321 |
+
"uuid": "ir-rego-" + hashlib.sha256(g["name"].encode()).hexdigest()[:8],
|
| 322 |
+
"control-id": "ac-3",
|
| 323 |
+
"description": f"Rego gate {g['package']} (controls: {', '.join(g['controls'])}). "
|
| 324 |
+
f"Bundle digest {policy_bundle_digest()} is cited in every DSSE receipt.",
|
| 325 |
+
} for g in REGO_GATES]
|
| 326 |
+
return {
|
| 327 |
+
"component-definition": {
|
| 328 |
+
"uuid": "a11oy-comp-def-" + DOCTRINE_VERSION,
|
| 329 |
+
"metadata": {
|
| 330 |
+
"title": "a11oy Governed AI Orchestrator — OSCAL Component Definition",
|
| 331 |
+
"last-modified": datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
| 332 |
+
"version": DOCTRINE_VERSION,
|
| 333 |
+
"oscal-version": "1.1.2",
|
| 334 |
+
"remarks": HONEST_DISCLAIMER,
|
| 335 |
+
},
|
| 336 |
+
"components": [{
|
| 337 |
+
"uuid": "a11oy-orchestrator",
|
| 338 |
+
"type": "software",
|
| 339 |
+
"title": "a11oy Governed AI Orchestrator",
|
| 340 |
+
"description": "Governed agentic-AI orchestration layer emitting a DSSE-signed "
|
| 341 |
+
"receipt per inference. ALIGNS WITH the controls below; not certified.",
|
| 342 |
+
"props": [
|
| 343 |
+
{"name": "doctrine", "ns": "https://szlholdings.ai/ns/oscal", "value": DOCTRINE_VERSION},
|
| 344 |
+
{"name": "kernel-commit", "ns": "https://szlholdings.ai/ns/oscal", "value": KERNEL_COMMIT},
|
| 345 |
+
{"name": "policy-bundle-digest", "ns": "https://szlholdings.ai/ns/oscal", "value": policy_bundle_digest()},
|
| 346 |
+
{"name": "eu-ai-act-class", "ns": "https://szlholdings.ai/ns/oscal", "value": "High-Risk (self-classified)"},
|
| 347 |
+
],
|
| 348 |
+
"control-implementations": [{
|
| 349 |
+
"uuid": "ci-800-53r5",
|
| 350 |
+
"source": src,
|
| 351 |
+
"description": "a11oy mechanism mapping to NIST SP 800-53 Rev 5 (alignment only).",
|
| 352 |
+
"implemented-requirements": impl + rego_statements,
|
| 353 |
+
}],
|
| 354 |
+
}],
|
| 355 |
+
}
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
|
| 359 |
+
def _selftest() -> None:
|
| 360 |
+
assert len(LAMBDA_AXES) == 13, "must be 13 Λ axes"
|
| 361 |
+
# axes 1-10 must map to MEASURE 2.1..2.10
|
| 362 |
+
m2 = [a for a in LAMBDA_AXES if a["nist_measure"].startswith("MEASURE 2.")]
|
| 363 |
+
assert len(m2) >= 10
|
| 364 |
+
assert all(v in ("COVERED", "PARTIAL", "ROADMAP", "NA") for v in (r["coverage"] for r in COVERAGE_MATRIX))
|
| 365 |
+
s = coverage_summary()
|
| 366 |
+
assert sum(s.values()) == len(COVERAGE_MATRIX)
|
| 367 |
+
d1 = policy_bundle_digest(); d2 = policy_bundle_digest()
|
| 368 |
+
assert d1 == d2 and d1.startswith("sha256:")
|
| 369 |
+
oscal = build_oscal()
|
| 370 |
+
cd = oscal["component-definition"]
|
| 371 |
+
assert cd["components"][0]["control-implementations"][0]["implemented-requirements"], "no impl reqs"
|
| 372 |
+
assert "certified" not in HONEST_DISCLAIMER.lower() or "not" in HONEST_DISCLAIMER.lower()
|
| 373 |
+
# OSCAL must be valid JSON-serialisable
|
| 374 |
+
json.dumps(oscal)
|
| 375 |
+
mp = build_mapping(); mx = build_matrix()
|
| 376 |
+
assert mp["axis_count"] == 13 and mx["summary"]
|
| 377 |
+
print("a11oy_grc_data: ALL OK (%d matrix rows, 13 axes, %d gates, %d schema fields)"
|
| 378 |
+
% (len(COVERAGE_MATRIX), len(REGO_GATES), len(DSSE_RECEIPT_SCHEMA_V2)))
|
| 379 |
+
|
| 380 |
+
|
| 381 |
+
if __name__ == "__main__":
|
| 382 |
+
_selftest()
|
compliance/oscal/a11oy-component-definition.json
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"component-definition": {
|
| 3 |
+
"uuid": "a11oy-comp-def-v11",
|
| 4 |
+
"metadata": {
|
| 5 |
+
"title": "a11oy Governed AI Orchestrator \u2014 OSCAL Component Definition",
|
| 6 |
+
"last-modified": "2026-06-14T06:40:15.254257+00:00",
|
| 7 |
+
"version": "v11",
|
| 8 |
+
"oscal-version": "1.1.2",
|
| 9 |
+
"remarks": "Coverage assessments reflect a11oy's INTERNAL analysis of its mechanisms against published framework control text. a11oy ALIGNS WITH / MAPS TO these frameworks; it does NOT claim certification. No third-party certification has been obtained for any framework as of Doctrine v11. Gaps are shown honestly. \u039b = Conjecture 1; locked-proven = 8 @ c7c0ba17; trust never 100%."
|
| 10 |
+
},
|
| 11 |
+
"components": [
|
| 12 |
+
{
|
| 13 |
+
"uuid": "a11oy-orchestrator",
|
| 14 |
+
"type": "software",
|
| 15 |
+
"title": "a11oy Governed AI Orchestrator",
|
| 16 |
+
"description": "Governed agentic-AI orchestration layer emitting a DSSE-signed receipt per inference. ALIGNS WITH the controls below; not certified.",
|
| 17 |
+
"props": [
|
| 18 |
+
{
|
| 19 |
+
"name": "doctrine",
|
| 20 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 21 |
+
"value": "v11"
|
| 22 |
+
},
|
| 23 |
+
{
|
| 24 |
+
"name": "kernel-commit",
|
| 25 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 26 |
+
"value": "c7c0ba17"
|
| 27 |
+
},
|
| 28 |
+
{
|
| 29 |
+
"name": "policy-bundle-digest",
|
| 30 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 31 |
+
"value": "sha256:4b035da9e752dcdb81c8390974752fc729da8192e60a0459de50a05d4c9563ba"
|
| 32 |
+
},
|
| 33 |
+
{
|
| 34 |
+
"name": "eu-ai-act-class",
|
| 35 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 36 |
+
"value": "High-Risk (self-classified)"
|
| 37 |
+
}
|
| 38 |
+
],
|
| 39 |
+
"control-implementations": [
|
| 40 |
+
{
|
| 41 |
+
"uuid": "ci-800-53r5",
|
| 42 |
+
"source": "https://raw.githubusercontent.com/usnistgov/oscal-content/main/nist.gov/SP800-53/rev5/json/NIST_SP-800-53_rev5_catalog.json",
|
| 43 |
+
"description": "a11oy mechanism mapping to NIST SP 800-53 Rev 5 (alignment only).",
|
| 44 |
+
"implemented-requirements": [
|
| 45 |
+
{
|
| 46 |
+
"uuid": "ir-95efdfab",
|
| 47 |
+
"control-id": "au-2",
|
| 48 |
+
"description": "[COVERED] DSSE-signed audit event per inference (verdict + rule ID) (a11oy Event logging).",
|
| 49 |
+
"props": [
|
| 50 |
+
{
|
| 51 |
+
"name": "coverage",
|
| 52 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 53 |
+
"value": "COVERED"
|
| 54 |
+
}
|
| 55 |
+
]
|
| 56 |
+
},
|
| 57 |
+
{
|
| 58 |
+
"uuid": "ir-941c0684",
|
| 59 |
+
"control-id": "au-3",
|
| 60 |
+
"description": "[COVERED] Timestamp + input/output hash in every receipt (a11oy Content of audit records).",
|
| 61 |
+
"props": [
|
| 62 |
+
{
|
| 63 |
+
"name": "coverage",
|
| 64 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 65 |
+
"value": "COVERED"
|
| 66 |
+
}
|
| 67 |
+
]
|
| 68 |
+
},
|
| 69 |
+
{
|
| 70 |
+
"uuid": "ir-a0f3ffcd",
|
| 71 |
+
"control-id": "au-9",
|
| 72 |
+
"description": "[COVERED] Records sealed in DSSE envelopes signed by ECDSA-P256; tamper-detectable (a11oy Protection of audit information).",
|
| 73 |
+
"props": [
|
| 74 |
+
{
|
| 75 |
+
"name": "coverage",
|
| 76 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 77 |
+
"value": "COVERED"
|
| 78 |
+
}
|
| 79 |
+
]
|
| 80 |
+
},
|
| 81 |
+
{
|
| 82 |
+
"uuid": "ir-80c2667f",
|
| 83 |
+
"control-id": "cm-8",
|
| 84 |
+
"description": "[COVERED] Model ID + version + digest recorded per inference (a11oy System component inventory).",
|
| 85 |
+
"props": [
|
| 86 |
+
{
|
| 87 |
+
"name": "coverage",
|
| 88 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 89 |
+
"value": "COVERED"
|
| 90 |
+
}
|
| 91 |
+
]
|
| 92 |
+
},
|
| 93 |
+
{
|
| 94 |
+
"uuid": "ir-76491072",
|
| 95 |
+
"control-id": "ra-3",
|
| 96 |
+
"description": "[COVERED] 13-axis \u039b trust score is the per-inference risk assessment (a11oy Risk assessment).",
|
| 97 |
+
"props": [
|
| 98 |
+
{
|
| 99 |
+
"name": "coverage",
|
| 100 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 101 |
+
"value": "COVERED"
|
| 102 |
+
}
|
| 103 |
+
]
|
| 104 |
+
},
|
| 105 |
+
{
|
| 106 |
+
"uuid": "ir-74879421",
|
| 107 |
+
"control-id": "si-10",
|
| 108 |
+
"description": "[PARTIAL] Input hash + classification-boundary gate (a11oy Information input validation).",
|
| 109 |
+
"props": [
|
| 110 |
+
{
|
| 111 |
+
"name": "coverage",
|
| 112 |
+
"ns": "https://szlholdings.ai/ns/oscal",
|
| 113 |
+
"value": "PARTIAL"
|
| 114 |
+
}
|
| 115 |
+
]
|
| 116 |
+
},
|
| 117 |
+
{
|
| 118 |
+
"uuid": "ir-rego-b4e45455",
|
| 119 |
+
"control-id": "ac-3",
|
| 120 |
+
"description": "Rego gate a11oy.gates.classification_boundary (controls: ISO42001/A.9.6, NIST80053/AC-3, EUAIAct/Art.14). Bundle digest sha256:4b035da9e752dcdb81c8390974752fc729da8192e60a0459de50a05d4c9563ba is cited in every DSSE receipt."
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
"uuid": "ir-rego-0abacbce",
|
| 124 |
+
"control-id": "ac-3",
|
| 125 |
+
"description": "Rego gate a11oy.gates.human_override_required (controls: ISO42001/A.9.3, ISO42001/A.4.6, NIST80053/AU-2, EUAIAct/Art.14). Bundle digest sha256:4b035da9e752dcdb81c8390974752fc729da8192e60a0459de50a05d4c9563ba is cited in every DSSE receipt."
|
| 126 |
+
},
|
| 127 |
+
{
|
| 128 |
+
"uuid": "ir-rego-864d6ebc",
|
| 129 |
+
"control-id": "ac-3",
|
| 130 |
+
"description": "Rego gate a11oy.gates.deployment_readiness (controls: ISO27001/8.25, NIST80053/CM-3, ISO42001/A.6.7). Bundle digest sha256:4b035da9e752dcdb81c8390974752fc729da8192e60a0459de50a05d4c9563ba is cited in every DSSE receipt."
|
| 131 |
+
}
|
| 132 |
+
]
|
| 133 |
+
}
|
| 134 |
+
]
|
| 135 |
+
}
|
| 136 |
+
]
|
| 137 |
+
}
|
| 138 |
+
}
|
compliance/rego/classification_boundary.rego
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# a11oy policy gate: classification_boundary
|
| 2 |
+
# controls: ISO42001/A.9.6, NIST80053/AC-3, EUAIAct/Art.14
|
| 3 |
+
# bundle digest (whole bundle): sha256:4b035da9e752dcdb81c8390974752fc729da8192e60a0459de50a05d4c9563ba
|
| 4 |
+
|
| 5 |
+
package a11oy.gates.classification_boundary
|
| 6 |
+
|
| 7 |
+
# DENY when output classification exceeds the operator's clearance level.
|
| 8 |
+
default allow := false
|
| 9 |
+
|
| 10 |
+
deny[msg] {
|
| 11 |
+
input.output_classification > input.user_clearance_level
|
| 12 |
+
msg := sprintf("output classification %v exceeds user clearance %v",
|
| 13 |
+
[input.output_classification, input.user_clearance_level])
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
allow {
|
| 17 |
+
count(deny) == 0
|
| 18 |
+
}
|
compliance/rego/deployment_readiness.rego
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# a11oy policy gate: deployment_readiness
|
| 2 |
+
# controls: ISO27001/8.25, NIST80053/CM-3, ISO42001/A.6.7
|
| 3 |
+
# bundle digest (whole bundle): sha256:4b035da9e752dcdb81c8390974752fc729da8192e60a0459de50a05d4c9563ba
|
| 4 |
+
|
| 5 |
+
package a11oy.gates.deployment_readiness
|
| 6 |
+
|
| 7 |
+
# Block model promotion unless the signed package digest + Λ floor are met.
|
| 8 |
+
default promote := false
|
| 9 |
+
|
| 10 |
+
promote {
|
| 11 |
+
input.package_signed == true
|
| 12 |
+
input.slsa_level >= 2
|
| 13 |
+
input.lambda_score >= input.lambda_promote_floor
|
| 14 |
+
}
|
compliance/rego/human_override_required.rego
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# a11oy policy gate: human_override_required
|
| 2 |
+
# controls: ISO42001/A.9.3, ISO42001/A.4.6, NIST80053/AU-2, EUAIAct/Art.14
|
| 3 |
+
# bundle digest (whole bundle): sha256:4b035da9e752dcdb81c8390974752fc729da8192e60a0459de50a05d4c9563ba
|
| 4 |
+
|
| 5 |
+
package a11oy.gates.human_override_required
|
| 6 |
+
|
| 7 |
+
# Require a human override for irreversible actions or when Λ < threshold.
|
| 8 |
+
default require_human := false
|
| 9 |
+
|
| 10 |
+
require_human {
|
| 11 |
+
input.action_class == "irreversible"
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
require_human {
|
| 15 |
+
input.lambda_score < input.lambda_halt_threshold
|
| 16 |
+
}
|
compliance/rego/manifest.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"bundle": "a11oy-policy-gates",
|
| 3 |
+
"doctrine": "v11",
|
| 4 |
+
"digest": "sha256:4b035da9e752dcdb81c8390974752fc729da8192e60a0459de50a05d4c9563ba",
|
| 5 |
+
"gates": [
|
| 6 |
+
{
|
| 7 |
+
"name": "classification_boundary",
|
| 8 |
+
"package": "a11oy.gates.classification_boundary",
|
| 9 |
+
"controls": [
|
| 10 |
+
"ISO42001/A.9.6",
|
| 11 |
+
"NIST80053/AC-3",
|
| 12 |
+
"EUAIAct/Art.14"
|
| 13 |
+
]
|
| 14 |
+
},
|
| 15 |
+
{
|
| 16 |
+
"name": "human_override_required",
|
| 17 |
+
"package": "a11oy.gates.human_override_required",
|
| 18 |
+
"controls": [
|
| 19 |
+
"ISO42001/A.9.3",
|
| 20 |
+
"ISO42001/A.4.6",
|
| 21 |
+
"NIST80053/AU-2",
|
| 22 |
+
"EUAIAct/Art.14"
|
| 23 |
+
]
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
"name": "deployment_readiness",
|
| 27 |
+
"package": "a11oy.gates.deployment_readiness",
|
| 28 |
+
"controls": [
|
| 29 |
+
"ISO27001/8.25",
|
| 30 |
+
"NIST80053/CM-3",
|
| 31 |
+
"ISO42001/A.6.7"
|
| 32 |
+
]
|
| 33 |
+
}
|
| 34 |
+
],
|
| 35 |
+
"note": "Version-locked OPA/Rego bundle. Every DSSE receipt cites this digest. ALIGNMENT only."
|
| 36 |
+
}
|
serve.py
CHANGED
|
@@ -3500,6 +3500,34 @@ except Exception as _a11oy_af_e:
|
|
| 3500 |
_a11oy_af_tb.print_exc()
|
| 3501 |
# ── end ACTIVE-FLUX ROUTER CROSSOVER ──
|
| 3502 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3503 |
# ===========================================================================
|
| 3504 |
# ADDITIVE — Parity Gap Closure + Differentiators (Yachay / Parity Squad, 2026-06-04)
|
| 3505 |
# Co-Authored-By: Perplexity Computer Agent <agent@perplexity.ai>
|
|
|
|
| 3500 |
_a11oy_af_tb.print_exc()
|
| 3501 |
# ── end ACTIVE-FLUX ROUTER CROSSOVER ──
|
| 3502 |
|
| 3503 |
+
# ===========================================================================
|
| 3504 |
+
# GRC ALIGNMENT surface (Lane I5) — in-product ISO 42001 / NIST AI RMF / NIST
|
| 3505 |
+
# 800-53 Rev 5 / EU AI Act COVERAGE MATRIX (honest COVERED/PARTIAL/ROADMAP/NA per
|
| 3506 |
+
# control); the 13 Λ trust axes mapped to NIST AI RMF MEASURE 2 (+ Credo AI / MIT
|
| 3507 |
+
# taxonomy labels); policy gates published as OPA/Rego with a version-locked bundle
|
| 3508 |
+
# digest that every DSSE receipt cites; an OSCAL component-definition committed to the
|
| 3509 |
+
# repo (compliance/oscal/) + served live; and a DSSE Receipt Schema v2 whose every field
|
| 3510 |
+
# cites the control IDs it provides evidence for. Endpoints /api/a11oy/v1/grc/{matrix,
|
| 3511 |
+
# mapping,oscal,info} (dual-registered at /v1/grc/* for the HF proxy) + a self-contained
|
| 3512 |
+
# 0-CDN "Compliance / GRC" page at /grc (alias /compliance). A nav link is injected by
|
| 3513 |
+
# this module's OWN idempotent middleware (the console SPA source is NOT edited and other
|
| 3514 |
+
# devs' tabs are never clobbered). HONEST (Doctrine v11): a11oy ALIGNS WITH / MAPS TO these
|
| 3515 |
+
# frameworks — NEVER "certified" / "compliant"; no third-party certification obtained; gaps
|
| 3516 |
+
# shown honestly. Adds NOTHING to the locked-8; Λ = Conjecture 1; trust never 100%; 0 CDN.
|
| 3517 |
+
# Additive, try/except-guarded, BEFORE the SPA/proxy catch-all.
|
| 3518 |
+
# ===========================================================================
|
| 3519 |
+
try:
|
| 3520 |
+
import a11oy_grc as _a11oy_grc
|
| 3521 |
+
_a11oy_grc_status = _a11oy_grc.register(app, ns="a11oy")
|
| 3522 |
+
print(f"[a11oy] GRC alignment registered: {_a11oy_grc_status['count']} routes "
|
| 3523 |
+
f"({_a11oy_grc_status['data_label']}) \u2014 aligns with ISO 42001 / NIST AI RMF / "
|
| 3524 |
+
f"800-53 / EU AI Act (NOT certified)", file=sys.stderr)
|
| 3525 |
+
except Exception as _a11oy_grc_e:
|
| 3526 |
+
import traceback as _a11oy_grc_tb
|
| 3527 |
+
print(f"[a11oy] GRC alignment NOT registered: {_a11oy_grc_e!r}", file=sys.stderr)
|
| 3528 |
+
_a11oy_grc_tb.print_exc()
|
| 3529 |
+
# ── end GRC ALIGNMENT ──
|
| 3530 |
+
|
| 3531 |
# ===========================================================================
|
| 3532 |
# ADDITIVE — Parity Gap Closure + Differentiators (Yachay / Parity Squad, 2026-06-04)
|
| 3533 |
# Co-Authored-By: Perplexity Computer Agent <agent@perplexity.ai>
|
szl_cuas_formulas.py
CHANGED
|
@@ -51,6 +51,11 @@ SOURCES = {
|
|
| 51 |
"Li Yu (李彧) — PI-correction bandwidth in an active-flux observer (LinkedIn 2026)": "https://www.linkedin.com/pulse/how-should-bandwidth-pi-correction-loop-active-flux-observer-%E5%BD%A7-%E6%9D%8E-qxksc",
|
| 52 |
"Revised Hybrid Active-Flux encoderless PMSM control (IEEE)": "https://ieeexplore.ieee.org/document/9319155",
|
| 53 |
"TI InstaSPIN-FOC / FAST flux observer (SPRUHJ1)": "https://www.ti.com/lit/ug/spruhj1h/spruhj1h.pdf",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
}
|
| 55 |
|
| 56 |
|
|
@@ -370,6 +375,196 @@ def szl_active_flux_observer(psi_f: float = 0.09, Ld: float = 0.0085, Lq: float
|
|
| 370 |
}
|
| 371 |
|
| 372 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 373 |
def summary(ns: str = "killinchu") -> dict[str, Any]:
|
| 374 |
"""Headline of all six SZL counter-UAS formulas + honest provenance/legend.
|
| 375 |
`ns` names the serving app so the title is accurate on both killinchu and a11oy."""
|
|
@@ -386,6 +581,8 @@ def summary(ns: str = "killinchu") -> dict[str, Any]:
|
|
| 386 |
"wta": "SZL-WTA Threat Triage (weapon-target assignment, SIMULATED)",
|
| 387 |
"pqbus": "SZL-PQ Receipt Bus (post-quantum receipt chain)",
|
| 388 |
"active_flux": "SZL Active-Flux Hybrid Observer (sensorless PMSM; ADOPTED Li Yu/APEC 2001, MODELED)",
|
|
|
|
|
|
|
| 389 |
},
|
| 390 |
"examples": {
|
| 391 |
"engage": szl_engageability(N=3.5, Vc=300.0, los_rate=0.02, t_go=4.0, a_max=200.0),
|
|
@@ -441,6 +638,28 @@ def register(app, ns: str) -> None:
|
|
| 441 |
"points": n, "curve": curve, "li_yu_reference": LI_YU_REFERENCE_BODE,
|
| 442 |
"data_label": "MODELED/SIMULATED — no live motor", "status": "MODELED"}
|
| 443 |
app.add_api_route(f"{base}/active-flux/bode", _active_flux_bode, methods=["GET"])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 444 |
|
| 445 |
|
| 446 |
def _selftest() -> None:
|
|
@@ -484,7 +703,31 @@ def _selftest() -> None:
|
|
| 484 |
obs = szl_active_flux_observer()
|
| 485 |
assert obs["status"] == "MODELED" and obs["effector"] == "SIMULATED"
|
| 486 |
assert "MODELED/SIMULATED" in obs["data_label"]
|
| 487 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
|
| 489 |
|
| 490 |
if __name__ == "__main__":
|
|
|
|
| 51 |
"Li Yu (李彧) — PI-correction bandwidth in an active-flux observer (LinkedIn 2026)": "https://www.linkedin.com/pulse/how-should-bandwidth-pi-correction-loop-active-flux-observer-%E5%BD%A7-%E6%9D%8E-qxksc",
|
| 52 |
"Revised Hybrid Active-Flux encoderless PMSM control (IEEE)": "https://ieeexplore.ieee.org/document/9319155",
|
| 53 |
"TI InstaSPIN-FOC / FAST flux observer (SPRUHJ1)": "https://www.ti.com/lit/ug/spruhj1h/spruhj1h.pdf",
|
| 54 |
+
# Platform dynamics (F-θ) — 6DOF quadcopter MBD + Moore-Penrose control allocation.
|
| 55 |
+
"Ahmed Hassan — Quadcopter Modeling/Control/Simulation (Simulink 6DOF, Aerospace Blockset; LinkedIn 2026)": "https://www.linkedin.com/posts/ahmedhassan2002_aerospaceengineering-aerospace-uav-activity-7348481891039129600-TbmA",
|
| 56 |
+
"Moore-Penrose pseudo-inverse control allocation (overview)": "https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse",
|
| 57 |
+
"Control allocation survey (Johansen & Fossen, Automatica 2013)": "https://doi.org/10.1016/j.automatica.2013.01.035",
|
| 58 |
+
"Model-Based Design / V-cycle, MIL/SIL/HIL (MathWorks)": "https://www.mathworks.com/solutions/model-based-design.html",
|
| 59 |
}
|
| 60 |
|
| 61 |
|
|
|
|
| 375 |
}
|
| 376 |
|
| 377 |
|
| 378 |
+
# ---------------------------------------------------------------------------
|
| 379 |
+
# F-θ SZL Platform Dynamics — 6DOF quadcopter/interceptor model + Moore-Penrose
|
| 380 |
+
# pseudo-inverse CONTROL ALLOCATION (thrust distribution). MODELED/SIMULATED.
|
| 381 |
+
#
|
| 382 |
+
# ADOPTED-AND-GENERALIZED, NOT invented here. Ahmed Hassan's Simulink Quadcopter MBD
|
| 383 |
+
# project (full 6DOF model in Aerospace Blockset; control ALLOCATION via the
|
| 384 |
+
# Moore-Penrose pseudo-inverse for optimal thrust distribution; MIL/SIL via Embedded
|
| 385 |
+
# Coder) is the on-domain technique we fold in: it rounds out the killinchu drone-
|
| 386 |
+
# platform puzzle — estimate (active-flux, F-η) → 6DOF dynamics + control allocation
|
| 387 |
+
# (this) → CBF-QP safety clamp (autonomy) → BFT multi-sensor fusion → governed/ROE
|
| 388 |
+
# engage (SIMULATED human-on-loop). Pure stdlib (no numpy): the 4-rotor mixing matrix
|
| 389 |
+
# is small and fixed, so we compute the pseudo-inverse in closed form.
|
| 390 |
+
#
|
| 391 |
+
# HONEST: there is NO live airframe on the demo floor. Every angular rate, attitude,
|
| 392 |
+
# rotor thrust here is a MODELED model output, NOT live telemetry. The effector stays
|
| 393 |
+
# SIMULATED human-on-loop — this computes a thrust allocation + a one-step state
|
| 394 |
+
# derivative, it NEVER actuates a motor or a vessel. EXPERIMENTAL-tier; adds NOTHING
|
| 395 |
+
# to the locked-8; Λ stays Conjecture 1; trust never 100%.
|
| 396 |
+
# ---------------------------------------------------------------------------
|
| 397 |
+
def quad_mixing_matrix(arm_length: float = 0.25, k_thrust: float = 1.0,
|
| 398 |
+
k_torque: float = 0.02) -> list[list[float]]:
|
| 399 |
+
"""Quadcopter (X-config) control-effectiveness / mixing matrix B (4×4) mapping the
|
| 400 |
+
four rotor thrusts f = [f1,f2,f3,f4] (front-right, back-left, front-left, back-right)
|
| 401 |
+
to the body wrench tau = [T, L, M, N] = [total thrust, roll, pitch, yaw torque]:
|
| 402 |
+
T = f1 + f2 + f3 + f4
|
| 403 |
+
L (roll, about x) = arm · ( -f1 + f2 - f3 + f4 ) · k_thrust (right rotors down)
|
| 404 |
+
M (pitch, about y) = arm · ( f1 + f2 - f3 - f4 ) · k_thrust (front rotors up)
|
| 405 |
+
N (yaw, about z) = k_torque · ( f1 + f2 - f3 - f4 ) via reaction torque sign
|
| 406 |
+
The exact signs encode the X-frame geometry + the CW/CCW spin pattern. This is the
|
| 407 |
+
standard quadrotor control-allocation matrix. MODELED. [EXPERIMENTAL]"""
|
| 408 |
+
a = arm_length * k_thrust
|
| 409 |
+
kt = k_torque
|
| 410 |
+
# rows: [T, L(roll), M(pitch), N(yaw)] ; cols: f1 f2 f3 f4
|
| 411 |
+
return [
|
| 412 |
+
[1.0, 1.0, 1.0, 1.0], # total thrust
|
| 413 |
+
[-a, a, -a, a], # roll torque
|
| 414 |
+
[a, a, -a, -a], # pitch torque
|
| 415 |
+
[kt, -kt, -kt, kt], # yaw reaction torque (CW/CCW pattern)
|
| 416 |
+
]
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
def _mat_mul(A: list[list[float]], B: list[list[float]]) -> list[list[float]]:
|
| 420 |
+
return [[sum(A[i][k] * B[k][j] for k in range(len(B)))
|
| 421 |
+
for j in range(len(B[0]))] for i in range(len(A))]
|
| 422 |
+
|
| 423 |
+
|
| 424 |
+
def _transpose(A: list[list[float]]) -> list[list[float]]:
|
| 425 |
+
return [[A[i][j] for i in range(len(A))] for j in range(len(A[0]))]
|
| 426 |
+
|
| 427 |
+
|
| 428 |
+
def _inv(A: list[list[float]]) -> list[list[float]]:
|
| 429 |
+
"""Gauss-Jordan inverse of a small square matrix (no numpy). Raises on singular."""
|
| 430 |
+
n = len(A)
|
| 431 |
+
M = [list(map(float, A[i])) + [1.0 if i == j else 0.0 for j in range(n)] for i in range(n)]
|
| 432 |
+
for col in range(n):
|
| 433 |
+
piv = max(range(col, n), key=lambda r: abs(M[r][col]))
|
| 434 |
+
if abs(M[piv][col]) < 1e-12:
|
| 435 |
+
raise ValueError("singular matrix")
|
| 436 |
+
M[col], M[piv] = M[piv], M[col]
|
| 437 |
+
pv = M[col][col]
|
| 438 |
+
M[col] = [x / pv for x in M[col]]
|
| 439 |
+
for r in range(n):
|
| 440 |
+
if r != col:
|
| 441 |
+
fac = M[r][col]
|
| 442 |
+
M[r] = [a - fac * b for a, b in zip(M[r], M[col])]
|
| 443 |
+
return [row[n:] for row in M]
|
| 444 |
+
|
| 445 |
+
|
| 446 |
+
def moore_penrose_pinv(B: list[list[float]]) -> list[list[float]]:
|
| 447 |
+
"""Moore-Penrose pseudo-inverse B+ of a (possibly non-square) matrix, pure stdlib.
|
| 448 |
+
For a wide/tall full-rank B we use the closed forms:
|
| 449 |
+
right pinv (rows<=cols, full row rank): B+ = B^T (B B^T)^-1
|
| 450 |
+
left pinv (rows> cols, full col rank): B+ = (B^T B)^-1 B^T
|
| 451 |
+
For a square invertible B both reduce to B^-1. This is the minimum-norm /
|
| 452 |
+
least-squares control allocator. Cite Moore-Penrose; Johansen & Fossen (2013).
|
| 453 |
+
[EXPERIMENTAL]"""
|
| 454 |
+
rows, cols = len(B), len(B[0])
|
| 455 |
+
Bt = _transpose(B)
|
| 456 |
+
if rows <= cols:
|
| 457 |
+
# right inverse: B^T (B B^T)^-1
|
| 458 |
+
BBt = _mat_mul(B, Bt)
|
| 459 |
+
return _mat_mul(Bt, _inv(BBt))
|
| 460 |
+
else:
|
| 461 |
+
# left inverse: (B^T B)^-1 B^T
|
| 462 |
+
BtB = _mat_mul(Bt, B)
|
| 463 |
+
return _mat_mul(_inv(BtB), Bt)
|
| 464 |
+
|
| 465 |
+
|
| 466 |
+
def szl_control_allocation(tau_cmd: list[float], arm_length: float = 0.25,
|
| 467 |
+
k_thrust: float = 1.0, k_torque: float = 0.02,
|
| 468 |
+
f_min: float = 0.0, f_max: float = 12.0) -> dict[str, Any]:
|
| 469 |
+
"""Moore-Penrose pseudo-inverse CONTROL ALLOCATION: given a commanded body wrench
|
| 470 |
+
tau_cmd = [T, L, M, N] (total thrust + roll/pitch/yaw torque), solve for the
|
| 471 |
+
minimum-norm rotor-thrust vector f = B+ · tau that realizes it, then saturate each
|
| 472 |
+
rotor to [f_min, f_max] and report the achieved wrench tau_ach = B · f_sat and the
|
| 473 |
+
allocation residual. This is the optimal (least-norm) thrust distribution — the
|
| 474 |
+
classic Moore-Penrose allocator from Hassan's Simulink MBD project. MODELED/SIMULATED:
|
| 475 |
+
NO live airframe; this computes a solution, it never actuates. [EXPERIMENTAL · MODELED]"""
|
| 476 |
+
B = quad_mixing_matrix(arm_length, k_thrust, k_torque)
|
| 477 |
+
Bp = moore_penrose_pinv(B)
|
| 478 |
+
tau = [float(x) for x in (list(tau_cmd) + [0.0, 0.0, 0.0, 0.0])[:4]]
|
| 479 |
+
# f = B+ tau
|
| 480 |
+
f_raw = [sum(Bp[i][j] * tau[j] for j in range(4)) for i in range(4)]
|
| 481 |
+
f_sat = [min(max(v, f_min), f_max) for v in f_raw]
|
| 482 |
+
saturated = [bool(abs(v - s) > 1e-9) for v, s in zip(f_raw, f_sat)]
|
| 483 |
+
# achieved wrench tau_ach = B f_sat
|
| 484 |
+
tau_ach = [sum(B[i][j] * f_sat[j] for j in range(4)) for i in range(4)]
|
| 485 |
+
resid = [round(tau_ach[i] - tau[i], 6) for i in range(4)]
|
| 486 |
+
resid_norm = math.sqrt(sum(r * r for r in resid))
|
| 487 |
+
labels = ["thrust_T", "roll_L", "pitch_M", "yaw_N"]
|
| 488 |
+
rotors = ["f1_front_right", "f2_back_left", "f3_front_left", "f4_back_right"]
|
| 489 |
+
return {
|
| 490 |
+
"tau_cmd": {labels[i]: round(tau[i], 4) for i in range(4)},
|
| 491 |
+
"rotor_thrust_raw": {rotors[i]: round(f_raw[i], 6) for i in range(4)},
|
| 492 |
+
"rotor_thrust_sat": {rotors[i]: round(f_sat[i], 6) for i in range(4)},
|
| 493 |
+
"any_rotor_saturated": any(saturated),
|
| 494 |
+
"tau_achieved": {labels[i]: round(tau_ach[i], 4) for i in range(4)},
|
| 495 |
+
"allocation_residual": {labels[i]: resid[i] for i in range(4)},
|
| 496 |
+
"residual_norm": round(resid_norm, 6),
|
| 497 |
+
"method": "Moore-Penrose pseudo-inverse f = B⁺·τ (minimum-norm least-squares), then saturate",
|
| 498 |
+
"mixing_matrix_B": B,
|
| 499 |
+
"effector": "SIMULATED",
|
| 500 |
+
"data_label": "MODELED/SIMULATED — no live airframe; computes a thrust solution, never actuates",
|
| 501 |
+
"doctrine": "adopted Hassan quadcopter MBD control-allocation; NOT added to the locked-8; Λ Conjecture 1",
|
| 502 |
+
"status": "MODELED",
|
| 503 |
+
}
|
| 504 |
+
|
| 505 |
+
|
| 506 |
+
def szl_6dof_step(state: dict[str, float] | None = None, tau: list[float] | None = None,
|
| 507 |
+
mass: float = 1.2, ixx: float = 0.015, iyy: float = 0.015,
|
| 508 |
+
izz: float = 0.028, dt: float = 0.01, g: float = 9.81) -> dict[str, Any]:
|
| 509 |
+
"""One-step 6DOF rigid-body dynamics for a quad/interceptor (MODELED/SIMULATED).
|
| 510 |
+
State = body-frame translational velocity (u,v,w), angular rates (p,q,r), and
|
| 511 |
+
Euler attitude (phi,theta,psi). Given a body wrench tau=[T,L,M,N] (total thrust
|
| 512 |
+
along body -z + roll/pitch/yaw torques), integrate ONE Euler step of the Newton-
|
| 513 |
+
Euler equations:
|
| 514 |
+
translational: m(ẇ + ...) — here reported as body accelerations
|
| 515 |
+
u̇ = r*v - q*w - g*sin(theta)
|
| 516 |
+
v̇ = p*w - r*u + g*cos(theta)*sin(phi)
|
| 517 |
+
ẇ = q*u - p*v + g*cos(theta)*cos(phi) - T/m
|
| 518 |
+
rotational (Euler):
|
| 519 |
+
ṗ = (L - (izz-iyy)*q*r)/ixx
|
| 520 |
+
q̇ = (M - (ixx-izz)*p*r)/iyy
|
| 521 |
+
ṙ = (N - (iyy-ixx)*p*q)/izz
|
| 522 |
+
attitude kinematics: phi̇ = p + ... (small-angle body-rate ≈ Euler-rate).
|
| 523 |
+
Returns the derivatives + the integrated next state. This is the standard
|
| 524 |
+
Aerospace-Blockset 6DOF body model (Hassan MBD). NO live airframe; deterministic
|
| 525 |
+
model output, never actuated. [EXPERIMENTAL · MODELED]"""
|
| 526 |
+
s = {"u": 0.0, "v": 0.0, "w": 0.0, "p": 0.0, "q": 0.0, "r": 0.0,
|
| 527 |
+
"phi": 0.0, "theta": 0.0, "psi": 0.0}
|
| 528 |
+
if state:
|
| 529 |
+
s.update({k: float(v) for k, v in state.items() if k in s})
|
| 530 |
+
T, L, M, N = ([float(x) for x in (list(tau or []) + [0.0] * 4)[:4]])
|
| 531 |
+
u, v, w = s["u"], s["v"], s["w"]
|
| 532 |
+
p, q, r = s["p"], s["q"], s["r"]
|
| 533 |
+
phi, theta, psi = s["phi"], s["theta"], s["psi"]
|
| 534 |
+
# translational body accelerations
|
| 535 |
+
du = r * v - q * w - g * math.sin(theta)
|
| 536 |
+
dv = p * w - r * u + g * math.cos(theta) * math.sin(phi)
|
| 537 |
+
dw = q * u - p * v + g * math.cos(theta) * math.cos(phi) - T / max(mass, 1e-9)
|
| 538 |
+
# rotational (Newton-Euler)
|
| 539 |
+
dp = (L - (izz - iyy) * q * r) / max(ixx, 1e-9)
|
| 540 |
+
dq = (M - (ixx - izz) * p * r) / max(iyy, 1e-9)
|
| 541 |
+
dr = (N - (iyy - ixx) * p * q) / max(izz, 1e-9)
|
| 542 |
+
# attitude kinematics (Euler-angle rates; full transport matrix)
|
| 543 |
+
dphi = p + math.sin(phi) * math.tan(theta) * q + math.cos(phi) * math.tan(theta) * r
|
| 544 |
+
dtheta = math.cos(phi) * q - math.sin(phi) * r
|
| 545 |
+
dpsi = (math.sin(phi) / max(math.cos(theta), 1e-6)) * q + (math.cos(phi) / max(math.cos(theta), 1e-6)) * r
|
| 546 |
+
deriv = {"du": du, "dv": dv, "dw": dw, "dp": dp, "dq": dq, "dr": dr,
|
| 547 |
+
"dphi": dphi, "dtheta": dtheta, "dpsi": dpsi}
|
| 548 |
+
nxt = {
|
| 549 |
+
"u": u + du * dt, "v": v + dv * dt, "w": w + dw * dt,
|
| 550 |
+
"p": p + dp * dt, "q": q + dq * dt, "r": r + dr * dt,
|
| 551 |
+
"phi": phi + dphi * dt, "theta": theta + dtheta * dt, "psi": psi + dpsi * dt,
|
| 552 |
+
}
|
| 553 |
+
return {
|
| 554 |
+
"state_in": {k: round(val, 6) for k, val in s.items()},
|
| 555 |
+
"tau": {"thrust_T": round(T, 4), "roll_L": round(L, 4),
|
| 556 |
+
"pitch_M": round(M, 4), "yaw_N": round(N, 4)},
|
| 557 |
+
"derivatives": {k: round(val, 6) for k, val in deriv.items()},
|
| 558 |
+
"state_next": {k: round(val, 6) for k, val in nxt.items()},
|
| 559 |
+
"params": {"mass": mass, "Ixx": ixx, "Iyy": iyy, "Izz": izz, "dt": dt, "g": g},
|
| 560 |
+
"model": "Newton-Euler rigid-body 6DOF (body frame); Aerospace-Blockset shape (Hassan MBD)",
|
| 561 |
+
"effector": "SIMULATED",
|
| 562 |
+
"data_label": "MODELED/SIMULATED — no live airframe; deterministic model step, never actuated",
|
| 563 |
+
"doctrine": "adopted Hassan quadcopter 6DOF MBD; NOT added to the locked-8; Λ Conjecture 1",
|
| 564 |
+
"status": "MODELED",
|
| 565 |
+
}
|
| 566 |
+
|
| 567 |
+
|
| 568 |
def summary(ns: str = "killinchu") -> dict[str, Any]:
|
| 569 |
"""Headline of all six SZL counter-UAS formulas + honest provenance/legend.
|
| 570 |
`ns` names the serving app so the title is accurate on both killinchu and a11oy."""
|
|
|
|
| 581 |
"wta": "SZL-WTA Threat Triage (weapon-target assignment, SIMULATED)",
|
| 582 |
"pqbus": "SZL-PQ Receipt Bus (post-quantum receipt chain)",
|
| 583 |
"active_flux": "SZL Active-Flux Hybrid Observer (sensorless PMSM; ADOPTED Li Yu/APEC 2001, MODELED)",
|
| 584 |
+
"platform_allocation": "SZL Platform Dynamics — Moore-Penrose control allocation (ADOPTED Hassan MBD, MODELED)",
|
| 585 |
+
"platform_6dof": "SZL Platform Dynamics — 6DOF Newton-Euler quad/interceptor step (ADOPTED Hassan MBD, MODELED)",
|
| 586 |
},
|
| 587 |
"examples": {
|
| 588 |
"engage": szl_engageability(N=3.5, Vc=300.0, los_rate=0.02, t_go=4.0, a_max=200.0),
|
|
|
|
| 638 |
"points": n, "curve": curve, "li_yu_reference": LI_YU_REFERENCE_BODE,
|
| 639 |
"data_label": "MODELED/SIMULATED — no live motor", "status": "MODELED"}
|
| 640 |
app.add_api_route(f"{base}/active-flux/bode", _active_flux_bode, methods=["GET"])
|
| 641 |
+
# F-θ Platform Dynamics — Moore-Penrose control allocation + 6DOF step (ADOPTED Hassan MBD; MODELED).
|
| 642 |
+
def _alloc(T: str = "11.8", L: str = "0.2", M: str = "0.0", N: str = "0.05",
|
| 643 |
+
arm: str = "0.25", k_torque: str = "0.02", f_max: str = "12.0"):
|
| 644 |
+
try:
|
| 645 |
+
return szl_control_allocation([float(T), float(L), float(M), float(N)],
|
| 646 |
+
arm_length=float(arm), k_torque=float(k_torque),
|
| 647 |
+
f_max=float(f_max))
|
| 648 |
+
except (ValueError, TypeError) as e:
|
| 649 |
+
return {"error": {"code": "validation_error", "detail": str(e)}}
|
| 650 |
+
app.add_api_route(f"{base}/allocation", _alloc, methods=["GET"])
|
| 651 |
+
|
| 652 |
+
def _sixdof(T: str = "11.77", L: str = "0.0", M: str = "0.0", N: str = "0.0",
|
| 653 |
+
p: str = "0.0", q: str = "0.0", r: str = "0.0",
|
| 654 |
+
phi: str = "0.0", theta: str = "0.1", psi: str = "0.0", dt: str = "0.01"):
|
| 655 |
+
try:
|
| 656 |
+
return szl_6dof_step(
|
| 657 |
+
state={"p": float(p), "q": float(q), "r": float(r),
|
| 658 |
+
"phi": float(phi), "theta": float(theta), "psi": float(psi)},
|
| 659 |
+
tau=[float(T), float(L), float(M), float(N)], dt=float(dt))
|
| 660 |
+
except (ValueError, TypeError) as e:
|
| 661 |
+
return {"error": {"code": "validation_error", "detail": str(e)}}
|
| 662 |
+
app.add_api_route(f"{base}/dynamics", _sixdof, methods=["GET"])
|
| 663 |
|
| 664 |
|
| 665 |
def _selftest() -> None:
|
|
|
|
| 703 |
obs = szl_active_flux_observer()
|
| 704 |
assert obs["status"] == "MODELED" and obs["effector"] == "SIMULATED"
|
| 705 |
assert "MODELED/SIMULATED" in obs["data_label"]
|
| 706 |
+
# F-θ Platform Dynamics (ADOPTED Hassan MBD; MODELED): pseudo-inverse round-trip.
|
| 707 |
+
B = quad_mixing_matrix()
|
| 708 |
+
Bp = moore_penrose_pinv(B)
|
| 709 |
+
# B is 4x4 invertible -> B B+ = I (within tolerance)
|
| 710 |
+
BBp = _mat_mul(B, Bp)
|
| 711 |
+
for i in range(4):
|
| 712 |
+
for j in range(4):
|
| 713 |
+
assert abs(BBp[i][j] - (1.0 if i == j else 0.0)) < 1e-6
|
| 714 |
+
# pure-thrust command -> equal rotor split, zero torque residual
|
| 715 |
+
al = szl_control_allocation([12.0, 0.0, 0.0, 0.0])
|
| 716 |
+
rs = al["rotor_thrust_sat"]
|
| 717 |
+
assert abs(rs["f1_front_right"] - 3.0) < 1e-6 and al["residual_norm"] < 1e-6
|
| 718 |
+
assert al["status"] == "MODELED" and al["effector"] == "SIMULATED"
|
| 719 |
+
# roll command on a hover baseline (so no rotor saturates) -> achieved wrench == commanded
|
| 720 |
+
al2 = szl_control_allocation([8.0, 0.5, 0.0, 0.0])
|
| 721 |
+
assert not al2["any_rotor_saturated"]
|
| 722 |
+
assert abs(al2["tau_achieved"]["roll_L"] - 0.5) < 1e-6
|
| 723 |
+
assert abs(al2["tau_achieved"]["thrust_T"] - 8.0) < 1e-6 and al2["residual_norm"] < 1e-6
|
| 724 |
+
# 6DOF: hover thrust ~ m*g cancels gravity in w-dot (theta=0)
|
| 725 |
+
st = szl_6dof_step(state={"theta": 0.0}, tau=[1.2 * 9.81, 0.0, 0.0, 0.0])
|
| 726 |
+
assert abs(st["derivatives"]["dw"]) < 1e-6 and st["status"] == "MODELED"
|
| 727 |
+
# roll torque produces a positive p-dot
|
| 728 |
+
st2 = szl_6dof_step(tau=[0.0, 0.01, 0.0, 0.0])
|
| 729 |
+
assert st2["derivatives"]["dp"] > 0.0 and st2["effector"] == "SIMULATED"
|
| 730 |
+
print("szl_cuas_formulas: ALL OK (27 checks)")
|
| 731 |
|
| 732 |
|
| 733 |
if __name__ == "__main__":
|