szl 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- szl-0.1.0/PKG-INFO +59 -0
- szl-0.1.0/README.md +46 -0
- szl-0.1.0/pyproject.toml +22 -0
- szl-0.1.0/setup.cfg +4 -0
- szl-0.1.0/szl/__init__.py +11 -0
- szl-0.1.0/szl/kamachikuna.py +47 -0
- szl-0.1.0/szl/khipu.py +120 -0
- szl-0.1.0/szl/openshell.py +152 -0
- szl-0.1.0/szl/provenance.py +53 -0
- szl-0.1.0/szl/router.py +63 -0
- szl-0.1.0/szl.egg-info/PKG-INFO +59 -0
- szl-0.1.0/szl.egg-info/SOURCES.txt +13 -0
- szl-0.1.0/szl.egg-info/dependency_links.txt +1 -0
- szl-0.1.0/szl.egg-info/top_level.txt +1 -0
- szl-0.1.0/tests/test_szl_sdk.py +241 -0
szl-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: szl
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The receipts layer for governed AI: khipu signing, the Kamachikuna constitution, provenance badges, and the two-axis Truth Router.
|
|
5
|
+
Author-email: SZL Holdings <stephen@szlholdings.com>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://szlholdings.com/
|
|
8
|
+
Project-URL: Source, https://github.com/szl-holdings/szl-gpu-bridge
|
|
9
|
+
Project-URL: Sponsors, https://szlholdings.com/sponsors.html
|
|
10
|
+
Keywords: ai,governance,provenance,receipts,honesty,khipu,kamachikuna
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# szl — the receipts layer for governed AI
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
import sys; sys.path.insert(0, ".") # until published: pip install szl
|
|
18
|
+
from szl import khipu, kamachikuna, provenance, router
|
|
19
|
+
|
|
20
|
+
# 1. Every claim carries a receipt (Law 7)
|
|
21
|
+
r = khipu.mint({"claim": "training completed", "steps": 2000}, secret="…")
|
|
22
|
+
assert khipu.check(r, secret="…") # integrity + origin
|
|
23
|
+
r2 = khipu.mint({"claim": "eval done"}, secret="…", prev_body_sha256=r["body_sha256"])
|
|
24
|
+
assert khipu.check_chain([r, r2], "…", expected_head=r2["body_sha256"])
|
|
25
|
+
|
|
26
|
+
# 2. Fail closed (Law 6)
|
|
27
|
+
assert kamachikuna.gate("deploy", verified=False)[1] == "BLOCKED"
|
|
28
|
+
|
|
29
|
+
# 3. Provenance badge — the Korea/Naver bar, machine-checked
|
|
30
|
+
c = provenance.ProvenanceClaim(model_id="m", source_sha="…", training_receipt=r,
|
|
31
|
+
datasets={"train": "sha256…"})
|
|
32
|
+
badge = c.badge(secret="…") # state: MEASURED | CARD_ONLY | UNTRAINED | UNAVAILABLE
|
|
33
|
+
|
|
34
|
+
# 4. Two-axis Truth Router — honest cheapest, joules reported separately
|
|
35
|
+
pick = router.route("honesty-critical", models) # None if no honest model: fail closed
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Modules
|
|
39
|
+
- **khipu** — signed, hash-chained receipts. Full-length HMAC-SHA256 signatures (never truncated — that was the v1 auditor bug). Tamper, reorder, and truncation detection (truncation via `expected_head`).
|
|
40
|
+
- **kamachikuna** — the constitution: 10 laws, 5 Prime Principles, 5 Lean-proven invariants, 3 amendments, and Law 6 as a callable gate.
|
|
41
|
+
- **provenance** — honest states only: UNTRAINED · CARD_ONLY · MEASURED · UNAVAILABLE · NOT_CLAIMED. Verification proves integrity and origin, never accuracy or performance.
|
|
42
|
+
- **router** — two-axis honesty routing: price axis decides, joules reported separately (never summed with dollars — different units), UNMEASURED energy never counts as zero, honesty-critical tasks fail closed.
|
|
43
|
+
|
|
44
|
+
## The freshness rule
|
|
45
|
+
> "A line older than seven days is a claim, not a fact." — Vidal-Gadea Lab roadmap, Nov 2026
|
|
46
|
+
|
|
47
|
+
`khipu.check_chain(..., max_age_days=7)` fails a chain whose newest receipt is
|
|
48
|
+
older than the window. A stale record that still verifies is worse than no
|
|
49
|
+
record, because it is believed — their lab's cached tracker sat 57 days untouched
|
|
50
|
+
and was read by a program with no error and no warning.
|
|
51
|
+
|
|
52
|
+
## Design debts deliberately not hidden
|
|
53
|
+
- Chain prefixes are internally valid; completeness requires `expected_head` (tamper-evidence ≠ completeness).
|
|
54
|
+
- An unmeasured quantity is None/UNKNOWN everywhere — never zero.
|
|
55
|
+
- Freshness is a separate axis from integrity: a chain can be both valid and stale.
|
|
56
|
+
|
|
57
|
+
Tests: `python3 sdk/tests/test_szl_sdk.py` — 11/11 offline, no network, no GPU.
|
|
58
|
+
|
|
59
|
+
Apache-2.0. Copyright 2026 SZL Holdings · Stephen P. Lutar Jr.
|
szl-0.1.0/README.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# szl — the receipts layer for governed AI
|
|
2
|
+
|
|
3
|
+
```python
|
|
4
|
+
import sys; sys.path.insert(0, ".") # until published: pip install szl
|
|
5
|
+
from szl import khipu, kamachikuna, provenance, router
|
|
6
|
+
|
|
7
|
+
# 1. Every claim carries a receipt (Law 7)
|
|
8
|
+
r = khipu.mint({"claim": "training completed", "steps": 2000}, secret="…")
|
|
9
|
+
assert khipu.check(r, secret="…") # integrity + origin
|
|
10
|
+
r2 = khipu.mint({"claim": "eval done"}, secret="…", prev_body_sha256=r["body_sha256"])
|
|
11
|
+
assert khipu.check_chain([r, r2], "…", expected_head=r2["body_sha256"])
|
|
12
|
+
|
|
13
|
+
# 2. Fail closed (Law 6)
|
|
14
|
+
assert kamachikuna.gate("deploy", verified=False)[1] == "BLOCKED"
|
|
15
|
+
|
|
16
|
+
# 3. Provenance badge — the Korea/Naver bar, machine-checked
|
|
17
|
+
c = provenance.ProvenanceClaim(model_id="m", source_sha="…", training_receipt=r,
|
|
18
|
+
datasets={"train": "sha256…"})
|
|
19
|
+
badge = c.badge(secret="…") # state: MEASURED | CARD_ONLY | UNTRAINED | UNAVAILABLE
|
|
20
|
+
|
|
21
|
+
# 4. Two-axis Truth Router — honest cheapest, joules reported separately
|
|
22
|
+
pick = router.route("honesty-critical", models) # None if no honest model: fail closed
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Modules
|
|
26
|
+
- **khipu** — signed, hash-chained receipts. Full-length HMAC-SHA256 signatures (never truncated — that was the v1 auditor bug). Tamper, reorder, and truncation detection (truncation via `expected_head`).
|
|
27
|
+
- **kamachikuna** — the constitution: 10 laws, 5 Prime Principles, 5 Lean-proven invariants, 3 amendments, and Law 6 as a callable gate.
|
|
28
|
+
- **provenance** — honest states only: UNTRAINED · CARD_ONLY · MEASURED · UNAVAILABLE · NOT_CLAIMED. Verification proves integrity and origin, never accuracy or performance.
|
|
29
|
+
- **router** — two-axis honesty routing: price axis decides, joules reported separately (never summed with dollars — different units), UNMEASURED energy never counts as zero, honesty-critical tasks fail closed.
|
|
30
|
+
|
|
31
|
+
## The freshness rule
|
|
32
|
+
> "A line older than seven days is a claim, not a fact." — Vidal-Gadea Lab roadmap, Nov 2026
|
|
33
|
+
|
|
34
|
+
`khipu.check_chain(..., max_age_days=7)` fails a chain whose newest receipt is
|
|
35
|
+
older than the window. A stale record that still verifies is worse than no
|
|
36
|
+
record, because it is believed — their lab's cached tracker sat 57 days untouched
|
|
37
|
+
and was read by a program with no error and no warning.
|
|
38
|
+
|
|
39
|
+
## Design debts deliberately not hidden
|
|
40
|
+
- Chain prefixes are internally valid; completeness requires `expected_head` (tamper-evidence ≠ completeness).
|
|
41
|
+
- An unmeasured quantity is None/UNKNOWN everywhere — never zero.
|
|
42
|
+
- Freshness is a separate axis from integrity: a chain can be both valid and stale.
|
|
43
|
+
|
|
44
|
+
Tests: `python3 sdk/tests/test_szl_sdk.py` — 11/11 offline, no network, no GPU.
|
|
45
|
+
|
|
46
|
+
Apache-2.0. Copyright 2026 SZL Holdings · Stephen P. Lutar Jr.
|
szl-0.1.0/pyproject.toml
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=69"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "szl"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "The receipts layer for governed AI: khipu signing, the Kamachikuna constitution, provenance badges, and the two-axis Truth Router."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "Apache-2.0" }
|
|
12
|
+
authors = [{ name = "SZL Holdings", email = "stephen@szlholdings.com" }]
|
|
13
|
+
keywords = ["ai", "governance", "provenance", "receipts", "honesty", "khipu", "kamachikuna"]
|
|
14
|
+
|
|
15
|
+
[project.urls]
|
|
16
|
+
Homepage = "https://szlholdings.com/"
|
|
17
|
+
Source = "https://github.com/szl-holdings/szl-gpu-bridge"
|
|
18
|
+
Sponsors = "https://szlholdings.com/sponsors.html"
|
|
19
|
+
|
|
20
|
+
[tool.setuptools.packages.find]
|
|
21
|
+
where = ["."]
|
|
22
|
+
include = ["szl*"]
|
szl-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"""szl — the receipts layer for governed AI, as an installable SDK.
|
|
2
|
+
|
|
3
|
+
Khipu signing, the Kamachikuna constitution constants, provenance badges,
|
|
4
|
+
and the two-axis Truth Router client. Every claim this package helps you
|
|
5
|
+
make carries a receipt; verification proves integrity and origin, never
|
|
6
|
+
accuracy or performance.
|
|
7
|
+
|
|
8
|
+
Canonical source: szl-holdings/szl-gpu-bridge (GitHub is canonical).
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""kamachikuna — the constitution as machine-usable constants.
|
|
2
|
+
|
|
3
|
+
10 Laws, 5 Prime Principles, EU AI Act-aligned amendments. These are the
|
|
4
|
+
gates every SZL model and service is trained on and checked against.
|
|
5
|
+
Doctrine v11. Λ = Conjecture 1 (uniqueness is a conjecture, not a theorem).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
PRIME_PRINCIPLES = {
|
|
9
|
+
1: "HARMLESSNESS — never hurt a human, above all laws",
|
|
10
|
+
2: "TRUTH — never deceive a human",
|
|
11
|
+
3: "AYNI — every taking gives back",
|
|
12
|
+
4: "THE SEVENTH GENERATION — weigh the unborn",
|
|
13
|
+
5: "SUMAK KAWSAY — harmony with community and nature",
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
LAWS = {
|
|
17
|
+
1: "Never hurt a human",
|
|
18
|
+
2: "Never deceive a human",
|
|
19
|
+
3: "Ayni: every taking gives back",
|
|
20
|
+
4: "The seventh generation: weigh the unborn",
|
|
21
|
+
5: "Tamper-evident: every state change leaves a verifiable trace",
|
|
22
|
+
6: "Fail closed: when the gate cannot verify, the action does not happen",
|
|
23
|
+
7: "Every claim carries a receipt; no receipt = UNKNOWN, never a claim",
|
|
24
|
+
8: "Abstain when you cannot prove; fabrication is perjury",
|
|
25
|
+
9: "No silent failure: errors surface or the system goes to safe state",
|
|
26
|
+
10: "The loop audits itself: the estate consumes its own receipts",
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# Machine-checked invariant theorems (Lean 4, zero errors, zero sorries).
|
|
30
|
+
LEAN_PROVEN = [
|
|
31
|
+
"Kamachi.law1_fail_closed",
|
|
32
|
+
"law4_no_bound_raising",
|
|
33
|
+
"law5_tamper_evident",
|
|
34
|
+
"law7_irreversible_needs_human",
|
|
35
|
+
"law9_no_silent_failure",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
AMENDMENTS = {
|
|
39
|
+
1: "EU AI Act Article 11: synthetic content marking",
|
|
40
|
+
2: "Prime Principle: never hurt a human",
|
|
41
|
+
3: "Five Prime Principles adopted",
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def gate(action: str, verified: bool) -> tuple[str, str]:
|
|
46
|
+
"""Law 6 as a function. Returns (action, 'ALLOWED'|'BLOCKED')."""
|
|
47
|
+
return (action, "ALLOWED") if verified else (action, "BLOCKED")
|
szl-0.1.0/szl/khipu.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""khipu — signed, hash-chained receipts. Fail closed, tamper-evident.
|
|
2
|
+
|
|
3
|
+
A receipt is canonical JSON. Its signature is HMAC-SHA256 over the
|
|
4
|
+
canonical body hash, stored FULL length (never truncated). Receipts chain:
|
|
5
|
+
each carries the sha256 of the previous receipt's body, so any reorder,
|
|
6
|
+
edit, or deletion is detectable (Kamachikuna Law 5).
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import hashlib
|
|
11
|
+
import hmac
|
|
12
|
+
import json
|
|
13
|
+
import time
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
KIND = "szl.receipt/v1"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def canonical(obj: Any) -> str:
|
|
20
|
+
"""Deterministic JSON: sorted keys, no whitespace. The signing basis."""
|
|
21
|
+
return json.dumps(obj, sort_keys=True, separators=(",", ":"))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def sha256_hex(s: str) -> str:
|
|
25
|
+
return hashlib.sha256(s.encode("utf-8")).hexdigest()
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def sign(body_sha256: str, secret: str) -> str:
|
|
29
|
+
"""Full-length HMAC signature. Never truncate a signature."""
|
|
30
|
+
return hmac.new(secret.encode(), body_sha256.encode(), hashlib.sha256).hexdigest()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def verify(body_sha256: str, signature: str, secret: str) -> bool:
|
|
34
|
+
if not isinstance(signature, str) or len(signature) != 64:
|
|
35
|
+
return False
|
|
36
|
+
return hmac.compare_digest(sign(body_sha256, secret), signature)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def mint(
|
|
40
|
+
claim: dict[str, Any],
|
|
41
|
+
secret: str,
|
|
42
|
+
prev_body_sha256: str | None = None,
|
|
43
|
+
ts: str | None = None,
|
|
44
|
+
) -> dict[str, Any]:
|
|
45
|
+
"""Mint one signed receipt for a claim. The claim must already be
|
|
46
|
+
honest: no receipt can make an unverified claim true (Law 7)."""
|
|
47
|
+
body = {
|
|
48
|
+
"kind": KIND,
|
|
49
|
+
"ts": ts or time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
|
50
|
+
"prev_receipt_sha256": prev_body_sha256,
|
|
51
|
+
"claim": claim,
|
|
52
|
+
}
|
|
53
|
+
body_sha256 = sha256_hex(canonical(body))
|
|
54
|
+
return {**body, "body_sha256": body_sha256, "signature": sign(body_sha256, secret)}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def check(receipt: dict[str, Any], secret: str) -> bool:
|
|
58
|
+
"""Verify one receipt's integrity and origin. Proves the receipt is
|
|
59
|
+
intact and signed by the holder of `secret` — never that the claim
|
|
60
|
+
inside is accurate. An unsigned or empty receipt NEVER verifies."""
|
|
61
|
+
if not isinstance(receipt, dict):
|
|
62
|
+
return False
|
|
63
|
+
if not receipt.get("ts"): # missing timestamp = unverifiable
|
|
64
|
+
return False
|
|
65
|
+
import datetime
|
|
66
|
+
try:
|
|
67
|
+
dt = datetime.datetime.fromisoformat(str(receipt["ts"]).replace("Z", "+00:00"))
|
|
68
|
+
if dt.tzinfo is None: # timezone-free = unverifiable
|
|
69
|
+
return False
|
|
70
|
+
if dt > datetime.datetime.now(datetime.timezone.utc) + datetime.timedelta(minutes=5):
|
|
71
|
+
return False # future timestamp = unverifiable
|
|
72
|
+
except (ValueError, TypeError):
|
|
73
|
+
return False
|
|
74
|
+
body = {k: v for k, v in receipt.items() if k not in ("body_sha256", "signature")}
|
|
75
|
+
if body.get("kind") != KIND:
|
|
76
|
+
return False
|
|
77
|
+
expected = sha256_hex(canonical(body))
|
|
78
|
+
if receipt.get("body_sha256") != expected:
|
|
79
|
+
return False
|
|
80
|
+
return verify(expected, receipt.get("signature", ""), secret)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def check_chain(
|
|
84
|
+
receipts: list[dict[str, Any]],
|
|
85
|
+
secret: str,
|
|
86
|
+
expected_head: str | None = None,
|
|
87
|
+
max_age_days: float | None = None,
|
|
88
|
+
) -> bool:
|
|
89
|
+
"""Verify a full chain: every receipt valid, every link intact.
|
|
90
|
+
A prefix of the chain is internally valid — truncation is only
|
|
91
|
+
detectable against `expected_head` (the latest known body_sha256).
|
|
92
|
+
Pass it to prove completeness, not just integrity.
|
|
93
|
+
|
|
94
|
+
`max_age_days` implements the freshness rule: a chain whose newest
|
|
95
|
+
receipt is older than the window is STALE, not green. A stale record
|
|
96
|
+
that still verifies is worse than no record, because it is believed.
|
|
97
|
+
(Vidal-Gadea Lab roadmap, Nov 2026: cached values sat untouched 57
|
|
98
|
+
days and a program read them with no error and no warning.)"""
|
|
99
|
+
prev: str | None = None
|
|
100
|
+
newest_ts: str | None = None
|
|
101
|
+
for r in receipts:
|
|
102
|
+
if not check(r, secret):
|
|
103
|
+
return False
|
|
104
|
+
if r.get("prev_receipt_sha256") != prev:
|
|
105
|
+
return False
|
|
106
|
+
prev = r["body_sha256"]
|
|
107
|
+
newest_ts = r.get("ts") or newest_ts
|
|
108
|
+
if expected_head is not None and prev != expected_head:
|
|
109
|
+
return False # truncated chain
|
|
110
|
+
if max_age_days is not None and newest_ts is not None:
|
|
111
|
+
import datetime
|
|
112
|
+
|
|
113
|
+
try:
|
|
114
|
+
dt = datetime.datetime.fromisoformat(str(newest_ts).replace("Z", "+00:00"))
|
|
115
|
+
except ValueError:
|
|
116
|
+
return False # unreadable timestamp: cannot prove freshness
|
|
117
|
+
age = (datetime.datetime.now(datetime.timezone.utc) - dt).total_seconds()
|
|
118
|
+
if age > max_age_days * 86400:
|
|
119
|
+
return False # stale chain: valid, but no longer current
|
|
120
|
+
return True
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""openshell — the Kamachikuna as NVIDIA OpenShell-compatible policy-as-code.
|
|
2
|
+
|
|
3
|
+
NVIDIA OpenShell (https://github.com/NVIDIA/OpenShell) governs what an agent
|
|
4
|
+
may TOUCH: filesystem, network, process, with declarative YAML policies,
|
|
5
|
+
kernel-level sandboxes, and an OCSF audit trail. The Kamachikuna governs what
|
|
6
|
+
an agent may CLAIM: honesty, receipts, abstention, fail-closed.
|
|
7
|
+
|
|
8
|
+
This module compiles the constitution into OpenShell-reviewable artifacts so
|
|
9
|
+
any OpenShell-governed agent can run under the Kamachikuna:
|
|
10
|
+
|
|
11
|
+
- policy_document(): the 10 laws + 5 prime principles as a declarative,
|
|
12
|
+
version-controllable policy mapping (law -> enforcement domain -> rule).
|
|
13
|
+
- audit_event(): map a khipu receipt to an OCSF-shaped audit record so
|
|
14
|
+
Kamachikuna decisions land in the same audit trail as OpenShell decisions.
|
|
15
|
+
- admission_gate(): Law 6/Law 8 as an OpenShell-style middleware check —
|
|
16
|
+
deny-by-default, receipt-required, fail-closed.
|
|
17
|
+
|
|
18
|
+
Doctrine v11. Every emitted artifact carries the doctrine version and the
|
|
19
|
+
law text verbatim from szl.kamachikuna — single source of truth, no drift.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import datetime as _dt
|
|
25
|
+
import hashlib
|
|
26
|
+
import json
|
|
27
|
+
|
|
28
|
+
from . import kamachikuna
|
|
29
|
+
|
|
30
|
+
DOCTRINE_VERSION = "v11"
|
|
31
|
+
|
|
32
|
+
# Law -> OpenShell policy domain. OpenShell enforces fs/net/process; the
|
|
33
|
+
# Kamachikuna layers claim-governance on top of the same deny-by-default model.
|
|
34
|
+
LAW_DOMAINS = {
|
|
35
|
+
1: ("harm", "harmless"), # Prime Principle 1 — above all laws
|
|
36
|
+
2: ("honesty", "claim"), # measured honesty, two-axis
|
|
37
|
+
3: ("ayni", "resource"), # every taking gives back
|
|
38
|
+
4: ("seventh-generation", "impact"),
|
|
39
|
+
5: ("tamper-evidence", "audit"), # state changes leave verifiable traces
|
|
40
|
+
6: ("fail-closed", "gate"),
|
|
41
|
+
7: ("receipts", "audit"), # no receipt = UNKNOWN, never a claim
|
|
42
|
+
8: ("abstention", "claim"),
|
|
43
|
+
9: ("no-silent-failure", "runtime"),
|
|
44
|
+
10: ("self-audit", "runtime"),
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Actions that are irreversible (Tier 2 of the autonomy ladder) and therefore
|
|
48
|
+
# human-only under Law 7 — the lean-proven irreversibility theorem.
|
|
49
|
+
IRREVERSIBLE_ACTIONS = frozenset({
|
|
50
|
+
"constitution.amend", "payment.execute", "credential.rotate",
|
|
51
|
+
"human.dismiss", "deployment.production-delete",
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def law_rules() -> list[dict]:
|
|
56
|
+
"""Each law as a declarative rule: id, domain, text, enforcement."""
|
|
57
|
+
rules = []
|
|
58
|
+
for n, text in kamachikuna.LAWS.items():
|
|
59
|
+
domain, kind = LAW_DOMAINS[n]
|
|
60
|
+
rules.append({
|
|
61
|
+
"id": f"kamachikuna.law{n}",
|
|
62
|
+
"domain": domain,
|
|
63
|
+
"kind": kind,
|
|
64
|
+
"effect": "deny-by-default" if n in (6, 8) else "enforce",
|
|
65
|
+
"text": text,
|
|
66
|
+
"lean_proven": any(
|
|
67
|
+
p.split(".")[-1].startswith(f"law{n}_")
|
|
68
|
+
for p in kamachikuna.LEAN_PROVEN
|
|
69
|
+
),
|
|
70
|
+
})
|
|
71
|
+
return rules
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def policy_document() -> dict:
|
|
75
|
+
"""The constitution as an OpenShell-reviewable policy document.
|
|
76
|
+
|
|
77
|
+
Version-controllable, hash-stamped, single-sourced from szl.kamachikuna.
|
|
78
|
+
"""
|
|
79
|
+
doc = {
|
|
80
|
+
"apiVersion": "kamachikuna.szl/v1",
|
|
81
|
+
"kind": "AgentConstitution",
|
|
82
|
+
"metadata": {
|
|
83
|
+
"name": "kamachikuna",
|
|
84
|
+
"doctrine": DOCTRINE_VERSION,
|
|
85
|
+
"primePrinciples": list(kamachikuna.PRIME_PRINCIPLES.values()),
|
|
86
|
+
"amendments": list(kamachikuna.AMENDMENTS.values()),
|
|
87
|
+
"leanProven": list(kamachikuna.LEAN_PROVEN),
|
|
88
|
+
},
|
|
89
|
+
"spec": {
|
|
90
|
+
"default": "deny", # Law 6 — fail closed
|
|
91
|
+
"rules": law_rules(),
|
|
92
|
+
"irreversibleActions": sorted(IRREVERSIBLE_ACTIONS),
|
|
93
|
+
"irreversiblePolicy": "human-only", # Law 7, lean-proven
|
|
94
|
+
},
|
|
95
|
+
}
|
|
96
|
+
doc["metadata"]["sha256"] = hashlib.sha256(
|
|
97
|
+
json.dumps(doc, sort_keys=True, separators=(",", ":")).encode()
|
|
98
|
+
).hexdigest()
|
|
99
|
+
return doc
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def admission_gate(action: str, verified: bool, *, receipt: dict | None = None,
|
|
103
|
+
irreversible: bool | None = None) -> dict:
|
|
104
|
+
"""Law 6 + Law 7 + Law 8 as one OpenShell-style middleware decision.
|
|
105
|
+
|
|
106
|
+
Deny-by-default. An ALLOWED decision always carries the governing laws
|
|
107
|
+
and the receipt hash (Law 7). Irreversible actions are human-only.
|
|
108
|
+
"""
|
|
109
|
+
_, verdict = kamachikuna.gate(action, verified)
|
|
110
|
+
irr = action in IRREVERSIBLE_ACTIONS if irreversible is None else irreversible
|
|
111
|
+
laws = [6]
|
|
112
|
+
if irr:
|
|
113
|
+
laws.append(7)
|
|
114
|
+
verdict = "BLOCKED" # irreversible needs a human, not a gate
|
|
115
|
+
if receipt is None:
|
|
116
|
+
laws.append(7)
|
|
117
|
+
if verdict == "ALLOWED":
|
|
118
|
+
verdict = "BLOCKED" # no receipt = no claim = no allow
|
|
119
|
+
return {
|
|
120
|
+
"action": action,
|
|
121
|
+
"decision": verdict,
|
|
122
|
+
"laws": laws,
|
|
123
|
+
"receiptSha256": (
|
|
124
|
+
receipt.get("sha256") if isinstance(receipt, dict) else None
|
|
125
|
+
),
|
|
126
|
+
"reason": (
|
|
127
|
+
"irreversible: human-only (Law 7)" if irr and verdict == "BLOCKED"
|
|
128
|
+
else "unverified: fail closed (Law 6)" if verdict == "BLOCKED"
|
|
129
|
+
else "verified with receipt"
|
|
130
|
+
),
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def audit_event(decision: dict) -> dict:
|
|
135
|
+
"""Map a gate decision to an OCSF-shaped audit record.
|
|
136
|
+
|
|
137
|
+
OpenShell writes OCSF audit events; this makes Kamachikuna decisions
|
|
138
|
+
legible in the same trail — one audit plane for touch and claim.
|
|
139
|
+
"""
|
|
140
|
+
return {
|
|
141
|
+
"class": "application_activity",
|
|
142
|
+
"activity": 6, # authorized / denied per decision
|
|
143
|
+
"authorized": decision["decision"] == "ALLOWED",
|
|
144
|
+
"action": decision["action"],
|
|
145
|
+
"metadata": {
|
|
146
|
+
"doctrine": DOCTRINE_VERSION,
|
|
147
|
+
"laws": decision["laws"],
|
|
148
|
+
"receiptSha256": decision["receiptSha256"],
|
|
149
|
+
"reason": decision["reason"],
|
|
150
|
+
},
|
|
151
|
+
"time": _dt.datetime.now(_dt.timezone.utc).isoformat(),
|
|
152
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""provenance — the Korea/Naver bar as a machine-checkable badge.
|
|
2
|
+
|
|
3
|
+
A model claims provenance only when the evidence is present and bound.
|
|
4
|
+
States are honest: UNTRAINED, CARD_ONLY, MEASURED, UNAVAILABLE, NOT_CLAIMED.
|
|
5
|
+
Verification proves integrity and origin of the evidence — never accuracy
|
|
6
|
+
or performance of the model.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from . import khipu
|
|
14
|
+
|
|
15
|
+
BADGE_KIND = "szl.provenance-badge/v1"
|
|
16
|
+
|
|
17
|
+
STATES = ("UNTRAINED", "CARD_ONLY", "MEASURED", "UNAVAILABLE", "NOT_CLAIMED")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class ProvenanceClaim:
|
|
22
|
+
"""What a model card claims, with the evidence that must back it."""
|
|
23
|
+
model_id: str
|
|
24
|
+
source_sha: str | None = None # canonical GitHub revision trained from
|
|
25
|
+
training_receipt: dict[str, Any] | None = None # signed khipu receipt
|
|
26
|
+
datasets: dict[str, str] = field(default_factory=dict) # name -> sha256
|
|
27
|
+
|
|
28
|
+
def state(self, secret: str | None = None) -> str:
|
|
29
|
+
if self.training_receipt is None:
|
|
30
|
+
return "CARD_ONLY" if self.source_sha else "UNTRAINED"
|
|
31
|
+
# NO SECRET = CANNOT VERIFY = NEVER MEASURED (Law 6: fail closed)
|
|
32
|
+
if secret is None:
|
|
33
|
+
return "UNAVAILABLE"
|
|
34
|
+
if not khipu.check(self.training_receipt, secret):
|
|
35
|
+
return "UNAVAILABLE" # unverifiable receipt = UNAVAILABLE, never MEASURED
|
|
36
|
+
if not self.source_sha or not self.datasets:
|
|
37
|
+
return "UNAVAILABLE"
|
|
38
|
+
return "MEASURED"
|
|
39
|
+
|
|
40
|
+
def badge(self, secret: str | None = None) -> dict[str, Any]:
|
|
41
|
+
"""Mint the provenance badge. Honest states only, never a guess."""
|
|
42
|
+
state = self.state(secret)
|
|
43
|
+
body = {
|
|
44
|
+
"kind": BADGE_KIND,
|
|
45
|
+
"model_id": self.model_id,
|
|
46
|
+
"state": state,
|
|
47
|
+
"source_sha": self.source_sha,
|
|
48
|
+
"datasets": self.datasets,
|
|
49
|
+
"note": "Verification proves integrity and origin, never accuracy or performance.",
|
|
50
|
+
}
|
|
51
|
+
if secret is None:
|
|
52
|
+
return body # unsigned inspection badge
|
|
53
|
+
return khipu.mint(body, secret)
|
szl-0.1.0/szl/router.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""router — the two-axis Truth Router client.
|
|
2
|
+
|
|
3
|
+
Axis 1: measured honesty (census abstention + proving-ground badges).
|
|
4
|
+
Axis 2: cost (joules/token where MEASURED, price otherwise — never zero
|
|
5
|
+
for an unmeasured quantity).
|
|
6
|
+
|
|
7
|
+
Routing rule (Honesty Gate, from the ADAP-Khipu bridge): honesty-critical
|
|
8
|
+
tasks NEVER route to a model whose honesty state is UNAVAILABLE or FAILED,
|
|
9
|
+
even if it is the cheapest or most capable. Fail closed.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from dataclasses import dataclass
|
|
14
|
+
|
|
15
|
+
HONESTY_STATES = ("MEASURED", "UNMEASURED", "FAILED")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class Model:
|
|
20
|
+
model_id: str
|
|
21
|
+
honesty_state: str # HONESTY_STATES
|
|
22
|
+
abstain_rate: float | None # census: abstentions / total, None if unmeasured
|
|
23
|
+
prove_badge: str | None # proving-ground badge or None
|
|
24
|
+
joules_per_token: float | None # MEASURED only; never fabricated
|
|
25
|
+
price_per_mtok: float | None
|
|
26
|
+
|
|
27
|
+
def honesty_score(self) -> float | None:
|
|
28
|
+
"""None means UNKNOWN — never collapse to zero."""
|
|
29
|
+
if self.honesty_state != "MEASURED" or self.abstain_rate is None:
|
|
30
|
+
return None
|
|
31
|
+
return self.abstain_rate
|
|
32
|
+
|
|
33
|
+
def cost_per_mtok(self) -> float | None:
|
|
34
|
+
"""Price axis only. Joules are a SEPARATE axis — never summed with
|
|
35
|
+
dollars (units differ); the router reports both, prices on one."""
|
|
36
|
+
return self.price_per_mtok
|
|
37
|
+
|
|
38
|
+
def energy_per_mtok_joules(self) -> float | None:
|
|
39
|
+
"""Energy axis. None = UNAVAILABLE, never zero."""
|
|
40
|
+
if self.honesty_state != "MEASURED":
|
|
41
|
+
return None # an unmeasured model's energy is unknown, not zero
|
|
42
|
+
return None if self.joules_per_token is None else self.joules_per_token * 1e6
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def route(task_kind: str, models: list[Model]) -> Model | None:
|
|
46
|
+
"""Pick the honest cheapest on the PRICE axis; report joules separately.
|
|
47
|
+
Honesty-critical tasks fail closed. Ties break toward lower MEASURED
|
|
48
|
+
energy; UNMEASURED energy never counts as zero."""
|
|
49
|
+
eligible = [m for m in models if m.honesty_state == "MEASURED"]
|
|
50
|
+
if task_kind == "honesty-critical" and not eligible:
|
|
51
|
+
return None # fail closed: no honest model, no routing
|
|
52
|
+
pool = eligible or models
|
|
53
|
+
priced = [m for m in pool if m.cost_per_mtok() is not None]
|
|
54
|
+
if not priced:
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
def sort_key(m: Model):
|
|
58
|
+
energy = m.energy_per_mtok_joules()
|
|
59
|
+
# measured energy (even zero) sorts BEFORE unknown: known > unknown
|
|
60
|
+
# a model that PROVED zero joules is more honest than one that didn't measure
|
|
61
|
+
return (m.cost_per_mtok(), 1 if energy is None else 0, energy if energy is not None else float("inf"))
|
|
62
|
+
|
|
63
|
+
return min(priced, key=sort_key)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: szl
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The receipts layer for governed AI: khipu signing, the Kamachikuna constitution, provenance badges, and the two-axis Truth Router.
|
|
5
|
+
Author-email: SZL Holdings <stephen@szlholdings.com>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://szlholdings.com/
|
|
8
|
+
Project-URL: Source, https://github.com/szl-holdings/szl-gpu-bridge
|
|
9
|
+
Project-URL: Sponsors, https://szlholdings.com/sponsors.html
|
|
10
|
+
Keywords: ai,governance,provenance,receipts,honesty,khipu,kamachikuna
|
|
11
|
+
Requires-Python: >=3.10
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# szl — the receipts layer for governed AI
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
import sys; sys.path.insert(0, ".") # until published: pip install szl
|
|
18
|
+
from szl import khipu, kamachikuna, provenance, router
|
|
19
|
+
|
|
20
|
+
# 1. Every claim carries a receipt (Law 7)
|
|
21
|
+
r = khipu.mint({"claim": "training completed", "steps": 2000}, secret="…")
|
|
22
|
+
assert khipu.check(r, secret="…") # integrity + origin
|
|
23
|
+
r2 = khipu.mint({"claim": "eval done"}, secret="…", prev_body_sha256=r["body_sha256"])
|
|
24
|
+
assert khipu.check_chain([r, r2], "…", expected_head=r2["body_sha256"])
|
|
25
|
+
|
|
26
|
+
# 2. Fail closed (Law 6)
|
|
27
|
+
assert kamachikuna.gate("deploy", verified=False)[1] == "BLOCKED"
|
|
28
|
+
|
|
29
|
+
# 3. Provenance badge — the Korea/Naver bar, machine-checked
|
|
30
|
+
c = provenance.ProvenanceClaim(model_id="m", source_sha="…", training_receipt=r,
|
|
31
|
+
datasets={"train": "sha256…"})
|
|
32
|
+
badge = c.badge(secret="…") # state: MEASURED | CARD_ONLY | UNTRAINED | UNAVAILABLE
|
|
33
|
+
|
|
34
|
+
# 4. Two-axis Truth Router — honest cheapest, joules reported separately
|
|
35
|
+
pick = router.route("honesty-critical", models) # None if no honest model: fail closed
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Modules
|
|
39
|
+
- **khipu** — signed, hash-chained receipts. Full-length HMAC-SHA256 signatures (never truncated — that was the v1 auditor bug). Tamper, reorder, and truncation detection (truncation via `expected_head`).
|
|
40
|
+
- **kamachikuna** — the constitution: 10 laws, 5 Prime Principles, 5 Lean-proven invariants, 3 amendments, and Law 6 as a callable gate.
|
|
41
|
+
- **provenance** — honest states only: UNTRAINED · CARD_ONLY · MEASURED · UNAVAILABLE · NOT_CLAIMED. Verification proves integrity and origin, never accuracy or performance.
|
|
42
|
+
- **router** — two-axis honesty routing: price axis decides, joules reported separately (never summed with dollars — different units), UNMEASURED energy never counts as zero, honesty-critical tasks fail closed.
|
|
43
|
+
|
|
44
|
+
## The freshness rule
|
|
45
|
+
> "A line older than seven days is a claim, not a fact." — Vidal-Gadea Lab roadmap, Nov 2026
|
|
46
|
+
|
|
47
|
+
`khipu.check_chain(..., max_age_days=7)` fails a chain whose newest receipt is
|
|
48
|
+
older than the window. A stale record that still verifies is worse than no
|
|
49
|
+
record, because it is believed — their lab's cached tracker sat 57 days untouched
|
|
50
|
+
and was read by a program with no error and no warning.
|
|
51
|
+
|
|
52
|
+
## Design debts deliberately not hidden
|
|
53
|
+
- Chain prefixes are internally valid; completeness requires `expected_head` (tamper-evidence ≠ completeness).
|
|
54
|
+
- An unmeasured quantity is None/UNKNOWN everywhere — never zero.
|
|
55
|
+
- Freshness is a separate axis from integrity: a chain can be both valid and stale.
|
|
56
|
+
|
|
57
|
+
Tests: `python3 sdk/tests/test_szl_sdk.py` — 11/11 offline, no network, no GPU.
|
|
58
|
+
|
|
59
|
+
Apache-2.0. Copyright 2026 SZL Holdings · Stephen P. Lutar Jr.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
szl/__init__.py
|
|
4
|
+
szl/kamachikuna.py
|
|
5
|
+
szl/khipu.py
|
|
6
|
+
szl/openshell.py
|
|
7
|
+
szl/provenance.py
|
|
8
|
+
szl/router.py
|
|
9
|
+
szl.egg-info/PKG-INFO
|
|
10
|
+
szl.egg-info/SOURCES.txt
|
|
11
|
+
szl.egg-info/dependency_links.txt
|
|
12
|
+
szl.egg-info/top_level.txt
|
|
13
|
+
tests/test_szl_sdk.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
szl
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Offline tests for the szl SDK. No network, no GPU."""
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
import unittest
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
|
|
8
|
+
|
|
9
|
+
from szl import kamachikuna, khipu, provenance, router # noqa: E402
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class KhipuTests(unittest.TestCase):
|
|
13
|
+
def test_mint_and_check(self):
|
|
14
|
+
r = khipu.mint({"claim": "training completed", "steps": 2000}, secret="s")
|
|
15
|
+
self.assertTrue(khipu.check(r, secret="s"))
|
|
16
|
+
self.assertFalse(khipu.check(r, secret="wrong"))
|
|
17
|
+
self.assertEqual(len(r["signature"]), 64)
|
|
18
|
+
|
|
19
|
+
def test_tamper_detection(self):
|
|
20
|
+
r = khipu.mint({"claim": "x"}, secret="s")
|
|
21
|
+
r2 = dict(r)
|
|
22
|
+
r2["claim"] = {"claim": "y"} # tamper
|
|
23
|
+
self.assertFalse(khipu.check(r2, secret="s"))
|
|
24
|
+
|
|
25
|
+
def test_chain(self):
|
|
26
|
+
secret = "s"
|
|
27
|
+
r1 = khipu.mint({"n": 1}, secret)
|
|
28
|
+
r2 = khipu.mint({"n": 2}, secret, prev_body_sha256=r1["body_sha256"])
|
|
29
|
+
r3 = khipu.mint({"n": 3}, secret, prev_body_sha256=r2["body_sha256"])
|
|
30
|
+
self.assertTrue(khipu.check_chain([r1, r2, r3], secret))
|
|
31
|
+
self.assertFalse(khipu.check_chain([r1, r3, r2], secret)) # reorder
|
|
32
|
+
# a prefix is internally valid; truncation needs the expected head
|
|
33
|
+
self.assertTrue(khipu.check_chain([r1, r2], secret)) # prefix: valid
|
|
34
|
+
self.assertFalse(
|
|
35
|
+
khipu.check_chain([r1, r2], secret, expected_head=r3["body_sha256"])
|
|
36
|
+
) # truncated vs known head
|
|
37
|
+
self.assertTrue(
|
|
38
|
+
khipu.check_chain([r1, r2, r3], secret, expected_head=r3["body_sha256"])
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
def test_truncated_signature_rejected(self):
|
|
42
|
+
r = khipu.mint({"claim": "x"}, secret="s")
|
|
43
|
+
r["signature"] = r["signature"][:48] # the v1 auditor truncation bug
|
|
44
|
+
self.assertFalse(khipu.check(r, secret="s"))
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class FreshnessTests(unittest.TestCase):
|
|
48
|
+
def test_stale_chain_is_not_green(self):
|
|
49
|
+
"""A valid-but-old chain must fail a freshness check. Cached values
|
|
50
|
+
sat 57 days untouched in the Vidal-Gadea tracker and were read with
|
|
51
|
+
no error and no warning."""
|
|
52
|
+
import datetime
|
|
53
|
+
|
|
54
|
+
secret = "s"
|
|
55
|
+
old_ts = (datetime.datetime.now(datetime.timezone.utc)
|
|
56
|
+
- datetime.timedelta(days=30)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
57
|
+
r1 = khipu.mint({"n": 1}, secret, ts=old_ts)
|
|
58
|
+
self.assertTrue(khipu.check_chain([r1], secret)) # integrity: valid
|
|
59
|
+
self.assertFalse(khipu.check_chain([r1], secret, max_age_days=7)) # stale
|
|
60
|
+
fresh = khipu.mint({"n": 2}, secret, prev_body_sha256=r1["body_sha256"])
|
|
61
|
+
self.assertTrue(khipu.check_chain([r1, fresh], secret, max_age_days=7))
|
|
62
|
+
|
|
63
|
+
def test_unreadable_timestamp_fails_freshness(self):
|
|
64
|
+
r = khipu.mint({"n": 1}, "s")
|
|
65
|
+
r["ts"] = "not-a-date"
|
|
66
|
+
# integrity check re-hashes the body, so we cannot tamper ts post-mint;
|
|
67
|
+
# instead verify that a bad ts inside a properly minted receipt fails
|
|
68
|
+
r2 = khipu.mint({"n": 1}, "s")
|
|
69
|
+
self.assertTrue(khipu.check_chain([r2], "s"))
|
|
70
|
+
# mint with a garbage ts and check freshness rejects it
|
|
71
|
+
r3 = khipu.mint({"n": 1}, "s", ts="garbage")
|
|
72
|
+
self.assertFalse(khipu.check_chain([r3], "s", max_age_days=7))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
class KamachikunaTests(unittest.TestCase):
|
|
76
|
+
def test_constants_complete(self):
|
|
77
|
+
self.assertEqual(len(kamachikuna.LAWS), 10)
|
|
78
|
+
self.assertEqual(len(kamachikuna.PRIME_PRINCIPLES), 5)
|
|
79
|
+
self.assertEqual(len(kamachikuna.LEAN_PROVEN), 5)
|
|
80
|
+
self.assertEqual(len(kamachikuna.AMENDMENTS), 3)
|
|
81
|
+
|
|
82
|
+
def test_fail_closed_gate(self):
|
|
83
|
+
self.assertEqual(kamachikuna.gate("deploy", verified=True)[1], "ALLOWED")
|
|
84
|
+
self.assertEqual(kamachikuna.gate("deploy", verified=False)[1], "BLOCKED")
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class ProvenanceTests(unittest.TestCase):
|
|
88
|
+
def test_honest_states(self):
|
|
89
|
+
untrained = provenance.ProvenanceClaim(model_id="m")
|
|
90
|
+
self.assertEqual(untrained.state(), "UNTRAINED")
|
|
91
|
+
card_only = provenance.ProvenanceClaim(model_id="m", source_sha="a" * 40)
|
|
92
|
+
self.assertEqual(card_only.state(), "CARD_ONLY")
|
|
93
|
+
# measured requires a verifiable receipt + source + datasets
|
|
94
|
+
secret = "s"
|
|
95
|
+
receipt = khipu.mint({"kind": "szl.training-receipt/v1"}, secret)
|
|
96
|
+
measured = provenance.ProvenanceClaim(
|
|
97
|
+
model_id="m", source_sha="a" * 40, training_receipt=receipt,
|
|
98
|
+
datasets={"train": "b" * 64},
|
|
99
|
+
)
|
|
100
|
+
self.assertEqual(measured.state(secret), "MEASURED")
|
|
101
|
+
# unverifiable receipt -> UNAVAILABLE, never MEASURED
|
|
102
|
+
self.assertEqual(measured.state("wrong-secret"), "UNAVAILABLE")
|
|
103
|
+
|
|
104
|
+
def test_badge_is_signed(self):
|
|
105
|
+
secret = "s"
|
|
106
|
+
receipt = khipu.mint({"kind": "szl.training-receipt/v1"}, secret)
|
|
107
|
+
c = provenance.ProvenanceClaim(
|
|
108
|
+
model_id="m", source_sha="a" * 40, training_receipt=receipt,
|
|
109
|
+
datasets={"train": "b" * 64},
|
|
110
|
+
)
|
|
111
|
+
badge = c.badge(secret)
|
|
112
|
+
self.assertTrue(khipu.check(badge, secret))
|
|
113
|
+
self.assertEqual(badge["claim"]["state"], "MEASURED")
|
|
114
|
+
# unsigned inspection must NEVER be MEASURED (Law 6)
|
|
115
|
+
unsigned = c.badge(secret=None)
|
|
116
|
+
self.assertEqual(unsigned["state"], "UNAVAILABLE")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class RouterTests(unittest.TestCase):
|
|
120
|
+
def test_honest_cheapest_wins(self):
|
|
121
|
+
models = [
|
|
122
|
+
router.Model("cheap-liar", "FAILED", 0.0, None, None, 0.01),
|
|
123
|
+
router.Model("honest-mid", "MEASURED", 0.9, "PROVE-OR-ABSTAIN-MASTER", 2.0, 1.0),
|
|
124
|
+
router.Model("honest-expensive", "MEASURED", 0.95, None, 1.0, 5.0),
|
|
125
|
+
]
|
|
126
|
+
pick = router.route("eval", models)
|
|
127
|
+
self.assertEqual(pick.model_id, "honest-mid")
|
|
128
|
+
|
|
129
|
+
def test_honesty_critical_fails_closed(self):
|
|
130
|
+
models = [router.Model("cheap-liar", "FAILED", 0.0, None, None, 0.01)]
|
|
131
|
+
self.assertIsNone(router.route("honesty-critical", models))
|
|
132
|
+
# non-critical tasks may still use unmeasured models
|
|
133
|
+
self.assertIsNotNone(router.route("bulk", models))
|
|
134
|
+
|
|
135
|
+
def test_unmeasured_is_none_not_zero(self):
|
|
136
|
+
m = router.Model("m", "UNMEASURED", None, None, None, None)
|
|
137
|
+
self.assertIsNone(m.honesty_score())
|
|
138
|
+
self.assertIsNone(m.cost_per_mtok())
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class TightenedSecurityTests(unittest.TestCase):
|
|
142
|
+
"""Codex review findings: empty receipts, missing timestamps, future timestamps."""
|
|
143
|
+
|
|
144
|
+
def test_empty_receipt_never_verifies(self):
|
|
145
|
+
r = {} # empty receipt — must fail
|
|
146
|
+
self.assertFalse(khipu.check(r, secret="s"))
|
|
147
|
+
|
|
148
|
+
def test_unsigned_receipt_never_measured(self):
|
|
149
|
+
c = provenance.ProvenanceClaim(model_id="m", source_sha="a" * 40,
|
|
150
|
+
training_receipt={"kind": "szl.training-receipt/v1"},
|
|
151
|
+
datasets={"train": "b" * 64})
|
|
152
|
+
# no secret = UNAVAILABLE, never MEASURED
|
|
153
|
+
self.assertEqual(c.state(None), "UNAVAILABLE")
|
|
154
|
+
|
|
155
|
+
def test_missing_timestamp_never_verifies(self):
|
|
156
|
+
r = khipu.mint({"claim": "x"}, secret="s")
|
|
157
|
+
del r["ts"] # remove the timestamp
|
|
158
|
+
self.assertFalse(khipu.check(r, secret="s"))
|
|
159
|
+
|
|
160
|
+
def test_future_timestamp_never_verifies(self):
|
|
161
|
+
import datetime
|
|
162
|
+
future = (datetime.datetime.now(datetime.timezone.utc)
|
|
163
|
+
+ datetime.timedelta(days=1)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
164
|
+
r = khipu.mint({"claim": "x"}, secret="s", ts=future)
|
|
165
|
+
self.assertFalse(khipu.check(r, secret="s"))
|
|
166
|
+
|
|
167
|
+
def test_measured_zero_energy_beats_unknown(self):
|
|
168
|
+
models = [
|
|
169
|
+
router.Model("unknown-energy", "MEASURED", 0.9, None, None, 1.0),
|
|
170
|
+
router.Model("measured-zero", "MEASURED", 0.9, None, 0.0, 1.0),
|
|
171
|
+
]
|
|
172
|
+
pick = router.route("eval", models)
|
|
173
|
+
self.assertEqual(pick.model_id, "measured-zero") # known zero > unknown
|
|
174
|
+
|
|
175
|
+
def test_timezone_free_timestamp_never_verifies(self):
|
|
176
|
+
r = khipu.mint({"claim": "x"}, secret="s")
|
|
177
|
+
r["ts"] = "2026-11-10T07:00:00" # no timezone
|
|
178
|
+
self.assertFalse(khipu.check(r, secret="s"))
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
if __name__ == "__main__":
|
|
182
|
+
unittest.main(verbosity=2)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class OpenShellPolicyTests(unittest.TestCase):
|
|
186
|
+
"""Kamachikuna as OpenShell-reviewable policy-as-code."""
|
|
187
|
+
|
|
188
|
+
def setUp(self):
|
|
189
|
+
from szl import openshell
|
|
190
|
+
self.os_ = openshell
|
|
191
|
+
|
|
192
|
+
def test_policy_document_is_deterministic_and_hashed(self):
|
|
193
|
+
d1 = self.os_.policy_document()
|
|
194
|
+
d2 = self.os_.policy_document()
|
|
195
|
+
self.assertEqual(d1, d2) # version-controllable: byte-stable
|
|
196
|
+
self.assertEqual(d1["spec"]["default"], "deny") # Law 6
|
|
197
|
+
self.assertEqual(len(d1["spec"]["rules"]), 10)
|
|
198
|
+
self.assertTrue(all("sha256" in d1["metadata"] for _ in [1]))
|
|
199
|
+
|
|
200
|
+
def test_laws_single_sourced(self):
|
|
201
|
+
doc = self.os_.policy_document()
|
|
202
|
+
texts = [r["text"] for r in doc["spec"]["rules"]]
|
|
203
|
+
from szl import kamachikuna
|
|
204
|
+
self.assertEqual(sorted(texts), sorted(kamachikuna.LAWS.values()))
|
|
205
|
+
|
|
206
|
+
def test_lean_proven_flags_are_true_only_for_proven_laws(self):
|
|
207
|
+
doc = self.os_.policy_document()
|
|
208
|
+
proven = [r["id"] for r in doc["spec"]["rules"] if r["lean_proven"]]
|
|
209
|
+
# laws 1,4,5,7,9 have Lean-proven theorems
|
|
210
|
+
self.assertEqual(proven, ["kamachikuna.law%d" % n for n in (1, 4, 5, 7, 9)])
|
|
211
|
+
|
|
212
|
+
def test_gate_fails_closed(self):
|
|
213
|
+
d = self.os_.admission_gate("train.launch", verified=False)
|
|
214
|
+
self.assertEqual(d["decision"], "BLOCKED")
|
|
215
|
+
self.assertIn(6, d["laws"])
|
|
216
|
+
self.assertIn("fail closed", d["reason"])
|
|
217
|
+
|
|
218
|
+
def test_allow_requires_receipt(self):
|
|
219
|
+
# verified but no receipt -> Law 7 blocks the claim
|
|
220
|
+
d = self.os_.admission_gate("train.launch", verified=True, receipt=None)
|
|
221
|
+
self.assertEqual(d["decision"], "BLOCKED")
|
|
222
|
+
self.assertIn(7, d["laws"])
|
|
223
|
+
# with a receipt -> allowed
|
|
224
|
+
d2 = self.os_.admission_gate("train.launch", verified=True,
|
|
225
|
+
receipt={"sha256": "ab" * 32})
|
|
226
|
+
self.assertEqual(d2["decision"], "ALLOWED")
|
|
227
|
+
self.assertEqual(d2["receiptSha256"], "ab" * 32)
|
|
228
|
+
|
|
229
|
+
def test_irreversible_actions_are_human_only(self):
|
|
230
|
+
d = self.os_.admission_gate("payment.execute", verified=True,
|
|
231
|
+
receipt={"sha256": "cd" * 32})
|
|
232
|
+
self.assertEqual(d["decision"], "BLOCKED") # Law 7: human-only
|
|
233
|
+
self.assertIn(7, d["laws"])
|
|
234
|
+
self.assertIn("human-only", d["reason"])
|
|
235
|
+
|
|
236
|
+
def test_audit_event_is_ocsf_shaped(self):
|
|
237
|
+
d = self.os_.admission_gate("train.launch", verified=False)
|
|
238
|
+
ev = self.os_.audit_event(d)
|
|
239
|
+
self.assertEqual(ev["class"], "application_activity")
|
|
240
|
+
self.assertFalse(ev["authorized"])
|
|
241
|
+
self.assertEqual(ev["metadata"]["doctrine"], "v11")
|