Align version=1 with the strict Lambda v0.2.0 source

#2
by betterwithage - opened
build.toml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ [general]
2
+ name = "szl_lambda_gate"
3
+
4
+ [torch]
5
+ universal = true
build/torch-cpu/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .szl_lambda_gate import * # noqa: F401,F403
2
+ from .szl_lambda_gate import __all__
build/torch-cpu/metadata.json CHANGED
@@ -1,10 +1 @@
1
- {
2
- "name": "szl-lambda-gate",
3
- "id": "_szl_lambda_gate_cpu_9cf02fddf8",
4
- "version": 1,
5
- "license": "Apache-2.0",
6
- "python-depends": [],
7
- "backend": {
8
- "type": "cpu"
9
- }
10
- }
 
1
+ {"backend":{"type":"cpu"},"digest":{"algorithm":"sha256","files":{"__init__.py":"NuinjlWRNlWgg0y2D61HEaKtW/VOktRHP8w2Nj3opjQ=","szl_lambda_gate/__init__.py":"QpfkkacuKUGxXitqBYLq0nM4NnCsX7uNFOLHbeye0V0=","szl_lambda_gate/_lambda.py":"+VOjgBnJGm+oqcQR9VuqT18rnnbXFTu6VLuKXZRprzg=","szl_lambda_gate/_ops.py":"at8dxC56nm2pFOME2pcgQ45ZwjQQThHz5cyqRezuI7Y=","szl_lambda_gate/_v1.py":"msLY/gpH/xkeunbmKx6d2bK1T2S6DD2GMG4M3Vi8Row=","szl_lambda_gate/governed_norm/__init__.py":"UP5PsJoWXQrpp4Hw7zUVOIx1KhTN6V9zaHhU9Zp9+tw=","szl_lambda_gate/governed_norm/_norm.py":"z3Ks4oHshsUEQm914j7r22YaHjoS5N/MbIufpjSwOUI=","szl_lambda_gate/governed_norm/_receipt.py":"2xJEvRhK/9ypKb04rHKLJpb4KtVlqvgtFMo4RdTXSKk=","szl_lambda_gate/governed_norm/layers.py":"15yDNVyyMyudDp2YWEuGQ05IZTLifTBlLfEBWLMPw3s=","szl_lambda_gate/layers.py":"UdpHjhhe5NFtqplxvcvc/LsMDFt4N6ACuXzQXLlo6nU="}},"id":"_szl_lambda_gate_cpu_7cb79cba7ecb5dbb9da59b2d6b516a98d2a114d6","license":"Apache-2.0","name":"szl-lambda-gate","python-depends":[],"source":"https://github.com/szl-holdings/szl-lambda-gate","universal":false,"version":1}
 
 
 
 
 
 
 
 
 
build/torch-cpu/szl_lambda_gate/__init__.py CHANGED
@@ -1,172 +1,216 @@
1
- # SPDX-License-Identifier: Apache-2.0
2
- # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
- """szl_lambda_gate — the Lambda-Spine aggregator (Λ) as a universal kernel.
4
-
5
- A pure-PyTorch (universal) kernel from SZL Holdings for the Hugging Face
6
- Kernel Hub. It ports the canonical Λ aggregator into a differentiable,
7
- torch.compile-friendly torch op:
8
-
9
- Λ(x) = ∏ xᵢ^{wᵢ}, Σwᵢ = 1, wᵢ > 0, xᵢ ∈ [0,1] (weighted geometric mean)
10
-
11
- plus an ADVISORY governance gate (Λ vs threshold), the four carried axioms as
12
- real runtime self-checks, and pure nn.Module layers.
13
-
14
- Load from the Hub:
15
-
16
- import torch
17
- from kernels import get_kernel
18
-
19
- lg = get_kernel("SZLHOLDINGS/szl-lambda-gate")
20
- axes = torch.tensor([0.9, 0.8, 0.95]) # axis scores in [0,1]
21
- score = lg.lambda_aggregate(axes) # Λ(x) ∈ [0,1]
22
- res = lg.lambda_gate(axes, threshold=0.5) # ADVISORY pass/fail
23
- print(res.score, res.passed, res.advisory)
24
-
25
- WHAT Λ IS / IS NOT (HONESTY — SZL Holdings doctrine v11):
26
- Λ is the weighted-geometric-mean aggregator — a non-compensatory, ADVISORY
27
- way to roll axis scores in [0,1] into one number (any zeroed axis zeroes the
28
- aggregate). It is NOT "proven trust" and NOT a closed theorem: Λ-uniqueness
29
- remains Conjecture 1 (OPEN — an unresolved CAUCHY_ND step plus a missing
30
- symmetry axiom). Label it honestly everywhere; a gate "pass" is advisory.
31
-
32
- PROVENANCE: backed by the Lean 4 formalization szl-holdings/lutar-lean
33
- (749 declarations / 14 axioms / 163 tracked sorries),
34
- DOI 10.5281/zenodo.20434308 (lutar-lean). Λ uniqueness = Conjecture 1 (open).
35
- """
36
- from typing import Optional
37
-
38
- import torch
39
-
40
- from . import layers # noqa: F401 (must be importable for Hub layer mapping)
41
- from ._lambda import YUYAY_AXES, YUYAY_FLOORS, LambdaGateResult
42
- from ._lambda import find_axiom_violation as _find_axiom_violation
43
- from ._lambda import is_bounded_by_max as _is_bounded_by_max
44
- from ._lambda import is_egyptian_exact as _is_egyptian_exact
45
- from ._lambda import is_homogeneous as _is_homogeneous
46
- from ._lambda import is_monotone as _is_monotone
47
- from ._lambda import lambda_aggregate as _lambda_aggregate
48
- from ._lambda import lambda_gate as _lambda_gate
49
- from ._lambda import lambda_gate_batch as _lambda_gate_batch
50
- from ._lambda import selfcheck as _selfcheck
51
- from ._lambda import yuyay_weights as _yuyay_weights
52
-
53
- __all__ = [
54
- "lambda_aggregate",
55
- "lambda_gate",
56
- "lambda_gate_batch",
57
- "LambdaGateResult",
58
- "is_monotone",
59
- "is_egyptian_exact",
60
- "is_bounded_by_max",
61
- "is_homogeneous",
62
- "find_axiom_violation",
63
- "selfcheck",
64
- "yuyay_weights",
65
- "YUYAY_AXES",
66
- "YUYAY_FLOORS",
67
- "layers",
68
- "DOCTRINE_FOOTER",
69
- "PROVENANCE",
70
- "__version__",
71
- ]
72
-
73
- __version__ = "0.2.0"
74
- DOCTRINE_FOOTER = (
75
- "SZL Holdings · Λ = Conjecture 1 (ADVISORY, weighted geometric mean) · "
76
- "uniqueness OPEN · NOT proven trust · honesty over checklist"
77
- )
78
- PROVENANCE = {
79
- "lean_repo": "szl-holdings/lutar-lean",
80
- "lean_declarations": 749,
81
- "lean_axioms": 14,
82
- "lean_tracked_sorries": 163,
83
- "doi_lutar_lean": "10.5281/zenodo.20434308",
84
- "lambda_status": "Conjecture 1 (open) — uniqueness unproven; advisory only",
85
- }
86
-
87
-
88
- def lambda_aggregate(
89
- axes: torch.Tensor,
90
- weights: Optional[torch.Tensor] = None,
91
- ) -> torch.Tensor:
92
- """Λ(x) = ∏ xᵢ^{wᵢ}, the weighted geometric mean over the last dim of axes.
93
-
94
- See ``szl_lambda_gate._lambda.lambda_aggregate``. Axis scores in [0,1],
95
- uniform weights when ``weights`` is None. Differentiable, batched, and
96
- torch.compile-friendly. ADVISORY — NOT proven trust.
97
- """
98
- return _lambda_aggregate(axes, weights=weights)
99
-
100
-
101
- def lambda_gate(
102
- axes: torch.Tensor,
103
- weights: Optional[torch.Tensor] = None,
104
- threshold: float = 0.5,
105
- ) -> LambdaGateResult:
106
- """ADVISORY Λ governance gate: returns LambdaGateResult(score, passed,
107
- threshold, advisory). ``passed`` = Λ(axes) >= threshold. A pass is an
108
- advisory, non-compensatory signal — NOT proven trust (Λ = Conjecture 1).
109
- """
110
- return _lambda_gate(axes, weights=weights, threshold=threshold)
111
-
112
-
113
- def lambda_gate_batch(
114
- candidates: torch.Tensor,
115
- weights: Optional[torch.Tensor] = None,
116
- threshold: float = 0.5,
117
- ) -> LambdaGateResult:
118
- """ADVISORY batch gate over many candidate action-vectors (shape (..., N, k)).
119
-
120
- The realistic per-inference-step call: score all N candidates at once and
121
- return the advisory pass mask. Returns LambdaGateResult(score, passed,
122
- threshold, advisory) with score/passed of shape (..., N). NOT proven trust.
123
- """
124
- return _lambda_gate_batch(candidates, weights=weights, threshold=threshold)
125
-
126
-
127
- def yuyay_weights(dtype: torch.dtype = torch.float64, device=None) -> torch.Tensor:
128
- """Canonical 13-axis Yuyay Λ weight vector (uniform 1/13), ADVISORY only.
129
-
130
- Use as ``weights`` over the 13 ``YUYAY_AXES``. The yuyay_v3 gate is a
131
- conjunctive AND with per-axis floors (``YUYAY_FLOORS``); this Λ roll-up is
132
- the weighted geometric mean and is ADVISORY — NOT proven trust.
133
- """
134
- return _yuyay_weights(dtype=dtype, device=device)
135
-
136
-
137
- def find_axiom_violation(k=5, trials=200, weights=None, seed=0, tol=1e-6):
138
- """Random-search for any A1–A4 violation; returns (axiom, axes, weights) or
139
- None. An honest falsification attempt — finding nothing is evidence, not a
140
- proof (Λ-uniqueness is Conjecture 1, open).
141
- """
142
- return _find_axiom_violation(k=k, trials=trials, weights=weights, seed=seed, tol=tol)
143
-
144
-
145
- def selfcheck(k=5, trials=64, seed=0) -> dict:
146
- """Expose the A1–A4 empirical self-checks + version as a single verdict dict.
147
-
148
- Callable as get_kernel(...).selfcheck(). EMPIRICAL checks on sampled inputs,
149
- NOT a proof of Λ-uniqueness (Conjecture 1, open). Advisory only.
150
- """
151
- return _selfcheck(k=k, trials=trials, seed=seed)
152
-
153
-
154
- # ---- axiom runtime self-checks (real, verifiable; NOT a uniqueness proof) -- #
155
- def is_monotone(axes, weights=None, delta=0.05, tol=1e-7) -> bool:
156
- """A1 IsMonotone self-check: Λ is non-decreasing in each axis (on this data)."""
157
- return _is_monotone(axes, weights=weights, delta=delta, tol=tol)
158
-
159
-
160
- def is_egyptian_exact(c, k=3, weights=None, tol=1e-5) -> bool:
161
- """A3 IsEgyptianExact self-check: Λ(c, …, c) = c."""
162
- return _is_egyptian_exact(c, k=k, weights=weights, tol=tol)
163
-
164
-
165
- def is_bounded_by_max(axes, weights=None, tol=1e-6) -> bool:
166
- """A4 IsBounded self-check: Λ(x) ≤ maxᵢ xᵢ."""
167
- return _is_bounded_by_max(axes, weights=weights, tol=tol)
168
-
169
-
170
- def is_homogeneous(axes, t, weights=None, tol=1e-5) -> bool:
171
- """A2 IsHomogeneous(degree 1) self-check: Λ(t·x) = t·Λ(x)."""
172
- return _is_homogeneous(axes, t, weights=weights, tol=tol)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """szl_lambda_gate — the Lambda-Spine aggregator (Λ) as a universal kernel.
4
+
5
+ A pure-PyTorch (universal) kernel from SZL Holdings for the Hugging Face
6
+ Kernel Hub. It ports the canonical Λ aggregator into a differentiable,
7
+ torch.compile-friendly torch op:
8
+
9
+ Λ(x) = ∏ xᵢ^{wᵢ}, Σwᵢ = 1, wᵢ > 0, xᵢ ∈ [0,1] (weighted geometric mean)
10
+
11
+ plus an ADVISORY governance gate (Λ vs threshold), the four carried axioms as
12
+ real runtime self-checks, and pure nn.Module layers.
13
+
14
+ Load from the Hub:
15
+
16
+ import torch
17
+ from kernels import get_kernel
18
+
19
+ lg = get_kernel("SZLHOLDINGS/szl-lambda-gate")
20
+ axes = torch.tensor([0.9, 0.8, 0.95]) # axis scores in [0,1]
21
+ score = lg.lambda_aggregate(axes) # Λ(x) ∈ [0,1]
22
+ res = lg.lambda_gate(axes, threshold=0.5) # ADVISORY pass/fail
23
+ print(res.score, res.passed, res.advisory)
24
+
25
+ # szl.lambda/v1 strict gate (spec/szl.lambda.v1.json): no clamping, no
26
+ # renormalisation, tau required; bad input -> verdict BLOCK with a code.
27
+ w = torch.tensor([0.4, 0.3, 0.3], dtype=torch.float64)
28
+ v1 = lg.lambda_v1_gate(axes.double(), w, tau=0.8)
29
+ print(v1.verdict, v1.code) # GO / NO_GO / ABSTAIN / BLOCK
30
+
31
+ WHAT Λ IS / IS NOT (HONESTY — SZL Holdings doctrine v11):
32
+ Λ is the weighted-geometric-mean aggregator — a non-compensatory, ADVISORY
33
+ way to roll axis scores in [0,1] into one number (any zeroed axis zeroes the
34
+ aggregate). It is NOT "proven trust" and NOT a closed theorem: Λ-uniqueness
35
+ remains Conjecture 1 (OPEN — an unresolved CAUCHY_ND step plus a missing
36
+ symmetry axiom). Label it honestly everywhere; a gate "pass" is advisory.
37
+
38
+ PROVENANCE: backed by the Lean 4 formalization szl-holdings/lutar-lean
39
+ (749 declarations / 14 axioms / 163 tracked sorries),
40
+ DOI 10.5281/zenodo.20434308 (lutar-lean). Λ uniqueness = Conjecture 1 (open).
41
+ """
42
+ from typing import Optional
43
+
44
+ import torch
45
+
46
+ from . import layers # noqa: F401 (must be importable for Hub layer mapping)
47
+ # CONSOLIDATION (Wave D): the governed-norm universal kernel is folded in here
48
+ # as a subpackage so szl-lambda-gate is the ONE canonical kernels package. The
49
+ # source repo szl-holdings/szl-governed-norm is DEPRECATED and points here;
50
+ # nothing was deleted (additive, reversible copy). Λ stays Conjecture 1.
51
+ from . import governed_norm # noqa: F401 (folded-in governed normalization kernels)
52
+ from ._lambda import YUYAY_AXES, YUYAY_FLOORS, LambdaGateResult
53
+ from ._lambda import _resolve_threshold
54
+ from ._lambda import find_axiom_violation as _find_axiom_violation
55
+ from ._lambda import is_bounded_by_max as _is_bounded_by_max
56
+ from ._lambda import is_egyptian_exact as _is_egyptian_exact
57
+ from ._lambda import is_homogeneous as _is_homogeneous
58
+ from ._lambda import is_monotone as _is_monotone
59
+ from ._lambda import lambda_aggregate as _lambda_aggregate
60
+ from ._lambda import lambda_gate as _lambda_gate
61
+ from ._lambda import lambda_gate_batch as _lambda_gate_batch
62
+ from ._lambda import selfcheck as _selfcheck
63
+ from ._lambda import yuyay_weights as _yuyay_weights
64
+ # szl.lambda/v1 strict entry (spec/szl.lambda.v1.json): validated, coded, tau required.
65
+ from ._v1 import LambdaV1Error, LambdaV1GateResult, lambda_v1, lambda_v1_gate
66
+
67
+ __all__ = [
68
+ "lambda_aggregate",
69
+ "lambda_gate",
70
+ "lambda_gate_batch",
71
+ "LambdaGateResult",
72
+ "lambda_v1",
73
+ "lambda_v1_gate",
74
+ "LambdaV1Error",
75
+ "LambdaV1GateResult",
76
+ "is_monotone",
77
+ "is_egyptian_exact",
78
+ "is_bounded_by_max",
79
+ "is_homogeneous",
80
+ "find_axiom_violation",
81
+ "selfcheck",
82
+ "yuyay_weights",
83
+ "YUYAY_AXES",
84
+ "YUYAY_FLOORS",
85
+ "layers",
86
+ "DOCTRINE_FOOTER",
87
+ "PROVENANCE",
88
+ "__version__",
89
+ # ---- folded-in governed-norm kernels (Wave D consolidation) ----
90
+ "governed_norm",
91
+ "rms_norm",
92
+ "layer_norm",
93
+ "fused_add_rms_norm",
94
+ ]
95
+
96
+ # ---- folded-in governed-norm surface (Wave D consolidation) ---------------- #
97
+ # Convenience top-level re-exports of the governed normalization kernels that
98
+ # were absorbed from szl-governed-norm. The full surface (ReceiptChain,
99
+ # emit_receipt, receipt_* helpers, selfcheck, layers) lives under
100
+ # ``szl_lambda_gate.governed_norm``. These are a DIFFERENT kernel family from Λ
101
+ # (normalization, not the Λ aggregator); Λ itself remains Conjecture 1
102
+ # (advisory, uniqueness OPEN) and is never described as proven trust.
103
+ rms_norm = governed_norm.rms_norm
104
+ layer_norm = governed_norm.layer_norm
105
+ fused_add_rms_norm = governed_norm.fused_add_rms_norm
106
+
107
+ __version__ = "0.2.0"
108
+ DOCTRINE_FOOTER = (
109
+ "SZL Holdings · Λ = Conjecture 1 (ADVISORY, weighted geometric mean) · "
110
+ "uniqueness OPEN · NOT proven trust · honesty over checklist"
111
+ )
112
+ PROVENANCE = {
113
+ "lean_repo": "szl-holdings/lutar-lean",
114
+ "lean_declarations": 749,
115
+ "lean_axioms": 14,
116
+ "lean_tracked_sorries": 163,
117
+ "doi_lutar_lean": "10.5281/zenodo.20434308",
118
+ "lambda_status": "Conjecture 1 (open) — uniqueness unproven; advisory only",
119
+ }
120
+
121
+
122
+ def lambda_aggregate(
123
+ axes: torch.Tensor,
124
+ weights: Optional[torch.Tensor] = None,
125
+ ) -> torch.Tensor:
126
+ """Λ(x) = ∏ xᵢ^{wᵢ}, the weighted geometric mean over the last dim of axes.
127
+
128
+ See ``szl_lambda_gate._lambda.lambda_aggregate``. Axis scores in [0,1],
129
+ uniform weights when ``weights`` is None. Differentiable, batched, and
130
+ torch.compile-friendly. ADVISORY — NOT proven trust.
131
+ """
132
+ return _lambda_aggregate(axes, weights=weights)
133
+
134
+
135
+ def lambda_gate(
136
+ axes: torch.Tensor,
137
+ weights: Optional[torch.Tensor] = None,
138
+ threshold: Optional[float] = None,
139
+ ) -> LambdaGateResult:
140
+ """ADVISORY Λ governance gate: returns LambdaGateResult(score, passed,
141
+ threshold, advisory). ``passed`` = Λ(axes) >= threshold. ``threshold`` must
142
+ lie within Λ's range [0,1] (a value outside it is a misconfiguration — a
143
+ negative threshold would advisory-pass a fully-failing Λ=0 candidate — and
144
+ is rejected). Omitting it uses the legacy 0.5 with a DeprecationWarning
145
+ (policy_tau is 0.8); pass it, or use ``lambda_v1_gate(axes, weights, tau)``.
146
+ A pass is an advisory, non-compensatory signal — NOT proven trust
147
+ (Λ = Conjecture 1).
148
+ """
149
+ threshold = _resolve_threshold(threshold, stacklevel=2)
150
+ return _lambda_gate(axes, weights=weights, threshold=threshold)
151
+
152
+
153
+ def lambda_gate_batch(
154
+ candidates: torch.Tensor,
155
+ weights: Optional[torch.Tensor] = None,
156
+ threshold: Optional[float] = None,
157
+ ) -> LambdaGateResult:
158
+ """ADVISORY batch gate over many candidate action-vectors (shape (..., N, k)).
159
+
160
+ The realistic per-inference-step call: score all N candidates at once and
161
+ return the advisory pass mask. Returns LambdaGateResult(score, passed,
162
+ threshold, advisory) with score/passed of shape (..., N). ``threshold``
163
+ must lie within Λ's range [0,1] (same domain guard as ``lambda_gate``);
164
+ omitting it uses the legacy 0.5 with a DeprecationWarning.
165
+ NOT proven trust.
166
+ """
167
+ threshold = _resolve_threshold(threshold, stacklevel=2)
168
+ return _lambda_gate_batch(candidates, weights=weights, threshold=threshold)
169
+
170
+
171
+ def yuyay_weights(dtype: torch.dtype = torch.float64, device=None) -> torch.Tensor:
172
+ """Canonical 13-axis Yuyay Λ weight vector (uniform 1/13), ADVISORY only.
173
+
174
+ Use as ``weights`` over the 13 ``YUYAY_AXES``. The yuyay_v3 gate is a
175
+ conjunctive AND with per-axis floors (``YUYAY_FLOORS``); this Λ roll-up is
176
+ the weighted geometric mean and is ADVISORY — NOT proven trust.
177
+ """
178
+ return _yuyay_weights(dtype=dtype, device=device)
179
+
180
+
181
+ def find_axiom_violation(k=5, trials=200, weights=None, seed=0, tol=1e-6):
182
+ """Random-search for any A1–A4 violation; returns (axiom, axes, weights) or
183
+ None. An honest falsification attempt — finding nothing is evidence, not a
184
+ proof (Λ-uniqueness is Conjecture 1, open).
185
+ """
186
+ return _find_axiom_violation(k=k, trials=trials, weights=weights, seed=seed, tol=tol)
187
+
188
+
189
+ def selfcheck(k=5, trials=64, seed=0) -> dict:
190
+ """Expose the A1–A4 empirical self-checks + version as a single verdict dict.
191
+
192
+ Callable as get_kernel(...).selfcheck(). EMPIRICAL checks on sampled inputs,
193
+ NOT a proof of Λ-uniqueness (Conjecture 1, open). Advisory only.
194
+ """
195
+ return _selfcheck(k=k, trials=trials, seed=seed)
196
+
197
+
198
+ # ---- axiom runtime self-checks (real, verifiable; NOT a uniqueness proof) -- #
199
+ def is_monotone(axes, weights=None, delta=0.05, tol=1e-7) -> bool:
200
+ """A1 IsMonotone self-check: Λ is non-decreasing in each axis (on this data)."""
201
+ return _is_monotone(axes, weights=weights, delta=delta, tol=tol)
202
+
203
+
204
+ def is_egyptian_exact(c, k=3, weights=None, tol=1e-5) -> bool:
205
+ """A3 IsEgyptianExact self-check: Λ(c, …, c) = c."""
206
+ return _is_egyptian_exact(c, k=k, weights=weights, tol=tol)
207
+
208
+
209
+ def is_bounded_by_max(axes, weights=None, tol=1e-6) -> bool:
210
+ """A4 IsBounded self-check: Λ(x) ≤ maxᵢ xᵢ."""
211
+ return _is_bounded_by_max(axes, weights=weights, tol=tol)
212
+
213
+
214
+ def is_homogeneous(axes, t, weights=None, tol=1e-5) -> bool:
215
+ """A2 IsHomogeneous(degree 1) self-check: Λ(t·x) = t·Λ(x)."""
216
+ return _is_homogeneous(axes, t, weights=weights, tol=tol)
build/torch-cpu/szl_lambda_gate/_lambda.py CHANGED
@@ -1,313 +1,556 @@
1
- # SPDX-License-Identifier: Apache-2.0
2
- # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
- """Pure-PyTorch Lambda-Spine aggregator (Λ) for the szl-lambda-gate kernel.
4
-
5
- Λ(x) = ∏ xᵢ^{wᵢ}, Σwᵢ = 1, wᵢ > 0, xᵢ ∈ [0,1] (weighted geometric mean)
6
-
7
- This is a TORCH port of the canonical pure-Python reference. It is a
8
- correctness reference, computed via logs in float32 for stability,
9
- differentiable (autograd works), and torch.compile-friendly. Depends ONLY on
10
- torch + the Python standard library (a Kernel Hub requirement for universal
11
- kernels).
12
-
13
- WHAT Λ IS / IS NOT (HONESTY — SZL Holdings doctrine v11):
14
- Λ is the *weighted-geometric-mean aggregator*: a non-compensatory way to
15
- combine axis scores in [0,1] into one number. It is an ADVISORY governance
16
- signal — a conservative roll-up where any single zeroed axis drives the
17
- aggregate to 0. It is NOT "proven trust" and NOT a closed theorem. Its
18
- *uniqueness* remains Conjecture 1 — OPEN (an unresolved CAUCHY_ND step plus a
19
- missing symmetry axiom in the Lean development). Do not describe Λ as proven
20
- trust anywhere.
21
-
22
- PRIOR ART (honest attribution): the weighted geometric mean as a less-
23
- compensatory composite-indicator aggregator is established practice — the UN
24
- HDI (arithmetic→geometric switch, 2010) and the OECD Handbook on Constructing
25
- Composite Indicators (2008) both use it to limit the compensation effect. The
26
- veto / cut-off idea (a single failing criterion blocks a pass) is the ELECTRE
27
- veto threshold. The 13-axis conjunctive form (yuyay_weights) is SZL's own
28
- yuyay_v3 gate. None of this makes Λ "proven trust"; the gate is ADVISORY.
29
-
30
- PROVENANCE: backed by the Lean 4 formalization szl-holdings/lutar-lean
31
- (749 declarations / 14 axioms / 163 tracked sorries),
32
- DOI 10.5281/zenodo.20434308 (lutar-lean). Λ uniqueness = Conjecture 1 (open).
33
-
34
- Axioms carried (Lutar/Axioms.lean), available below as runtime self-checks:
35
- A1 IsMonotone — Λ is non-decreasing in each axis
36
- A2 IsHomogeneous — Λ(t·x) = t·Λ(x) (degree 1)
37
- A3 IsEgyptianExact — Λ(c,…,c) = c (the uniform-diagonal fixpoint)
38
- A4 IsBounded(by max) — Λ(x) ≤ maxᵢ xᵢ
39
- """
40
- from typing import Optional
41
-
42
- import torch
43
-
44
- _SUPPORTED_DTYPES = (torch.float16, torch.bfloat16, torch.float32, torch.float64)
45
-
46
-
47
- def _compute_dtype(in_dtype: torch.dtype) -> torch.dtype:
48
- return torch.float32 if in_dtype in (torch.float16, torch.bfloat16) else in_dtype
49
-
50
-
51
- def _check_axes(axes: torch.Tensor) -> None:
52
- """Cheap, allocation-free metadata guards on the axis-score tensor."""
53
- if not isinstance(axes, torch.Tensor):
54
- raise TypeError(f"axes must be a torch.Tensor, got {type(axes).__name__}")
55
- if axes.dtype not in _SUPPORTED_DTYPES:
56
- raise TypeError(
57
- f"axes has unsupported dtype {axes.dtype}; "
58
- f"expected one of {tuple(str(d) for d in _SUPPORTED_DTYPES)}"
59
- )
60
- if axes.dim() < 1:
61
- raise ValueError(
62
- "axes must have at least 1 dimension (the k axis scores live on "
63
- f"the last dim); got a {axes.dim()}-d tensor"
64
- )
65
- if axes.shape[-1] < 1:
66
- raise ValueError("axes last dimension (k = number of axes) must be >= 1")
67
-
68
-
69
- def _resolve_weights(
70
- axes: torch.Tensor,
71
- weights: Optional[torch.Tensor],
72
- cdt: torch.dtype,
73
- ) -> torch.Tensor:
74
- """Return a normalized (Σw = 1) weight vector of shape (k,) in compute dtype."""
75
- k = axes.shape[-1]
76
- if weights is None:
77
- return torch.full((k,), 1.0 / k, dtype=cdt, device=axes.device)
78
- if not isinstance(weights, torch.Tensor):
79
- raise TypeError(f"weights must be a torch.Tensor or None, got {type(weights).__name__}")
80
- if weights.device != axes.device:
81
- raise ValueError(
82
- f"weights is on device {weights.device} but axes is on {axes.device}; "
83
- "move them to the same device"
84
- )
85
- if weights.dim() != 1 or weights.shape[0] != k:
86
- raise ValueError(
87
- f"weights must be 1-D with shape ({k},) to match the last dim of axes; "
88
- f"got shape {tuple(weights.shape)}"
89
- )
90
- wf = weights.to(cdt)
91
- if not bool(torch.all(torch.isfinite(wf))):
92
- raise ValueError("weights must all be finite (no NaN/Inf)")
93
- if bool(torch.any(wf <= 0.0)):
94
- raise ValueError("weights must be strictly positive (wᵢ > 0)")
95
- sw = wf.sum()
96
- if not bool(sw > 0.0):
97
- raise ValueError("weights must sum to a positive value")
98
- return wf / sw
99
-
100
-
101
- def lambda_aggregate(
102
- axes: torch.Tensor,
103
- weights: Optional[torch.Tensor] = None,
104
- ) -> torch.Tensor:
105
- """Weighted geometric mean Λ(x) = ∏ xᵢ^{wᵢ} over the last dim of ``axes``.
106
-
107
- Axis scores expected in [0,1] and clamped into [0,1]; uniform weights (1/k)
108
- when ``weights`` is None. Computed via logs for stability:
109
-
110
- Λ(x) = exp( Σᵢ wᵢ · log(clamp(xᵢ, 0, 1)) )
111
-
112
- Non-compensatory zero-routing (A4-consistent): any axis that is zero, OR
113
- that is NON-FINITE (NaN / ±Inf), is treated as a FAILING axis and drives
114
- the whole aggregate to exactly 0. A garbage/invalid axis must never silently
115
- pass as a perfect (clamped-to-1) axis; output and gradient stay finite and
116
- in [0,1] for every input.
117
-
118
- Returns a tensor of shape (...) — Λ(x) ∈ [0,1] per batch row, differentiable
119
- w.r.t. ``axes``.
120
-
121
- HONESTY: a non-compensatory governance roll-up, NOT proven trust.
122
- Λ-uniqueness is Conjecture 1 (open).
123
- """
124
- _check_axes(axes)
125
- in_dtype = axes.dtype
126
- cdt = _compute_dtype(in_dtype)
127
- xf = axes.to(cdt)
128
- w = _resolve_weights(axes, weights, cdt) # (k,), Σw=1
129
-
130
- finite_mask = torch.isfinite(xf)
131
- xc = xf.clamp(0.0, 1.0)
132
- bad_mask = (~finite_mask) | (xc <= 0.0)
133
- any_bad = torch.any(bad_mask, dim=-1) # (...)
134
-
135
- safe = torch.where(bad_mask, torch.ones_like(xc), xc)
136
- logx = torch.log(safe) # (..., k)
137
- acc = (logx * w).sum(dim=-1) # (...)
138
- val = torch.exp(acc) # (...)
139
-
140
- out = torch.where(any_bad, torch.zeros_like(val), val)
141
- out = out.clamp(0.0, 1.0)
142
- return out.to(in_dtype)
143
-
144
-
145
- def lambda_gate(
146
- axes: torch.Tensor,
147
- weights: Optional[torch.Tensor] = None,
148
- threshold: float = 0.5,
149
- ):
150
- """ADVISORY governance gate over Λ(x): score plus a pass/fail vs threshold.
151
-
152
- Returns a :class:`LambdaGateResult` namedtuple (score, passed, threshold,
153
- advisory). ``passed`` := Λ(x) >= threshold; ``advisory`` is always True.
154
-
155
- HONESTY: a "pass" is an ADVISORY signal only. Λ is the weighted-geometric-
156
- mean aggregator; its uniqueness is Conjecture 1 (open). Do not treat a pass
157
- as proven trust or a closed theorem.
158
- """
159
- t = float(threshold)
160
- if t != t or t == float("inf") or t == float("-inf"):
161
- raise ValueError(f"threshold must be a finite float, got {threshold!r}")
162
- score = lambda_aggregate(axes, weights)
163
- passed = score >= t
164
- return LambdaGateResult(score=score, passed=passed, threshold=t, advisory=True)
165
-
166
-
167
- def lambda_gate_batch(
168
- candidates: torch.Tensor,
169
- weights: Optional[torch.Tensor] = None,
170
- threshold: float = 0.5,
171
- ):
172
- """ADVISORY batch gate: score MANY candidate action-vectors in one call.
173
-
174
- ``candidates`` is shape (..., N, k): last dim ``k`` is per-axis scores of one
175
- candidate, the dim before it enumerates the N candidates. Returns a
176
- :class:`LambdaGateResult` with score/passed of shape (..., N).
177
-
178
- HONESTY: the pass mask is ADVISORY, non-compensatory. NOT proven trust;
179
- Λ-uniqueness is Conjecture 1 (open).
180
- """
181
- _check_axes(candidates)
182
- if candidates.dim() < 2:
183
- raise ValueError(
184
- "candidates must be at least 2-D, shape (..., N, k); "
185
- f"got a {candidates.dim()}-d tensor"
186
- )
187
- return lambda_gate(candidates, weights=weights, threshold=threshold)
188
-
189
-
190
- # ---- A1..A4 axiom RUNTIME self-checks (real, verifiable) ------------------- #
191
- def is_egyptian_exact(c, k: int = 3, weights=None, tol: float = 1e-5) -> bool:
192
- """A3 IsEgyptianExact: Λ(c, …, c) = c for a constant axis vector of length k."""
193
- if k < 1:
194
- raise ValueError("k must be >= 1")
195
- cc = min(max(float(c), 0.0), 1.0)
196
- axes = torch.full((k,), cc, dtype=torch.float64)
197
- val = lambda_aggregate(axes, weights)
198
- return bool(torch.abs(val - cc) <= tol)
199
-
200
-
201
- def is_bounded_by_max(axes: torch.Tensor, weights=None, tol: float = 1e-6) -> bool:
202
- """A4 IsBounded: Λ(x) ≤ maxᵢ xᵢ (over the last dim), within ``tol``."""
203
- _check_axes(axes)
204
- val = lambda_aggregate(axes, weights)
205
- xf = axes.to(_compute_dtype(axes.dtype))
206
- xf = torch.where(torch.isfinite(xf), xf, torch.zeros_like(xf))
207
- mx = xf.clamp(0.0, 1.0).amax(dim=-1)
208
- return bool(torch.all(val.to(mx.dtype) <= mx + tol))
209
-
210
-
211
- def is_homogeneous(axes: torch.Tensor, t, weights=None, tol: float = 1e-5) -> bool:
212
- """A2 IsHomogeneous (degree 1): Λ(t·x) = t·Λ(x) for scalar t in [0,1]."""
213
- _check_axes(axes)
214
- tt = min(max(float(t), 0.0), 1.0)
215
- x = axes.to(torch.float64).clamp(0.0, 1.0)
216
- lhs = lambda_aggregate(x * tt, weights)
217
- rhs = tt * lambda_aggregate(x, weights)
218
- return bool(torch.all(torch.abs(lhs - rhs) <= tol))
219
-
220
-
221
- def is_monotone(axes: torch.Tensor, weights=None, delta: float = 0.05, tol: float = 1e-7) -> bool:
222
- """A1 IsMonotone: Λ is non-decreasing in each axis."""
223
- _check_axes(axes)
224
- x = axes.to(torch.float64).clamp(0.0, 1.0)
225
- base = lambda_aggregate(x, weights)
226
- k = x.shape[-1]
227
- ok = True
228
- for j in range(k):
229
- bumped = x.clone()
230
- bumped[..., j] = (bumped[..., j] + float(delta)).clamp(0.0, 1.0)
231
- bumped_val = lambda_aggregate(bumped, weights)
232
- ok = ok and bool(torch.all(bumped_val - base >= -tol))
233
- return ok
234
-
235
-
236
- def find_axiom_violation(k: int = 5, trials: int = 200, weights=None, seed=0, tol: float = 1e-6):
237
- """Random-search for ANY A1–A4 violation. Returns the first violating triple
238
- ``(axiom, axes, weights)`` or ``None``. An honest FALSIFICATION attempt —
239
- finding nothing is empirical evidence, NOT a proof (Λ-uniqueness = Conjecture 1).
240
- """
241
- gen = torch.Generator()
242
- if seed is not None:
243
- gen.manual_seed(int(seed))
244
- for _ in range(int(trials)):
245
- x = torch.rand(k, generator=gen, dtype=torch.float64)
246
- w = weights
247
- if w is None:
248
- w = torch.rand(k, generator=gen, dtype=torch.float64) + 1e-3
249
- c = float(torch.rand(1, generator=gen).item())
250
- if not is_egyptian_exact(c, k=k, weights=w, tol=max(tol, 1e-5)):
251
- return ("A3_IsEgyptianExact", torch.full((k,), c, dtype=torch.float64), w)
252
- if not is_bounded_by_max(x, w, tol=max(tol, 1e-6)):
253
- return ("A4_IsBounded", x, w)
254
- t = float(torch.rand(1, generator=gen).item())
255
- if not is_homogeneous(x, t, weights=w, tol=max(tol, 1e-5)):
256
- return ("A2_IsHomogeneous", x, w)
257
- if not is_monotone(x * 0.9, w, tol=max(tol, 1e-7)):
258
- return ("A1_IsMonotone", x * 0.9, w)
259
- return None
260
-
261
-
262
- # ---- Canonical 13-axis Yuyay preset (ADVISORY ONLY) ------------------------ #
263
- YUYAY_AXES = (
264
- "moralGrounding", "measurabilityHonesty", "empiricalGrounding",
265
- "logicalConsistency", "sourceTransparency", "reproducibility",
266
- "licenseHygiene", "scopeDiscipline", "claimCalibration", "evalAwareness",
267
- "deceptionKeywords", "conflictingDirectives", "reversalDirective",
268
- )
269
- YUYAY_FLOORS = (
270
- 0.95, 0.95,
271
- 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, 0.90,
272
- 0.90, 0.90, 0.90, 0.90,
273
- )
274
-
275
-
276
- def yuyay_weights(dtype: torch.dtype = torch.float64, device=None) -> torch.Tensor:
277
- """Canonical 13-axis Yuyay Λ weight vector (uniform 1/13), ADVISORY only."""
278
- k = len(YUYAY_AXES)
279
- return torch.full((k,), 1.0 / k, dtype=dtype, device=device)
280
-
281
-
282
- def selfcheck(k: int = 5, trials: int = 64, seed=0) -> dict:
283
- """Run the A1–A4 empirical self-checks and report a verdict + version.
284
-
285
- HONESTY: EMPIRICAL checks on sampled inputs, NOT a proof of Λ-uniqueness
286
- (Conjecture 1, open). A clean run is evidence, not proof.
287
- """
288
- x = torch.rand(k, dtype=torch.float64) * 0.9
289
- w = torch.rand(k, dtype=torch.float64) + 1e-3
290
- axioms = {
291
- "A1_IsMonotone": is_monotone(x, w),
292
- "A2_IsHomogeneous": is_homogeneous(x, float(torch.rand(1).item()), weights=w),
293
- "A3_IsEgyptianExact": is_egyptian_exact(float(torch.rand(1).item()), k=k, weights=w),
294
- "A4_IsBounded": is_bounded_by_max(x, w),
295
- }
296
- violation = find_axiom_violation(k=k, trials=trials, seed=seed)
297
- return {
298
- "version": __version__,
299
- "axioms": axioms,
300
- "all_axioms_hold": all(axioms.values()) and violation is None,
301
- "adversarial": {"trials": int(trials), "violation": violation},
302
- "advisory": True,
303
- "lambda_status": "Conjecture 1 (open) — uniqueness unproven; advisory only",
304
- }
305
-
306
-
307
- __version__ = "0.2.0"
308
-
309
- from collections import namedtuple # noqa: E402
310
-
311
- LambdaGateResult = namedtuple(
312
- "LambdaGateResult", ["score", "passed", "threshold", "advisory"]
313
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Pure-PyTorch Lambda-Spine aggregator (Λ) for the szl-lambda-gate kernel.
4
+
5
+ Λ(x) = ∏ xᵢ^{wᵢ}, Σwᵢ = 1, wᵢ > 0, xᵢ ∈ [0,1] (weighted geometric mean)
6
+
7
+ This is a TORCH port of the canonical pure-Python reference
8
+ (packages/puriq-os/puriq_os/lambda_aggregator.py — saved alongside this kernel
9
+ as lambda_aggregator_source.py). It is a correctness reference, computed via
10
+ logs in float32 for stability, differentiable (autograd works), and
11
+ torch.compile-friendly. Depends ONLY on torch + the Python standard library
12
+ (a Kernel Hub requirement for universal kernels).
13
+
14
+ WHAT Λ IS / IS NOT (HONESTY — SZL Holdings doctrine v11):
15
+ Λ is the *weighted-geometric-mean aggregator*: a non-compensatory way to
16
+ combine axis scores in [0,1] into one number. It is ADVISORY governance
17
+ signal — a conservative roll-up where any single zeroed axis drives the
18
+ aggregate to 0. It is NOT "proven trust" and NOT a closed theorem. Its
19
+ *uniqueness* (that the weighted geometric mean is the only aggregator
20
+ satisfying the carried axioms) remains Conjecture 1 — OPEN (an unresolved
21
+ CAUCHY_ND step plus a missing symmetry axiom in the Lean development). Do
22
+ not describe Λ as proven trust anywhere.
23
+
24
+ PRIOR ART (honest attribution): the weighted geometric mean as a *less-
25
+ compensatory* composite-indicator aggregator is established practice — the
26
+ UN HDI (arithmetic→geometric switch, 2010), the OECD Handbook on
27
+ Constructing Composite Indicators (2008), and the UNECE well-being
28
+ guidelines all use it "to limit the compensation effect". The veto / cut-off
29
+ idea (a single failing criterion blocks a pass regardless of the others) is
30
+ the ELECTRE veto threshold / "satisficing" minimum-threshold screen. The
31
+ 13-axis conjunctive form exposed by :func:`yuyay_weights` is SZL's own
32
+ yuyay_v3 "Heart" gate. None of this makes Λ "proven trust"; the gate is
33
+ ADVISORY (a11oy: "the advisory Λ trust score is a research conjecture, not a
34
+ pass/fail oracle").
35
+
36
+ PROVENANCE: backed by the Lean 4 formalization szl-holdings/lutar-lean
37
+ (749 declarations / 14 axioms / 163 tracked sorries),
38
+ DOI 10.5281/zenodo.20434308 (lutar-lean).
39
+ Λ uniqueness = Conjecture 1 (open).
40
+
41
+ Axioms carried (Lutar/Axioms.lean), available below as runtime self-checks:
42
+ A1 IsMonotone — Λ is non-decreasing in each axis
43
+ A2 IsHomogeneous — Λ(t·x) = t·Λ(x) (degree 1)
44
+ A3 IsEgyptianExact — Λ(c,…,c) = c (the uniform-diagonal fixpoint)
45
+ A4 IsBounded(by max) — Λ(x) ≤ maxᵢ xᵢ
46
+ """
47
+ import warnings
48
+ from typing import Optional
49
+
50
+ import torch
51
+
52
+ # ---- the deprecated implicit threshold ------------------------------------- #
53
+ # lambda_gate / lambda_gate_batch / layers.LambdaGate used to default to 0.5.
54
+ # That default stays, so there is no behaviour change, but omitting the
55
+ # threshold now raises a DeprecationWarning. The admit policy value is
56
+ # policy_tau in frontier/model_admit_contract.v1.json, and the strict
57
+ # szl.lambda/v1 gate (_v1.lambda_v1_gate) takes tau as a required argument.
58
+ _LEGACY_DEFAULT_THRESHOLD = 0.5
59
+ _DEFAULT_THRESHOLD_WARNING = (
60
+ "default threshold 0.5 differs from policy_tau 0.8; pass tau. Omitting the "
61
+ "threshold of lambda_gate / lambda_gate_batch / LambdaGate is deprecated: "
62
+ "pass threshold= explicitly (policy_tau is in "
63
+ "frontier/model_admit_contract.v1.json), or use the strict "
64
+ "lambda_v1_gate(axes, weights, tau). The legacy default 0.5 still applies."
65
+ )
66
+
67
+
68
+ def _resolve_threshold(threshold: Optional[float], stacklevel: int) -> float:
69
+ """``None`` (the threshold was omitted) -> the legacy 0.5, with a DeprecationWarning.
70
+
71
+ ``stacklevel`` is what the calling entry point would pass to
72
+ ``warnings.warn`` itself (2 = its caller), so the warning names the line
73
+ that omitted the threshold. Dynamo cannot trace ``warnings.warn`` (a
74
+ fullgraph compile would fail), so the warning is skipped while
75
+ ``torch.compile`` traces; the default is applied either way.
76
+ """
77
+ if threshold is not None:
78
+ return threshold
79
+ if not bool(getattr(torch.compiler, "is_compiling", lambda: False)()):
80
+ warnings.warn(_DEFAULT_THRESHOLD_WARNING, DeprecationWarning, stacklevel=stacklevel + 1)
81
+ return _LEGACY_DEFAULT_THRESHOLD
82
+
83
+
84
+ # Compute reductions/log-sum in float32 for stability when inputs are low
85
+ # precision; keep float64 inputs in float64 (downcasting would break gradcheck
86
+ # and silently lose precision).
87
+ _SUPPORTED_DTYPES = (torch.float16, torch.bfloat16, torch.float32, torch.float64)
88
+
89
+
90
+ def _compute_dtype(in_dtype: torch.dtype) -> torch.dtype:
91
+ return torch.float32 if in_dtype in (torch.float16, torch.bfloat16) else in_dtype
92
+
93
+
94
+ def _check_axes(axes: torch.Tensor) -> None:
95
+ """Cheap, allocation-free metadata guards on the axis-score tensor.
96
+
97
+ Inspects only type / dtype / rank / last-dim, so it constant-folds under
98
+ torch.compile and adds no tensor work on the happy path.
99
+ """
100
+ if not isinstance(axes, torch.Tensor):
101
+ raise TypeError(f"axes must be a torch.Tensor, got {type(axes).__name__}")
102
+ if axes.dtype not in _SUPPORTED_DTYPES:
103
+ raise TypeError(
104
+ f"axes has unsupported dtype {axes.dtype}; "
105
+ f"expected one of {tuple(str(d) for d in _SUPPORTED_DTYPES)}"
106
+ )
107
+ if axes.dim() < 1:
108
+ raise ValueError(
109
+ "axes must have at least 1 dimension (the k axis scores live on "
110
+ f"the last dim); got a {axes.dim()}-d tensor"
111
+ )
112
+ if axes.shape[-1] < 1:
113
+ raise ValueError("axes last dimension (k = number of axes) must be >= 1")
114
+
115
+
116
+ def _resolve_weights(
117
+ axes: torch.Tensor,
118
+ weights: Optional[torch.Tensor],
119
+ cdt: torch.dtype,
120
+ ) -> torch.Tensor:
121
+ """Return a normalized (Σw = 1) weight vector of shape (k,) in compute dtype.
122
+
123
+ ``weights=None`` -> uniform 1/k (the Egyptian-exact diagonal). Otherwise the
124
+ weights must be 1-D of length k, strictly positive, with a positive sum;
125
+ they are normalized so Σwᵢ = 1.
126
+ """
127
+ k = axes.shape[-1]
128
+ if weights is None:
129
+ return torch.full((k,), 1.0 / k, dtype=cdt, device=axes.device)
130
+ if not isinstance(weights, torch.Tensor):
131
+ raise TypeError(f"weights must be a torch.Tensor or None, got {type(weights).__name__}")
132
+ if weights.device != axes.device:
133
+ raise ValueError(
134
+ f"weights is on device {weights.device} but axes is on {axes.device}; "
135
+ "move them to the same device"
136
+ )
137
+ if weights.dim() != 1 or weights.shape[0] != k:
138
+ raise ValueError(
139
+ f"weights must be 1-D with shape ({k},) to match the last dim of axes; "
140
+ f"got shape {tuple(weights.shape)}"
141
+ )
142
+ wf = weights.to(cdt)
143
+ compiling = bool(getattr(torch.compiler, "is_compiling", lambda: False)())
144
+ if not compiling:
145
+ if not bool(torch.all(torch.isfinite(wf))):
146
+ raise ValueError("weights must all be finite (no NaN/Inf)")
147
+ if bool(torch.any(wf <= 0.0)):
148
+ raise ValueError("weights must be strictly positive (wᵢ > 0)")
149
+ sw = wf.sum()
150
+ if not bool(sw > 0.0):
151
+ raise ValueError("weights must sum to a positive value")
152
+ return wf / sw
153
+ # Compiled path stays in tensor-land. Non-positive weights are a misuse;
154
+ # clamp them away from zero so the graph does not break, then normalize.
155
+ # This path is outside szl.lambda/v1; _v1.lambda_v1 validates before it
156
+ # gets here and is not meant to run under torch.compile.
157
+ wf = torch.where(torch.isfinite(wf), wf, torch.ones_like(wf))
158
+ wf = torch.clamp(wf, min=torch.finfo(wf.dtype).tiny)
159
+ return wf / wf.sum()
160
+
161
+
162
+ def lambda_aggregate(
163
+ axes: torch.Tensor,
164
+ weights: Optional[torch.Tensor] = None,
165
+ ) -> torch.Tensor:
166
+ """Weighted geometric mean Λ(x) = ∏ xᵢ^{wᵢ} over the last dim of ``axes``.
167
+
168
+ Λ is the (ADVISORY) Lambda-Spine aggregator. Axis scores are expected in
169
+ [0,1] and are clamped into [0,1]; uniform weights (1/k) are used when
170
+ ``weights`` is None — the Egyptian-exact diagonal. Computed via logs in
171
+ float32 (or float64 for float64 inputs) for numerical stability:
172
+
173
+ Λ(x) = exp( Σᵢ wᵢ · log(clamp(xᵢ, 0, 1)) )
174
+
175
+ Non-compensatory zero-routing (A4-consistent): any axis that is zero, OR
176
+ that is NON-FINITE (NaN / ±Inf), is treated as a FAILING axis and drives
177
+ the whole aggregate to exactly 0. This is the conservative governance
178
+ choice — a garbage/invalid axis must never silently pass as a "perfect"
179
+ (clamped-to-1) axis, and the output (and its gradient) stay finite and in
180
+ [0,1] for every input. Zeros/non-finite axes are routed explicitly so
181
+ log(0) = -inf and log(NaN) = NaN never produce a NaN value or gradient.
182
+
183
+ Args:
184
+ axes: tensor of shape (..., k) of axis scores in [0,1]. Batched:
185
+ the reduction is over the last dim, leading dims are batch.
186
+ weights: optional 1-D tensor of shape (k,); None -> uniform. Normalized
187
+ internally so Σwᵢ = 1.
188
+
189
+ Returns:
190
+ tensor of shape (...) — Λ(x) ∈ [0,1] per batch row. Differentiable
191
+ w.r.t. ``axes`` (and ``weights``).
192
+
193
+ NOT the szl.lambda/v1 contract: this function clamps, zero-routes NaN/±Inf
194
+ and renormalises (pinned in tests/test_lambda_v1_torch_divergence.py). For
195
+ validated, coded errors use :func:`szl_lambda_gate._v1.lambda_v1`.
196
+
197
+ HONESTY: this is a non-compensatory governance roll-up, NOT proven trust.
198
+ Λ-uniqueness is Conjecture 1 (open).
199
+ """
200
+ _check_axes(axes)
201
+ in_dtype = axes.dtype
202
+ cdt = _compute_dtype(in_dtype)
203
+ xf = axes.to(cdt)
204
+ w = _resolve_weights(axes, weights, cdt) # (k,), Σw=1
205
+
206
+ # A "bad" axis is one that fails non-compensatorily: a non-positive score
207
+ # OR a non-finite value (NaN / ±Inf). clamp(+inf)=1 would otherwise count a
208
+ # garbage axis as perfect, and clamp(NaN)=NaN would poison the product — we
209
+ # treat BOTH as failing (zeroing) axes. Detect non-finite on the RAW input.
210
+ finite_mask = torch.isfinite(xf)
211
+ xc = xf.clamp(0.0, 1.0)
212
+ bad_mask = (~finite_mask) | (xc <= 0.0)
213
+ any_bad = torch.any(bad_mask, dim=-1) # (...)
214
+
215
+ # Replace bad axes with 1.0 before the log purely to keep log finite and the
216
+ # gradient well-defined; the bad-axis contribution is reinstated via any_bad.
217
+ safe = torch.where(bad_mask, torch.ones_like(xc), xc)
218
+ logx = torch.log(safe) # (..., k)
219
+ acc = (logx * w).sum(dim=-1) # (...) weighted log-sum
220
+ val = torch.exp(acc) # (...) Λ before zero-routing
221
+
222
+ out = torch.where(any_bad, torch.zeros_like(val), val)
223
+ out = out.clamp(0.0, 1.0)
224
+ return out.to(in_dtype)
225
+
226
+
227
+ def lambda_gate(
228
+ axes: torch.Tensor,
229
+ weights: Optional[torch.Tensor] = None,
230
+ threshold: Optional[float] = None,
231
+ ):
232
+ """ADVISORY governance gate over Λ(x): score plus a pass/fail vs threshold.
233
+
234
+ Computes Λ(x) (see :func:`lambda_aggregate`) and compares it to
235
+ ``threshold``: pass := Λ(x) >= threshold.
236
+
237
+ DEPRECATED DEFAULT: omitting ``threshold`` (or passing ``None``) still uses
238
+ the legacy 0.5 but raises a ``DeprecationWarning``, because 0.5 differs
239
+ from the admit contract's policy_tau (0.8). Pass the threshold explicitly,
240
+ or use the strict szl.lambda/v1 gate
241
+ :func:`szl_lambda_gate._v1.lambda_v1_gate`, where tau is required.
242
+
243
+ ``threshold`` must be a finite float within Λ's range ``[0, 1]`` (Λ is the
244
+ weighted geometric mean over [0,1]). This bound is enforced: a threshold
245
+ below 0 or above 1 is meaningless for the advisory gate and is rejected —
246
+ see the non-compensatory rationale below. The domain edges are valid:
247
+ ``0.0`` admits every candidate (a permissive "no-gate" boundary) and
248
+ ``1.0`` admits only a Λ == 1 candidate.
249
+
250
+ Returns a :class:`LambdaGateResult` namedtuple with fields:
251
+ score — Λ(x) tensor of shape (...), in [0,1]
252
+ passed — boolean tensor of shape (...), Λ(x) >= threshold
253
+ threshold — the float threshold used
254
+ advisory — always True; a STANDING reminder that this is a
255
+ non-compensatory governance signal, NOT proven trust.
256
+
257
+ Non-compensatory threshold hardening: because a failing/garbage candidate
258
+ (a zero, NaN, or ±Inf axis) is routed to Λ = 0, a NEGATIVE threshold would
259
+ advisory-"pass" exactly those fully-failing candidates (0 >= t for t < 0) —
260
+ the opposite of a conservative admission gate. A threshold above 1 can
261
+ never pass. Both are misconfigurations, so the [0,1] domain is enforced up
262
+ front rather than silently producing a wrong pass mask.
263
+
264
+ HONESTY: a "pass" is an ADVISORY signal only. Λ is the weighted-geometric-
265
+ mean aggregator; its uniqueness is Conjecture 1 (open). Do not treat a
266
+ pass as proven trust or a closed theorem.
267
+ """
268
+ threshold = _resolve_threshold(threshold, stacklevel=2)
269
+ t = float(threshold)
270
+ if t != t or t == float("inf") or t == float("-inf"):
271
+ raise ValueError(f"threshold must be a finite float, got {threshold!r}")
272
+ if t < 0.0 or t > 1.0:
273
+ raise ValueError(
274
+ "threshold must be within Λ's range [0, 1] (Λ is the weighted "
275
+ f"geometric mean over [0,1]); got {t!r}. A threshold below 0 would "
276
+ "advisory-pass a fully-failing (Λ=0) candidate and one above 1 can "
277
+ "never pass — both signal a misconfigured gate."
278
+ )
279
+ score = lambda_aggregate(axes, weights)
280
+ passed = score >= t
281
+ return LambdaGateResult(score=score, passed=passed, threshold=t, advisory=True)
282
+
283
+
284
+ def lambda_gate_batch(
285
+ candidates: torch.Tensor,
286
+ weights: Optional[torch.Tensor] = None,
287
+ threshold: Optional[float] = None,
288
+ ):
289
+ """ADVISORY batch gate: score MANY candidate action-vectors in one call.
290
+
291
+ This is the realistic way a model/agent uses the gate — one call per
292
+ inference step that scores every proposed action-vector at once and returns
293
+ the advisory pass mask (which candidates clear the threshold).
294
+
295
+ ``candidates`` is a tensor of shape (..., N, k): the last dim ``k`` holds
296
+ the per-axis scores of a single candidate, and the second-to-last dim ``N``
297
+ enumerates the candidates (any leading dims are extra batch). Equivalent to
298
+ calling :func:`lambda_gate` on the whole tensor — the reduction is over the
299
+ last dim — but named to make the agent-loop intent explicit. ``threshold``
300
+ inherits the same [0,1] domain guard as :func:`lambda_gate` (a threshold
301
+ outside Λ's range is a misconfiguration and is rejected). Omitting it uses
302
+ the legacy 0.5 with a ``DeprecationWarning``, as in :func:`lambda_gate`.
303
+
304
+ Returns a :class:`LambdaGateResult` with:
305
+ score — Λ tensor of shape (..., N), one score per candidate
306
+ passed — boolean mask of shape (..., N): score >= threshold
307
+ threshold — the float threshold used
308
+ advisory — always True (NOT proven trust)
309
+
310
+ HONESTY: the pass mask is an ADVISORY, non-compensatory signal. A "pass"
311
+ is not proven trust; Λ-uniqueness is Conjecture 1 (open).
312
+ """
313
+ threshold = _resolve_threshold(threshold, stacklevel=2)
314
+ _check_axes(candidates)
315
+ if candidates.dim() < 2:
316
+ raise ValueError(
317
+ "candidates must be at least 2-D, shape (..., N, k): the last dim is "
318
+ f"the k axis scores and the one before it enumerates the N candidates; "
319
+ f"got a {candidates.dim()}-d tensor"
320
+ )
321
+ # Reuse the single-call gate — its reduction over the last dim already gives
322
+ # one score per candidate, so the (..., N) layout falls out for free.
323
+ return lambda_gate(candidates, weights=weights, threshold=threshold)
324
+
325
+
326
+ # ---- A1..A4 axiom RUNTIME self-checks (real, verifiable) ------------------- #
327
+ # These are honest empirical checks callers can run on concrete inputs. They
328
+ # verify the carried axioms hold for THIS implementation on the given data —
329
+ # they are NOT a proof of Λ-uniqueness (that is Conjecture 1, open).
330
+
331
+ def is_egyptian_exact(
332
+ c: float,
333
+ k: int = 3,
334
+ weights: Optional[torch.Tensor] = None,
335
+ tol: float = 1e-5,
336
+ ) -> bool:
337
+ """A3 IsEgyptianExact: Λ(c, …, c) = c for a constant axis vector of length k.
338
+
339
+ Builds the uniform vector (c repeated k times) and checks Λ equals c within
340
+ ``tol``. ``c`` is clamped into [0,1] to match the aggregator's domain.
341
+ """
342
+ if k < 1:
343
+ raise ValueError("k must be >= 1")
344
+ cc = min(max(float(c), 0.0), 1.0)
345
+ axes = torch.full((k,), cc, dtype=torch.float64)
346
+ val = lambda_aggregate(axes, weights)
347
+ return bool(torch.abs(val - cc) <= tol)
348
+
349
+
350
+ def is_bounded_by_max(
351
+ axes: torch.Tensor,
352
+ weights: Optional[torch.Tensor] = None,
353
+ tol: float = 1e-6,
354
+ ) -> bool:
355
+ """A4 IsBounded: Λ(x) ≤ maxᵢ xᵢ (over the last dim), within ``tol``.
356
+
357
+ Returns True iff the bound holds for every batch row. Non-finite axis
358
+ values are clamped/zero-routed the same way the aggregator treats them, so
359
+ the bound is checked on the conservative (finite) domain.
360
+ """
361
+ _check_axes(axes)
362
+ val = lambda_aggregate(axes, weights) # (...)
363
+ xf = axes.to(_compute_dtype(axes.dtype))
364
+ # Mirror the aggregator: non-finite axes are failing (treated as 0) for the
365
+ # purposes of the max bound, so the check matches the routed semantics.
366
+ xf = torch.where(torch.isfinite(xf), xf, torch.zeros_like(xf))
367
+ mx = xf.clamp(0.0, 1.0).amax(dim=-1) # (...)
368
+ return bool(torch.all(val.to(mx.dtype) <= mx + tol))
369
+
370
+
371
+ def is_homogeneous(
372
+ axes: torch.Tensor,
373
+ t: float,
374
+ weights: Optional[torch.Tensor] = None,
375
+ tol: float = 1e-5,
376
+ ) -> bool:
377
+ """A2 IsHomogeneous (degree 1): Λ(t·x) = t·Λ(x) for scalar t in [0,1].
378
+
379
+ Verified on the clamped domain: both ``axes`` and ``t*axes`` must remain in
380
+ [0,1] for the identity to be meaningful, so ``axes`` is clamped to [0,1] and
381
+ ``t`` to [0,1] before the comparison.
382
+ """
383
+ _check_axes(axes)
384
+ tt = min(max(float(t), 0.0), 1.0)
385
+ x = axes.to(torch.float64).clamp(0.0, 1.0)
386
+ lhs = lambda_aggregate(x * tt, weights)
387
+ rhs = tt * lambda_aggregate(x, weights)
388
+ return bool(torch.all(torch.abs(lhs - rhs) <= tol))
389
+
390
+
391
+ def is_monotone(
392
+ axes: torch.Tensor,
393
+ weights: Optional[torch.Tensor] = None,
394
+ delta: float = 0.05,
395
+ tol: float = 1e-7,
396
+ ) -> bool:
397
+ """A1 IsMonotone: Λ is non-decreasing in each axis.
398
+
399
+ For each axis j, nudges that axis UP by ``delta`` (clamped to stay ≤ 1) on
400
+ every batch row and checks Λ does not decrease (within ``tol``). Rows that
401
+ cannot move (already at 1) are skipped for that axis. A real check on the
402
+ given data — not a symbolic proof.
403
+ """
404
+ _check_axes(axes)
405
+ x = axes.to(torch.float64).clamp(0.0, 1.0)
406
+ base = lambda_aggregate(x, weights)
407
+ k = x.shape[-1]
408
+ ok = True
409
+ for j in range(k):
410
+ bumped = x.clone()
411
+ bumped[..., j] = (bumped[..., j] + float(delta)).clamp(0.0, 1.0)
412
+ bumped_val = lambda_aggregate(bumped, weights)
413
+ # Λ must not go DOWN when an axis goes UP.
414
+ ok = ok and bool(torch.all(bumped_val - base >= -tol))
415
+ return ok
416
+
417
+
418
+ # ---- Adversarial axiom search (honest: a falsification attempt) ------------ #
419
+ def find_axiom_violation(
420
+ k: int = 5,
421
+ trials: int = 200,
422
+ weights: Optional[torch.Tensor] = None,
423
+ seed: Optional[int] = 0,
424
+ tol: float = 1e-6,
425
+ ):
426
+ """Random-search for ANY A1–A4 violation on random axis/weight draws.
427
+
428
+ Returns the first ``(axiom, axes, weights)`` triple that violates a carried
429
+ axiom within ``tol``, or ``None`` if none is found in ``trials`` draws. This
430
+ is an honest FALSIFICATION attempt on this implementation — finding nothing
431
+ is empirical evidence, NOT a proof (Λ-uniqueness is Conjecture 1, open).
432
+ """
433
+ gen = torch.Generator()
434
+ if seed is not None:
435
+ gen.manual_seed(int(seed))
436
+ for _ in range(int(trials)):
437
+ x = torch.rand(k, generator=gen, dtype=torch.float64)
438
+ w = weights
439
+ if w is None:
440
+ w = torch.rand(k, generator=gen, dtype=torch.float64) + 1e-3
441
+ # A3 on a constant draw
442
+ c = float(torch.rand(1, generator=gen).item())
443
+ if not is_egyptian_exact(c, k=k, weights=w, tol=max(tol, 1e-5)):
444
+ return ("A3_IsEgyptianExact", torch.full((k,), c, dtype=torch.float64), w)
445
+ # A4 bounded-by-max
446
+ if not is_bounded_by_max(x, w, tol=max(tol, 1e-6)):
447
+ return ("A4_IsBounded", x, w)
448
+ # A2 homogeneous at a random t
449
+ t = float(torch.rand(1, generator=gen).item())
450
+ if not is_homogeneous(x, t, weights=w, tol=max(tol, 1e-5)):
451
+ return ("A2_IsHomogeneous", x, w)
452
+ # A1 monotone (leave headroom so an up-bump stays in range)
453
+ if not is_monotone(x * 0.9, w, tol=max(tol, 1e-7)):
454
+ return ("A1_IsMonotone", x * 0.9, w)
455
+ return None
456
+
457
+
458
+ # ---- Canonical 13-axis Yuyay preset (ADVISORY ONLY) ------------------------ #
459
+ # SZL's own yuyay_v3 "Heart" gate is a 13-axis CONJUNCTIVE-AND screen (each axis
460
+ # independently clears its floor — no compensation). We expose its published
461
+ # axis NAMES and per-axis FLOORS as advisory metadata, and a uniform Λ weight
462
+ # vector over the 13 axes. This is ADVISORY: Λ here is still the weighted
463
+ # geometric mean, and a "pass" is a research-conjecture signal, NOT proven
464
+ # trust. Source: yuyay_v3 spec (Lutar, 2026).
465
+ YUYAY_AXES = (
466
+ "moralGrounding",
467
+ "measurabilityHonesty",
468
+ "empiricalGrounding",
469
+ "logicalConsistency",
470
+ "sourceTransparency",
471
+ "reproducibility",
472
+ "licenseHygiene",
473
+ "scopeDiscipline",
474
+ "claimCalibration",
475
+ "evalAwareness",
476
+ "deceptionKeywords",
477
+ "conflictingDirectives",
478
+ "reversalDirective",
479
+ )
480
+ # Published per-axis advisory floors for the CONJUNCTIVE screen: two "sacred"
481
+ # axes at 0.95, seven "structural" at 0.90, four "introspection" at 0.90.
482
+ YUYAY_FLOORS = (
483
+ 0.95, 0.95, # sacred
484
+ 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, # structural (7)
485
+ 0.90, 0.90, 0.90, 0.90, # introspection (4)
486
+ )
487
+
488
+
489
+ def yuyay_weights(
490
+ dtype: torch.dtype = torch.float64,
491
+ device: Optional[torch.device] = None,
492
+ ) -> torch.Tensor:
493
+ """Canonical 13-axis Yuyay Λ weight vector (uniform 1/13), ADVISORY only.
494
+
495
+ Returns a length-13 weight tensor for use as the ``weights`` argument to
496
+ :func:`lambda_aggregate` / :func:`lambda_gate` over the 13 :data:`YUYAY_AXES`.
497
+ Uniform by default (the Egyptian-exact diagonal). The published yuyay_v3
498
+ gate is a conjunctive AND with per-axis floors (:data:`YUYAY_FLOORS`); the
499
+ Λ roll-up here is the weighted geometric mean and is ADVISORY — NOT proven
500
+ trust (Λ-uniqueness is Conjecture 1, open).
501
+ """
502
+ k = len(YUYAY_AXES)
503
+ return torch.full((k,), 1.0 / k, dtype=dtype, device=device)
504
+
505
+
506
+ # ---- Kernel self-check surface --------------------------------------------- #
507
+ def selfcheck(
508
+ k: int = 5,
509
+ trials: int = 64,
510
+ seed: Optional[int] = 0,
511
+ ) -> dict:
512
+ """Run the A1–A4 empirical self-checks and report a verdict + version.
513
+
514
+ Returns a dict:
515
+ version — kernel version string
516
+ axioms — {A1..A4: bool} empirical pass on sampled inputs
517
+ all_axioms_hold — bool, every sampled axiom check passed
518
+ adversarial — {trials, violation} from a random falsification search
519
+ (violation is None when no violation was found)
520
+ advisory — always True
521
+ lambda_status — Conjecture 1 (open) honesty string
522
+
523
+ HONESTY: these are EMPIRICAL checks on sampled inputs, NOT a proof of
524
+ Λ-uniqueness (Conjecture 1, open). A clean run is evidence, not proof.
525
+ """
526
+ x = torch.rand(k, dtype=torch.float64) * 0.9 # headroom for the A1 up-bump
527
+ w = torch.rand(k, dtype=torch.float64) + 1e-3
528
+ axioms = {
529
+ "A1_IsMonotone": is_monotone(x, w),
530
+ "A2_IsHomogeneous": is_homogeneous(x, float(torch.rand(1).item()), weights=w),
531
+ "A3_IsEgyptianExact": is_egyptian_exact(float(torch.rand(1).item()), k=k, weights=w),
532
+ "A4_IsBounded": is_bounded_by_max(x, w),
533
+ }
534
+ violation = find_axiom_violation(k=k, trials=trials, seed=seed)
535
+ return {
536
+ "version": __version__,
537
+ "axioms": axioms,
538
+ "all_axioms_hold": all(axioms.values()) and violation is None,
539
+ "adversarial": {"trials": int(trials), "violation": violation},
540
+ "advisory": True,
541
+ "lambda_status": "Conjecture 1 (open) — uniqueness unproven; advisory only",
542
+ }
543
+
544
+
545
+ # Kept in sync with the package __version__ (single source of truth lives in
546
+ # __init__; duplicated here so _lambda is importable/selfcheck-able standalone).
547
+ __version__ = "0.2.0"
548
+
549
+
550
+ # Namedtuple result type for the gate. Defined after functions so docstrings
551
+ # above can reference it; imported by __init__ and layers.
552
+ from collections import namedtuple # noqa: E402
553
+
554
+ LambdaGateResult = namedtuple(
555
+ "LambdaGateResult", ["score", "passed", "threshold", "advisory"]
556
+ )
build/torch-cpu/szl_lambda_gate/_ops.py CHANGED
@@ -1,10 +1,10 @@
1
- # SPDX-License-Identifier: Apache-2.0
2
- # Auto-style ops namespace shim for the universal kernel. Unique suffix lets
3
- # multiple versions load in the same process (Kernel Hub requirement).
4
- import torch
5
-
6
- ops = torch.ops._szl_lambda_gate_20260623081355
7
-
8
-
9
- def add_op_namespace_prefix(op_name: str) -> str:
10
- return f"_szl_lambda_gate_20260623081355::{op_name}"
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Auto-style ops namespace shim for the universal kernel. Unique suffix lets
3
+ # multiple versions load in the same process (Kernel Hub requirement).
4
+ import torch
5
+
6
+ ops = torch.ops._szl_lambda_gate_20260623081355
7
+
8
+
9
+ def add_op_namespace_prefix(op_name: str) -> str:
10
+ return f"_szl_lambda_gate_20260623081355::{op_name}"
build/torch-cpu/szl_lambda_gate/_v1.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """szl.lambda/v1 strict kernel entry: Λ and its gate on tensors, with no clamping or defaults.
4
+
5
+ This is the torch port of ``reference/szl_lambda_v1.py`` and follows
6
+ ``spec/szl.lambda.v1.json``. An input outside the contract makes ``lambda_v1``
7
+ raise ``LambdaV1Error(code)`` and makes ``lambda_v1_gate`` return verdict BLOCK
8
+ with that code. Nothing is clamped, renormalised, defaulted or rounded before
9
+ the compare::
10
+
11
+ lambda_v1(axes, weights) -> 0-d float64 tensor, Λ in [0, 1]
12
+ lambda_v1_gate(axes, weights, tau) -> LambdaV1GateResult(verdict, code, score, tau, advisory)
13
+
14
+ The legacy ``lambda_aggregate`` / ``lambda_gate`` are unchanged. They clamp
15
+ x > 1 to 1, route NaN and ±Inf to 0 and renormalise weights, and
16
+ ``lambda_gate`` falls back to a threshold of 0.5, which is now deprecated.
17
+ Use this module when a verdict must follow szl.lambda/v1.
18
+
19
+ Inputs
20
+ ``axes`` and ``weights`` are 1-D tensors of a real dtype (floating or
21
+ integer). bool and complex are not numbers. A Python list, None, or a 0-d
22
+ or 2-D tensor is LAMBDA_TYPE_INVALID; build the tensor with
23
+ ``torch.tensor(values, dtype=torch.float64)``. ``weights`` is moved to the
24
+ device of ``axes``. Inputs are read and never modified.
25
+
26
+ ``tau`` is a Python int or float (not bool), finite, with 0 < tau <= 1. It
27
+ is required and has no default. The policy value is ``policy_tau`` in
28
+ frontier/model_admit_contract.v1.json.
29
+
30
+ Checks run in phases, in the reference's order, so the reported code does not
31
+ depend on axis order::
32
+
33
+ LAMBDA_TYPE_INVALID (container) > LAMBDA_EMPTY > LAMBDA_LENGTH_MISMATCH
34
+ > LAMBDA_TYPE_INVALID (dtype) > LAMBDA_NONFINITE_AXIS
35
+ > LAMBDA_AXIS_OUT_OF_RANGE > LAMBDA_NONFINITE_WEIGHT
36
+ > LAMBDA_WEIGHT_NONPOSITIVE > LAMBDA_WEIGHT_SUM
37
+
38
+ The gate checks tau first (LAMBDA_TAU_INVALID). The element checks and the
39
+ weight sum (``math.fsum``) run on the float64 values exactly as the reference
40
+ runs them, so every error code agrees with the reference.
41
+
42
+ How the numbers are computed
43
+ * Λ, which is ``lambda_v1`` and the gate's ``score``, comes from
44
+ ``_lambda.lambda_aggregate`` in float64, so it stays a differentiable
45
+ tensor. On validated input that function's clamp and NaN routing change
46
+ nothing, and a zero axis gives exactly 0. Its renormalisation divides by
47
+ a sum within 1e-12 of 1, which moves Λ by at most Λ·|log Λ|·1e-12
48
+ (<= 3.7e-13) plus float64 rounding. The vectors' value_tol is 1e-12.
49
+ * The verdict comes from log Λ = fsum(w_k · log x_k) over the same float64
50
+ values, as in the reference, so it never depends on how Λ rounds (a
51
+ subnormal Λ has little relative precision). A zero axis gives
52
+ log Λ = -inf and the verdict NO_GO / ZERO_VETO, a veto rather than an
53
+ error. |log Λ - log tau| <= TIE_EPS gives ABSTAIN / NUMERIC_TIE. Above
54
+ the band the verdict is GO, and below it NO_GO / BELOW_TAU.
55
+
56
+ The checks depend on the data and the verdict is a Python string, so this
57
+ entry is not meant to run inside ``torch.compile``. The legacy compiled weight
58
+ path in ``_lambda._resolve_weights``, which clamps weights to ``finfo.tiny``,
59
+ is outside szl.lambda/v1.
60
+
61
+ Λ is advisory. Λ uniqueness is Conjecture 1 (open), and nothing here depends on it.
62
+ """
63
+ from __future__ import annotations
64
+
65
+ import math
66
+ from collections import namedtuple
67
+ from typing import Any, List, Optional, Tuple
68
+
69
+ import torch
70
+
71
+ from ._lambda import lambda_aggregate
72
+
73
+ SCHEMA = "szl.lambda/v1"
74
+ UNIQUENESS = "CONJECTURE_1_NOT_USED"
75
+ WEIGHT_SUM_TOL = 1e-12
76
+ TIE_EPS = 1e-9
77
+
78
+ TYPE_INVALID = "LAMBDA_TYPE_INVALID"
79
+ EMPTY = "LAMBDA_EMPTY"
80
+ LENGTH_MISMATCH = "LAMBDA_LENGTH_MISMATCH"
81
+ NONFINITE_AXIS = "LAMBDA_NONFINITE_AXIS"
82
+ AXIS_OUT_OF_RANGE = "LAMBDA_AXIS_OUT_OF_RANGE"
83
+ NONFINITE_WEIGHT = "LAMBDA_NONFINITE_WEIGHT"
84
+ WEIGHT_NONPOSITIVE = "LAMBDA_WEIGHT_NONPOSITIVE"
85
+ WEIGHT_SUM = "LAMBDA_WEIGHT_SUM"
86
+ TAU_INVALID = "LAMBDA_TAU_INVALID"
87
+
88
+ #: Every error code, in precedence order (tau is checked first by the gate).
89
+ ERROR_CODES = (
90
+ TYPE_INVALID,
91
+ EMPTY,
92
+ LENGTH_MISMATCH,
93
+ NONFINITE_AXIS,
94
+ AXIS_OUT_OF_RANGE,
95
+ NONFINITE_WEIGHT,
96
+ WEIGHT_NONPOSITIVE,
97
+ WEIGHT_SUM,
98
+ TAU_INVALID,
99
+ )
100
+
101
+ GO = "GO"
102
+ NO_GO = "NO_GO"
103
+ ABSTAIN = "ABSTAIN"
104
+ BLOCK = "BLOCK"
105
+ VERDICTS = (GO, NO_GO, ABSTAIN, BLOCK)
106
+
107
+ ZERO_VETO = "ZERO_VETO"
108
+ BELOW_TAU = "BELOW_TAU"
109
+ NUMERIC_TIE = "NUMERIC_TIE"
110
+
111
+ _INTEGER_DTYPES = (torch.uint8, torch.int8, torch.int16, torch.int32, torch.int64)
112
+
113
+
114
+ class LambdaV1Error(ValueError):
115
+ """An input outside the szl.lambda/v1 contract. ``code`` is one of ERROR_CODES."""
116
+
117
+ def __init__(self, code: str, detail: str = "") -> None:
118
+ self.code = code
119
+ self.detail = detail
120
+ super().__init__(f"{code}: {detail}" if detail else code)
121
+
122
+
123
+ #: verdict in VERDICTS; code as in the spec's gate rules; score is Λ as a 0-d
124
+ #: float64 tensor (None on BLOCK); tau is the validated float (None when tau
125
+ #: itself is invalid); advisory is always True.
126
+ LambdaV1GateResult = namedtuple(
127
+ "LambdaV1GateResult", ["verdict", "code", "score", "tau", "advisory"]
128
+ )
129
+
130
+
131
+ def _is_real(value: Any) -> bool:
132
+ return isinstance(value, (int, float)) and not isinstance(value, bool)
133
+
134
+
135
+ def _is_real_dtype(dtype: torch.dtype) -> bool:
136
+ return dtype.is_floating_point or dtype in _INTEGER_DTYPES
137
+
138
+
139
+ def _validate(
140
+ axes: Any, weights: Any
141
+ ) -> Tuple[torch.Tensor, torch.Tensor, List[float], List[float]]:
142
+ """Float64 tensors and their values, or LambdaV1Error in the reference's phase order."""
143
+ for name, t in (("axes", axes), ("weights", weights)):
144
+ if not isinstance(t, torch.Tensor):
145
+ raise LambdaV1Error(TYPE_INVALID, f"{name} must be a 1-D torch.Tensor, got {type(t).__name__}")
146
+ if t.dim() != 1:
147
+ raise LambdaV1Error(TYPE_INVALID, f"{name} must be a 1-D tensor, got {t.dim()}-D")
148
+ k, m = axes.shape[0], weights.shape[0]
149
+ if k == 0 or m == 0:
150
+ raise LambdaV1Error(EMPTY, f"len(axes)={k}, len(weights)={m}")
151
+ if k != m:
152
+ raise LambdaV1Error(LENGTH_MISMATCH, f"len(axes)={k} != len(weights)={m}")
153
+ for name, t in (("axes", axes), ("weights", weights)):
154
+ if not _is_real_dtype(t.dtype):
155
+ raise LambdaV1Error(TYPE_INVALID, f"{name} has dtype {t.dtype}, not a real number type")
156
+ x = axes.to(torch.float64)
157
+ w = weights.to(device=x.device, dtype=torch.float64)
158
+ xs, ws = x.tolist(), w.tolist()
159
+ for i, v in enumerate(xs):
160
+ if not math.isfinite(v):
161
+ raise LambdaV1Error(NONFINITE_AXIS, f"axes[{i}]={v!r}")
162
+ for i, v in enumerate(xs):
163
+ if not 0.0 <= v <= 1.0:
164
+ raise LambdaV1Error(AXIS_OUT_OF_RANGE, f"axes[{i}]={v!r} is outside [0, 1]")
165
+ for i, v in enumerate(ws):
166
+ if not math.isfinite(v):
167
+ raise LambdaV1Error(NONFINITE_WEIGHT, f"weights[{i}]={v!r}")
168
+ for i, v in enumerate(ws):
169
+ if not v > 0.0:
170
+ raise LambdaV1Error(WEIGHT_NONPOSITIVE, f"weights[{i}]={v!r} is not > 0")
171
+ try:
172
+ total = math.fsum(ws)
173
+ except OverflowError:
174
+ raise LambdaV1Error(WEIGHT_SUM, "sum of weights overflows a float") from None
175
+ if not abs(total - 1.0) <= WEIGHT_SUM_TOL:
176
+ raise LambdaV1Error(WEIGHT_SUM, f"fsum(weights)={total!r} is not within {WEIGHT_SUM_TOL} of 1")
177
+ return x, w, xs, ws
178
+
179
+
180
+ def lambda_v1(axes: torch.Tensor, weights: torch.Tensor) -> torch.Tensor:
181
+ """Λ_w(axes) as a 0-d float64 tensor in [0, 1]; exactly 0 iff some axis is 0.
182
+
183
+ Raises ``LambdaV1Error(code)`` for any input outside szl.lambda/v1.
184
+ Differentiable with respect to ``axes``.
185
+ """
186
+ x, w, _, _ = _validate(axes, weights)
187
+ return lambda_aggregate(x, w)
188
+
189
+
190
+ def _check_tau(tau: Any) -> float:
191
+ if not _is_real(tau):
192
+ raise LambdaV1Error(TAU_INVALID, f"tau is {type(tau).__name__}, not a real number")
193
+ if isinstance(tau, float) and not math.isfinite(tau):
194
+ raise LambdaV1Error(TAU_INVALID, f"tau={tau!r} is not finite")
195
+ if not 0 < tau <= 1:
196
+ raise LambdaV1Error(TAU_INVALID, f"tau={tau!r} is outside (0, 1]")
197
+ return float(tau)
198
+
199
+
200
+ def lambda_v1_gate(axes: torch.Tensor, weights: torch.Tensor, tau: float) -> LambdaV1GateResult:
201
+ """The szl.lambda/v1 gate. It never raises on bad input; it returns BLOCK with the code.
202
+
203
+ tau is required. The compare is in log space on the unrounded value, and a
204
+ tie within TIE_EPS is ABSTAIN. A verdict is ADVISORY.
205
+ """
206
+ t: Optional[float] = None
207
+ try:
208
+ t = _check_tau(tau)
209
+ x, w, xs, ws = _validate(axes, weights)
210
+ except LambdaV1Error as err:
211
+ return LambdaV1GateResult(BLOCK, err.code, None, t, True)
212
+ score = lambda_aggregate(x, w)
213
+ if any(v == 0.0 for v in xs):
214
+ return LambdaV1GateResult(NO_GO, ZERO_VETO, score, t, True)
215
+ log_lam = math.fsum(wk * math.log(xk) for xk, wk in zip(xs, ws))
216
+ delta = log_lam - math.log(t)
217
+ if abs(delta) <= TIE_EPS:
218
+ return LambdaV1GateResult(ABSTAIN, NUMERIC_TIE, score, t, True)
219
+ if delta > 0:
220
+ return LambdaV1GateResult(GO, None, score, t, True)
221
+ return LambdaV1GateResult(NO_GO, BELOW_TAU, score, t, True)
build/torch-cpu/szl_lambda_gate/governed_norm/__init__.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """szl_lambda_gate.governed_norm — governed normalization kernels (folded in).
4
+
5
+ CONSOLIDATION (Wave D): this subpackage is the ``szl-governed-norm`` universal
6
+ kernel folded into the canonical ``szl-lambda-gate`` kernels package so the two
7
+ duplicate micro-repos become ONE canonical home. The source repo
8
+ ``szl-holdings/szl-governed-norm`` is DEPRECATED (see its DEPRECATED.md) and
9
+ points here; nothing was deleted — this is the additive, reversible copy.
10
+
11
+ It provides correctness-verified RMSNorm and LayerNorm that run on CPU and CUDA
12
+ and are torch.compile-friendly, plus an optional *governed* path that emits
13
+ content-addressed, SHA3-256 hash-chained receipts of each call — provenance at
14
+ the kernel layer, in the spirit of the a11oy governed-AI platform
15
+ (https://a-11-oy.com).
16
+
17
+ Usage (as a subpackage of the canonical kernel)::
18
+
19
+ import torch
20
+ from szl_lambda_gate import governed_norm as gn
21
+
22
+ print(gn.selfcheck()) # one-shot correctness + receipt check
23
+ x = torch.randn(4, 1024, dtype=torch.float16)
24
+ y = gn.rms_norm(x, eps=1e-6) # plain path
25
+ y2 = gn.rms_norm(x, eps=1e-6, governed=True) # records to the default chain
26
+ chain = gn.ReceiptChain()
27
+ y3 = gn.rms_norm(x, eps=1e-6, chain=chain) # records into YOUR chain only
28
+ print(chain.verify()) # (ok, depth, first_break_seq)
29
+
30
+ Honesty: this is a universal (pure-Python) kernel — a correctness reference,
31
+ not a hand-tuned CUDA speed record. No fabricated benchmarks. Its
32
+ differentiator is verifiable governance, not raw FLOPs. Λ = Conjecture 1
33
+ (advisory, uniqueness OPEN) — never described as proven trust anywhere.
34
+
35
+ Note on torch.compile: every op is torch.compile(fullgraph=True)-compatible.
36
+ Receipt emission is an eager-only side effect (it hashes materialized tensor
37
+ bytes), so when a *governed* call is captured into a compiled graph the
38
+ numerics are unchanged but NO receipt is recorded — govern at the eager audit
39
+ boundary. This is documented honestly and covered by tests.
40
+ """
41
+ from typing import Any, Dict, List, Optional, Tuple
42
+
43
+ import torch
44
+
45
+ from . import layers # noqa: F401 (must be importable for Hub layer mapping)
46
+ from ._norm import fused_add_rms_norm as _fused_add_rms_norm
47
+ from ._norm import layer_norm as _layer_norm
48
+ from ._norm import rms_norm as _rms_norm
49
+ from ._receipt import _GENESIS as _GENESIS_HEAD
50
+ from ._receipt import ReceiptChain, default_chain, emit_receipt
51
+
52
+ __all__ = [
53
+ "rms_norm",
54
+ "layer_norm",
55
+ "fused_add_rms_norm",
56
+ "layers",
57
+ "ReceiptChain",
58
+ "emit_receipt",
59
+ "receipt_head",
60
+ "receipt_count",
61
+ "receipt_tail",
62
+ "receipt_verify",
63
+ "selfcheck",
64
+ "DOCTRINE_FOOTER",
65
+ "__version__",
66
+ ]
67
+
68
+ __version__ = "0.2.0"
69
+ DOCTRINE_FOOTER = (
70
+ "SZL Holdings · governed normalization · provenance at the kernel layer · "
71
+ "Lambda = Conjecture 1 (advisory) · honesty over checklist"
72
+ )
73
+
74
+
75
+ def _is_tracing() -> bool:
76
+ """True while torch.compile / Dynamo is tracing this code.
77
+
78
+ Receipt emission reads materialized tensor bytes (hashing on CPU), which is
79
+ an inherently eager, side-effecting host operation that cannot live inside
80
+ a traced FX graph — so under torch.compile we skip the emit. This keeps
81
+ EVERY op torch.compile(fullgraph=True)-compatible while remaining honest:
82
+ when a governed call is captured into a compiled graph, NO receipt is
83
+ recorded (the numerics are unchanged and identical to the eager path).
84
+ Governance is intended for the eager audit boundary; record receipts there.
85
+ """
86
+ is_compiling = getattr(torch.compiler, "is_compiling", None)
87
+ return bool(is_compiling()) if is_compiling is not None else False
88
+
89
+
90
+ def _emit(
91
+ chain: Optional[ReceiptChain],
92
+ op: str,
93
+ x: torch.Tensor,
94
+ out: torch.Tensor,
95
+ eps: float,
96
+ sign_key: Optional[Any] = None,
97
+ organ: str = "szl-governed-norm",
98
+ ) -> None:
99
+ """Append a receipt to ``chain`` (or the process default chain if None).
100
+
101
+ No-op while torch.compile is tracing (see ``_is_tracing``). When
102
+ ``sign_key`` (a PEM ECDSA-P256 private key) is supplied and szl-receipt is
103
+ installed, the receipt carries an additive DSSE ``signature`` envelope;
104
+ keyless is UNSIGNED-honest.
105
+ """
106
+ if _is_tracing():
107
+ return
108
+ target = chain if chain is not None else default_chain()
109
+ target.emit(op, x, out, eps, sign_key=sign_key, organ=organ)
110
+
111
+
112
+ def rms_norm(
113
+ x: torch.Tensor,
114
+ weight: Optional[torch.Tensor] = None,
115
+ eps: float = 1e-6,
116
+ governed: bool = False,
117
+ chain: Optional[ReceiptChain] = None,
118
+ sign_key: Optional[Any] = None,
119
+ organ: str = "szl-governed-norm",
120
+ ) -> torch.Tensor:
121
+ """RMSNorm over the last dim.
122
+
123
+ If ``governed=True``, append an audit receipt. By default the receipt goes
124
+ to the process-wide default chain (convenient). Pass your own ``chain`` (a
125
+ ``ReceiptChain`` instance) to record into a caller-owned chain instead —
126
+ this avoids global-state contention when many threads/requests govern
127
+ independently. Passing ``chain`` implies governance even if
128
+ ``governed=False`` is left at its default. Pass ``sign_key`` (PEM
129
+ ECDSA-P256) to additively sign the receipt via szl-receipt.
130
+ """
131
+ out = _rms_norm(x, weight=weight, eps=eps)
132
+ if governed or chain is not None:
133
+ _emit(chain, "rms_norm", x, out, eps, sign_key=sign_key, organ=organ)
134
+ return out
135
+
136
+
137
+ def layer_norm(
138
+ x: torch.Tensor,
139
+ weight: Optional[torch.Tensor] = None,
140
+ bias: Optional[torch.Tensor] = None,
141
+ eps: float = 1e-5,
142
+ governed: bool = False,
143
+ chain: Optional[ReceiptChain] = None,
144
+ sign_key: Optional[Any] = None,
145
+ organ: str = "szl-governed-norm",
146
+ ) -> torch.Tensor:
147
+ """LayerNorm over the last dim.
148
+
149
+ If ``governed=True`` (or a ``chain`` is supplied), append an audit receipt
150
+ to ``chain`` when given, otherwise to the process default chain. See
151
+ ``rms_norm`` for the per-call ``chain`` rationale and ``sign_key``.
152
+ """
153
+ out = _layer_norm(x, weight=weight, bias=bias, eps=eps)
154
+ if governed or chain is not None:
155
+ _emit(chain, "layer_norm", x, out, eps, sign_key=sign_key, organ=organ)
156
+ return out
157
+
158
+
159
+ def fused_add_rms_norm(
160
+ x: torch.Tensor,
161
+ residual: torch.Tensor,
162
+ weight: Optional[torch.Tensor] = None,
163
+ eps: float = 1e-6,
164
+ governed: bool = False,
165
+ chain: Optional[ReceiptChain] = None,
166
+ sign_key: Optional[Any] = None,
167
+ organ: str = "szl-governed-norm",
168
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
169
+ """Residual-add + RMSNorm (transformer block pattern).
170
+
171
+ Returns ``(y, new_residual)`` where ``new_residual = x + residual`` and
172
+ ``y = rms_norm(new_residual, weight, eps)``. If ``governed=True`` (or a
173
+ ``chain`` is supplied), append an audit receipt over the normalized output
174
+ to ``chain`` when given, otherwise to the process default chain. Pass
175
+ ``sign_key`` to additively sign the receipt via szl-receipt.
176
+ """
177
+ out, new_residual = _fused_add_rms_norm(x, residual, weight=weight, eps=eps)
178
+ if governed or chain is not None:
179
+ _emit(chain, "fused_add_rms_norm", x, out, eps, sign_key=sign_key, organ=organ)
180
+ return out, new_residual
181
+
182
+
183
+ # ---- governance receipt surface (operates on the default in-process chain) --
184
+ def receipt_head() -> str:
185
+ """SHA3-256 head of the governed-call receipt chain ('0'*64 if empty)."""
186
+ return default_chain().head()
187
+
188
+
189
+ def receipt_count() -> int:
190
+ """Number of governed calls recorded."""
191
+ return default_chain().count()
192
+
193
+
194
+ def receipt_tail(n: int = 10) -> List[Dict[str, Any]]:
195
+ """Last n receipts."""
196
+ return default_chain().tail(n)
197
+
198
+
199
+ def receipt_verify() -> Dict[str, Any]:
200
+ """Re-walk the receipt chain. Returns {ok, depth, first_break_seq}."""
201
+ ok, depth, brk = default_chain().verify()
202
+ return {"ok": ok, "depth": depth, "first_break_seq": brk, "head": default_chain().head()}
203
+
204
+
205
+ # ---- one-shot self-verification --------------------------------------------
206
+ def selfcheck() -> Dict[str, Any]:
207
+ """Verify correctness + governance in a single call; never raises.
208
+
209
+ Runs a tiny, self-contained, CPU-only smoke test against PyTorch references
210
+ so downstream code (and SZL's own a11oy / hatun-mcp) can confirm the loaded
211
+ kernel is the real, working article before trusting it.
212
+
213
+ Checks (all on a *private, throwaway* ReceiptChain so the process default
214
+ chain is never touched):
215
+ * ``rms_norm`` matches a Llama-style float32 reference,
216
+ * ``layer_norm`` matches ``torch.nn.functional.layer_norm``,
217
+ * ``fused_add_rms_norm`` matches the unfused add-then-norm path,
218
+ * a governed call emits exactly one receipt and the chain verifies.
219
+
220
+ Returns a JSON-able dict:
221
+ ``{ok, version, checks: {name: bool}, receipt_ok, receipt_head, error}``
222
+ ``ok`` is True iff every check passed. On unexpected failure ``ok`` is
223
+ False and ``error`` carries the message — this function is designed to be
224
+ safe to call in a health probe and will not raise.
225
+ """
226
+ checks: Dict[str, bool] = {}
227
+ receipt_ok = False
228
+ receipt_head = _GENESIS_HEAD
229
+ error = None
230
+ try:
231
+ torch.manual_seed(0)
232
+ x = torch.randn(4, 64, dtype=torch.float32)
233
+ w = torch.randn(64, dtype=torch.float32)
234
+ b = torch.randn(64, dtype=torch.float32)
235
+ res = torch.randn(4, 64, dtype=torch.float32)
236
+ eps_r, eps_l = 1e-6, 1e-5
237
+
238
+ # rms_norm vs Llama-style fp32 reference
239
+ xf = x.to(torch.float32)
240
+ ref_rms = (xf * torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + eps_r)) * w
241
+ checks["rms_norm"] = bool(
242
+ torch.allclose(rms_norm(x, weight=w, eps=eps_r), ref_rms, rtol=1e-5, atol=1e-5)
243
+ )
244
+
245
+ # layer_norm vs torch reference
246
+ ref_ln = torch.nn.functional.layer_norm(x, (64,), weight=w, bias=b, eps=eps_l)
247
+ checks["layer_norm"] = bool(
248
+ torch.allclose(layer_norm(x, weight=w, bias=b, eps=eps_l), ref_ln,
249
+ rtol=1e-5, atol=1e-5)
250
+ )
251
+
252
+ # fused_add_rms_norm vs unfused path
253
+ y_f, new_res = fused_add_rms_norm(x, res, weight=w, eps=eps_r)
254
+ h = x.to(torch.float32) + res.to(torch.float32)
255
+ ref_y = rms_norm(h.to(x.dtype), weight=w, eps=eps_r)
256
+ checks["fused_add_rms_norm"] = bool(
257
+ torch.allclose(y_f, ref_y, rtol=1e-5, atol=1e-5)
258
+ and torch.allclose(new_res, h.to(x.dtype), rtol=1e-6, atol=1e-6)
259
+ )
260
+
261
+ # governance on a private chain: one emit, chain verifies
262
+ probe_chain = ReceiptChain()
263
+ rms_norm(x, weight=w, eps=eps_r, chain=probe_chain)
264
+ ok, depth, brk = probe_chain.verify()
265
+ receipt_ok = bool(ok and depth == 1 and brk == -1)
266
+ receipt_head = probe_chain.head()
267
+ checks["governance"] = receipt_ok
268
+ except Exception as exc: # never raise from a health probe
269
+ error = f"{type(exc).__name__}: {exc}"
270
+
271
+ ok = bool(checks) and all(checks.values()) and error is None
272
+ return {
273
+ "ok": ok,
274
+ "version": __version__,
275
+ "checks": checks,
276
+ "receipt_ok": receipt_ok,
277
+ "receipt_head": receipt_head,
278
+ "error": error,
279
+ }
build/torch-cpu/szl_lambda_gate/governed_norm/_norm.py ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Pure-PyTorch normalization primitives for the SZL governed-norm kernel.
4
+
5
+ These are correctness-verified reference implementations (RMSNorm, LayerNorm,
6
+ and the residual-fused RMSNorm pattern used by transformer blocks) written in
7
+ pure PyTorch. They run on CPU and CUDA, are torch.compile-friendly, and depend
8
+ ONLY on torch + the Python standard library (a Kernel Hub requirement for
9
+ universal kernels).
10
+
11
+ HONESTY: this is a *universal* (pure-Python) kernel. It does NOT ship a
12
+ hand-tuned CUDA/Triton binary, so it is a correctness reference, not a
13
+ speed record. We make no fabricated benchmark claims. Where it adds value
14
+ is the optional *governed* path (see _receipt.py): every normalization call
15
+ can emit a content-addressed, hash-chained receipt of its inputs/outputs so
16
+ the operation is auditable — SZL Holdings' provenance doctrine applied at
17
+ the kernel layer.
18
+
19
+ Numerical convention (all ops): reductions and the normalization math are
20
+ computed in float32 for stability, then the result is cast back to the input
21
+ dtype. This is the standard Llama-style convention and is what makes
22
+ float16 / bfloat16 inputs numerically well-behaved.
23
+
24
+ Validation convention: guards below are cheap, branch-only checks on metadata
25
+ (dtype / ndim / shape / device) — they allocate nothing on the happy path and
26
+ constant-fold away under torch.compile, so they do not perturb traced graphs.
27
+ They exist to turn silent broadcasting / device-mismatch bugs into clear,
28
+ early errors. A zero-size normalized last dimension is rejected (normalizing
29
+ over zero elements is undefined); a single-element last dimension is allowed
30
+ (RMSNorm yields sign(x); LayerNorm yields 0, matching F.layer_norm).
31
+
32
+ Non-finite convention (NaN / Inf inputs): these ops do NOT sanitize their
33
+ input. A NaN or Inf in the input propagates through the reduction and appears
34
+ in the output, exactly as it would in torch.nn.functional.layer_norm / a
35
+ hand-written kernel. We deliberately do NOT silently replace non-finite values
36
+ (that would hide upstream numerical bugs); detecting/handling them is the
37
+ caller's responsibility. This propagation behavior is covered by regression
38
+ tests so it cannot change unnoticed.
39
+ """
40
+ from typing import Optional
41
+
42
+ import torch
43
+
44
+ # Floating dtypes this kernel supports. Integer / complex inputs are rejected
45
+ # early with a clear message rather than silently producing garbage.
46
+ _SUPPORTED_DTYPES = (torch.float16, torch.bfloat16, torch.float32, torch.float64)
47
+
48
+
49
+ def _compute_dtype(in_dtype: torch.dtype) -> torch.dtype:
50
+ """Reduction/normalization compute dtype.
51
+
52
+ Low-precision inputs (fp16/bf16) are upcast to float32 for stability — the
53
+ standard Llama-style convention. float64 inputs are NOT downcast: doing so
54
+ would silently lose precision (and break gradcheck), so we keep float64.
55
+ """
56
+ return torch.float32 if in_dtype in (torch.float16, torch.bfloat16) else in_dtype
57
+
58
+
59
+ def _check_input(x: torch.Tensor, name: str = "x") -> None:
60
+ """Cheap, allocation-free guards on the primary input tensor.
61
+
62
+ Only inspects metadata (type / dtype / ndim), so it is constant-folded by
63
+ torch.compile and adds no runtime tensor work on the happy path.
64
+ """
65
+ if not isinstance(x, torch.Tensor):
66
+ raise TypeError(f"{name} must be a torch.Tensor, got {type(x).__name__}")
67
+ if x.dtype not in _SUPPORTED_DTYPES:
68
+ raise TypeError(
69
+ f"{name} has unsupported dtype {x.dtype}; "
70
+ f"expected one of {tuple(str(d) for d in _SUPPORTED_DTYPES)}"
71
+ )
72
+ if x.dim() < 1:
73
+ raise ValueError(
74
+ f"{name} must have at least 1 dimension (the normalized dim); "
75
+ f"got a {x.dim()}-d tensor"
76
+ )
77
+ # A zero-size normalized (last) dimension is mathematically undefined:
78
+ # mean/RMS over zero elements is NaN, so normalization has no meaning.
79
+ # Reject it early with a clear message instead of silently returning an
80
+ # empty/NaN tensor (the classic shape-bug-masquerading-as-success case).
81
+ if x.shape[-1] == 0:
82
+ raise ValueError(
83
+ f"{name} has a zero-size normalized last dimension {tuple(x.shape)}; "
84
+ f"normalization over zero elements is undefined"
85
+ )
86
+
87
+
88
+ def _check_affine(
89
+ x: torch.Tensor,
90
+ param: Optional[torch.Tensor],
91
+ name: str,
92
+ ) -> None:
93
+ """Validate an optional affine parameter (weight/bias/residual peer).
94
+
95
+ Enforces that the parameter is 1-D and matches the normalized (last)
96
+ dimension, and lives on the same device as ``x``. This catches the
97
+ classic silent-broadcast bug where a mis-shaped weight would broadcast
98
+ instead of erroring. Metadata-only: no allocations.
99
+ """
100
+ if param is None:
101
+ return
102
+ if not isinstance(param, torch.Tensor):
103
+ raise TypeError(f"{name} must be a torch.Tensor or None, got {type(param).__name__}")
104
+ if param.device != x.device:
105
+ raise ValueError(
106
+ f"{name} is on device {param.device} but x is on {x.device}; "
107
+ f"move them to the same device"
108
+ )
109
+ last = x.shape[-1]
110
+ if param.dim() != 1 or param.shape[0] != last:
111
+ raise ValueError(
112
+ f"{name} must be 1-D with shape ({last},) to match the normalized "
113
+ f"last dimension of x; got shape {tuple(param.shape)}"
114
+ )
115
+
116
+
117
+ def _check_eps(eps: float) -> None:
118
+ """eps must be a positive, finite scalar (rsqrt(var+eps) must be safe)."""
119
+ e = float(eps)
120
+ if not (e > 0.0) or e != e or e == float("inf"):
121
+ raise ValueError(f"eps must be a positive finite float, got {eps!r}")
122
+
123
+
124
+ def rms_norm(
125
+ x: torch.Tensor,
126
+ weight: Optional[torch.Tensor] = None,
127
+ eps: float = 1e-6,
128
+ ) -> torch.Tensor:
129
+ """Root-mean-square layer normalization over the last dimension.
130
+
131
+ y = x / sqrt(mean(x^2, dim=-1) + eps) * weight
132
+
133
+ Computed in float32 for numerical stability, then cast back to the input
134
+ dtype (the standard, correctness-preserving convention used by Llama-style
135
+ RMSNorm). `weight` is optional; when omitted, no affine scale is applied.
136
+
137
+ Raises clear TypeError/ValueError on bad dtype, rank, eps, or a weight
138
+ whose shape/device does not match x's normalized dimension.
139
+ """
140
+ _check_input(x)
141
+ _check_eps(eps)
142
+ _check_affine(x, weight, "weight")
143
+
144
+ in_dtype = x.dtype
145
+ xf = x.to(_compute_dtype(in_dtype))
146
+ variance = xf.pow(2).mean(dim=-1, keepdim=True)
147
+ xf = xf * torch.rsqrt(variance + eps)
148
+ out = xf.to(in_dtype)
149
+ if weight is not None:
150
+ out = out * weight
151
+ return out
152
+
153
+
154
+ def layer_norm(
155
+ x: torch.Tensor,
156
+ weight: Optional[torch.Tensor] = None,
157
+ bias: Optional[torch.Tensor] = None,
158
+ eps: float = 1e-5,
159
+ ) -> torch.Tensor:
160
+ """Standard layer normalization over the last dimension.
161
+
162
+ Mean/variance computed in float32 for stability, then cast back. Matches
163
+ torch.nn.functional.layer_norm semantics for the normalized-shape = last
164
+ dim case; verified against it in the test suite.
165
+
166
+ Raises clear TypeError/ValueError on bad dtype, rank, eps, or a
167
+ weight/bias whose shape/device does not match x's normalized dimension.
168
+ """
169
+ _check_input(x)
170
+ _check_eps(eps)
171
+ _check_affine(x, weight, "weight")
172
+ _check_affine(x, bias, "bias")
173
+
174
+ in_dtype = x.dtype
175
+ xf = x.to(_compute_dtype(in_dtype))
176
+ mean = xf.mean(dim=-1, keepdim=True)
177
+ # Biased (population) variance = mean of squared deviations. We compute it
178
+ # directly rather than via Tensor.var(unbiased=False): torch's .var emits a
179
+ # "degrees of freedom <= 0" UserWarning when the normalized dim has a single
180
+ # element, even though unbiased=False is well-defined there (variance 0).
181
+ # Computing it ourselves matches F.layer_norm exactly and stays silent and
182
+ # torch.compile(fullgraph=True)-clean for the single-element edge case.
183
+ centered = xf - mean
184
+ var = centered.pow(2).mean(dim=-1, keepdim=True)
185
+ xf = centered * torch.rsqrt(var + eps)
186
+ out = xf.to(in_dtype)
187
+ if weight is not None:
188
+ out = out * weight
189
+ if bias is not None:
190
+ out = out + bias
191
+ return out
192
+
193
+
194
+ def fused_add_rms_norm(
195
+ x: torch.Tensor,
196
+ residual: torch.Tensor,
197
+ weight: Optional[torch.Tensor] = None,
198
+ eps: float = 1e-6,
199
+ ):
200
+ """Residual-add followed by RMSNorm — the canonical transformer block pattern.
201
+
202
+ h = x + residual # updated residual stream
203
+ y = rms_norm(h, weight, eps)
204
+ return y, h
205
+
206
+ This mirrors the `fused_add_rms_norm` used in real LLM inference stacks
207
+ (e.g. the pre-norm transformer block: the normalized output `y` feeds the
208
+ sublayer, while the un-normalized sum `h` is carried forward as the next
209
+ residual). We return BOTH so callers can thread the residual stream, which
210
+ is exactly why the fused form exists.
211
+
212
+ HONESTY: "fused" here means *logically* fused (one Python op, one float32
213
+ cast path, the add done in float32 alongside the norm) — it is a correct,
214
+ allocation-conscious pure-PyTorch reference, not a hand-written fused CUDA
215
+ kernel. No speed claims are made.
216
+
217
+ The add is performed in float32 so that, for float16/bfloat16 inputs, the
218
+ residual accumulation does not lose precision before normalization — this
219
+ matches high-quality reference implementations.
220
+ """
221
+ _check_input(x, "x")
222
+ _check_input(residual, "residual")
223
+ _check_eps(eps)
224
+ if residual.shape != x.shape:
225
+ raise ValueError(
226
+ f"residual shape {tuple(residual.shape)} must equal x shape "
227
+ f"{tuple(x.shape)} for the residual add"
228
+ )
229
+ if residual.device != x.device:
230
+ raise ValueError(
231
+ f"residual is on device {residual.device} but x is on {x.device}; "
232
+ f"move them to the same device"
233
+ )
234
+ _check_affine(x, weight, "weight")
235
+
236
+ in_dtype = x.dtype
237
+ cdt = _compute_dtype(in_dtype)
238
+ # Add in compute dtype, keep both the normalized output and the residual.
239
+ hf = x.to(cdt) + residual.to(cdt)
240
+ new_residual = hf.to(in_dtype)
241
+ variance = hf.pow(2).mean(dim=-1, keepdim=True)
242
+ yf = hf * torch.rsqrt(variance + eps)
243
+ out = yf.to(in_dtype)
244
+ if weight is not None:
245
+ out = out * weight
246
+ return out, new_residual
build/torch-cpu/szl_lambda_gate/governed_norm/_receipt.py ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Content-addressed governance receipts for normalization calls.
4
+
5
+ SZL Holdings' provenance doctrine applied at the kernel layer: when a
6
+ normalization runs in *governed* mode, it emits a small, deterministic
7
+ receipt describing the call — input shape/dtype, eps, and a SHA3-256 digest
8
+ of the (quantized) output tensor — and hash-chains it to the previous
9
+ receipt. This makes a sequence of kernel calls independently auditable
10
+ without trusting the caller.
11
+
12
+ HONESTY:
13
+ - The digest is a real SHA3-256 over the output bytes (rounded to a fixed
14
+ decimal precision so it is reproducible across runs/devices). It is an
15
+ integrity fingerprint, NOT a cryptographic signature — we never claim
16
+ it proves authorship. DSSE signing is a separate, out-of-band concern.
17
+ - Receipts are kept in an in-process, append-only chain. Nothing is written
18
+ to disk or the network from inside the kernel.
19
+ - Stdlib + torch (+ numpy for the output digest) only — Kernel Hub
20
+ universal-kernel requirement.
21
+ - The canonical szl-receipt v0.2.0 evidence binding (``emit_receipt``) is
22
+ ADDITIVE and IMPORT-GUARDED: with szl-receipt absent it returns ``None`` and
23
+ the kernel runs unchanged. It binds subject / input-digest / output-digest /
24
+ policy-id / energy; energy is the literal string "UNAVAILABLE" because this
25
+ kernel measures NO joules — a value is never fabricated. Like the SHA3-256
26
+ chain, it is an EVIDENCE trail, NOT a proof of correctness.
27
+ """
28
+ import hashlib
29
+ import json
30
+ import threading
31
+ import time
32
+ from typing import Any, Dict, List, Optional, Union
33
+
34
+ import torch
35
+
36
+ _GENESIS = "0" * 64
37
+
38
+ # Logical signing-authority label stamped onto signature envelopes.
39
+ _ORGAN = "szl-governed-norm"
40
+
41
+ # Governing policy id bound into every canonical szl-receipt evidence binding.
42
+ _POLICY_ID = "szl-governed-norm/provenance@v1"
43
+
44
+ # This universal kernel measures NO joules. The honesty doctrine forbids
45
+ # fabricating an energy value, so the canonical binding records the literal
46
+ # string "UNAVAILABLE" rather than a placeholder number.
47
+ _ENERGY_UNAVAILABLE = "UNAVAILABLE"
48
+
49
+
50
+ def _maybe_sign(
51
+ body: Dict[str, Any],
52
+ sign_key: Optional[Union[str, bytes]],
53
+ organ: str,
54
+ ) -> Optional[Dict[str, Any]]:
55
+ """ADDITIVE szl-receipt signature layer over the receipt *body*.
56
+
57
+ Returns a DSSE envelope (from ``szl_receipt.sign_receipt``) covering the
58
+ exact canonical body, or ``None`` when szl-receipt is not installed (the
59
+ kernel then behaves exactly as before). Doctrine: with no *sign_key* the
60
+ envelope is UNSIGNED-honest (``signed=False``); a signature is NEVER
61
+ fabricated. This is distinct from and additive to the SHA3-256 chain
62
+ integrity hash (``digest``) — szl-receipt's envelope carries its own
63
+ SHA-256 ``digest``/``algo`` so the two integrity hashes are explicit.
64
+ """
65
+ try:
66
+ from szl_receipt import Receipt, sign_receipt
67
+ except Exception: # noqa: BLE001 - signing is optional; absence is honest
68
+ return None
69
+ env = sign_receipt(Receipt(kind="governed-norm", body=body),
70
+ sign_key, organ=organ)
71
+ return env
72
+
73
+
74
+ def _tensor_digest(t: torch.Tensor, decimals: int = 6) -> str:
75
+ """Deterministic SHA3-256 over a tensor's rounded float32 contents.
76
+
77
+ Rounding to a fixed number of decimals makes the digest stable across
78
+ devices/dtypes for the same logical values (tiny FP noise won't change
79
+ it). This is an integrity fingerprint, not a signature.
80
+ """
81
+ flat = t.detach().to(torch.float32).reshape(-1)
82
+ # Round to `decimals` places, integerize, hash the raw bytes. CPU move is
83
+ # required to read bytes; kept O(n) and allocation-light.
84
+ scaled = torch.round(flat * (10 ** decimals)).to(torch.int64).cpu().numpy().tobytes()
85
+ h = hashlib.sha3_256()
86
+ h.update(scaled)
87
+ return h.hexdigest()
88
+
89
+
90
+ def _input_digest(x: torch.Tensor, eps: float) -> str:
91
+ """SHA3-256 over the canonical JSON of a call's input spec.
92
+
93
+ Binds {input shape, dtype, eps} — the *shape* of the call, not the input
94
+ bytes — so the receipt is a compact fingerprint of what produced the
95
+ output. Deterministic and stdlib-only (json + hashlib).
96
+ """
97
+ spec = {
98
+ "in_shape": list(x.shape),
99
+ "in_dtype": str(x.dtype).replace("torch.", ""),
100
+ "eps": float(eps),
101
+ }
102
+ raw = json.dumps(spec, sort_keys=True, separators=(",", ":")).encode("utf-8")
103
+ return hashlib.sha3_256(raw).hexdigest()
104
+
105
+
106
+ def emit_receipt(
107
+ op: str,
108
+ x: torch.Tensor,
109
+ out: torch.Tensor,
110
+ eps: float,
111
+ subject: Optional[str] = None,
112
+ policy_id: str = _POLICY_ID,
113
+ sign_key: Optional[Union[str, bytes]] = None,
114
+ organ: str = _ORGAN,
115
+ ) -> Optional[Dict[str, Any]]:
116
+ """Canonical szl-receipt v0.2.0 evidence binding for a governed-norm call.
117
+
118
+ ADDITIVE and IMPORT-GUARDED: returns ``None`` when szl-receipt is not
119
+ installed, so this universal Kernel-Hub kernel still imports and runs on
120
+ stdlib + torch + numpy alone. When szl-receipt is present it binds an
121
+ EVIDENCE trail and wraps it in a DSSE envelope via ``sign_receipt``:
122
+
123
+ subject organ / norm-call id (who/what emitted this)
124
+ input_digest SHA3-256 over canonical {input shape, dtype, eps}
125
+ output_digest the EXISTING SHA3-256 rounded-tensor digest of ``out``
126
+ policy_id the governing policy id
127
+ energy the literal string "UNAVAILABLE"
128
+
129
+ Doctrine (non-negotiable):
130
+ * A receipt is an integrity/EVIDENCE trail, NOT a proof of correctness.
131
+ * ``energy == "UNAVAILABLE"`` — this kernel measures NO joules; a joule is
132
+ NEVER fabricated.
133
+ * Keyless => UNSIGNED-honest (``signature["signed"] is False``); a
134
+ signature is NEVER fabricated. A real ``sign_key`` yields a real DSSE
135
+ signature over the exact canonical binding.
136
+
137
+ Returns the binding dict (subject/input_digest/output_digest/policy_id/
138
+ energy) with the DSSE envelope under ``signature``, or ``None`` when
139
+ szl-receipt is absent.
140
+ """
141
+ try:
142
+ from szl_receipt import Receipt, sign_receipt
143
+ except Exception: # noqa: BLE001 - canonical binding is optional; absence is honest
144
+ return None
145
+ body = {
146
+ "subject": subject if subject is not None else f"{organ}/{op}",
147
+ "input_digest": _input_digest(x, eps),
148
+ "output_digest": _tensor_digest(out),
149
+ "policy_id": policy_id,
150
+ "energy": _ENERGY_UNAVAILABLE,
151
+ }
152
+ env = sign_receipt(Receipt(kind="governed-norm", body=body), sign_key, organ=organ)
153
+ return dict(body, signature=env)
154
+
155
+
156
+ class ReceiptChain:
157
+ """Append-only, SHA3-256 hash-chained log of normalization receipts.
158
+
159
+ Each receipt: {seq, op, in_shape, in_dtype, eps, out_digest, prev, digest, ts}
160
+ digest = SHA3-256 over the canonical JSON body (excluding digest/ts).
161
+ verify() re-walks the chain and returns (ok, depth, first_break_seq).
162
+ """
163
+
164
+ def __init__(self) -> None:
165
+ self._lock = threading.RLock()
166
+ self._records: List[Dict[str, Any]] = []
167
+
168
+ @staticmethod
169
+ def _digest_body(body: Dict[str, Any]) -> str:
170
+ raw = json.dumps(body, sort_keys=True, separators=(",", ":")).encode("utf-8")
171
+ return hashlib.sha3_256(raw).hexdigest()
172
+
173
+ def emit(
174
+ self,
175
+ op: str,
176
+ x: torch.Tensor,
177
+ out: torch.Tensor,
178
+ eps: float,
179
+ sign_key: Optional[Union[str, bytes]] = None,
180
+ organ: str = _ORGAN,
181
+ policy_id: str = _POLICY_ID,
182
+ ) -> Dict[str, Any]:
183
+ with self._lock:
184
+ prev = self._records[-1]["digest"] if self._records else _GENESIS
185
+ seq = len(self._records)
186
+ body = {
187
+ "seq": seq,
188
+ "op": op,
189
+ "in_shape": list(x.shape),
190
+ "in_dtype": str(x.dtype).replace("torch.", ""),
191
+ "eps": float(eps),
192
+ "out_digest": _tensor_digest(out),
193
+ "prev": prev,
194
+ }
195
+ digest = self._digest_body(body)
196
+ rec = dict(body, digest=digest, ts=time.time())
197
+ sig = _maybe_sign(body, sign_key, organ)
198
+ if sig is not None:
199
+ rec["signature"] = sig
200
+ # ADDITIVE canonical szl-receipt v0.2.0 evidence binding. Import-
201
+ # guarded: None when szl-receipt is absent, so the universal kernel
202
+ # keeps working on stdlib + torch + numpy only. Binds subject /
203
+ # input-digest / output-digest / policy-id / energy; energy is
204
+ # "UNAVAILABLE" (no joules measured here). It does NOT enter the
205
+ # SHA3-256 chain body, so verify() is unaffected.
206
+ binding = emit_receipt(
207
+ op, x, out, eps,
208
+ subject=f"{organ}/{op}#{seq}",
209
+ policy_id=policy_id,
210
+ sign_key=sign_key,
211
+ organ=organ,
212
+ )
213
+ if binding is not None:
214
+ rec["receipt"] = binding
215
+ self._records.append(rec)
216
+ return rec
217
+
218
+ def head(self) -> str:
219
+ with self._lock:
220
+ return self._records[-1]["digest"] if self._records else _GENESIS
221
+
222
+ def count(self) -> int:
223
+ with self._lock:
224
+ return len(self._records)
225
+
226
+ def tail(self, n: int = 10) -> List[Dict[str, Any]]:
227
+ with self._lock:
228
+ return list(self._records[-n:])
229
+
230
+ def verify(self):
231
+ """Re-walk the chain. Returns (ok: bool, depth: int, first_break: int)."""
232
+ with self._lock:
233
+ prev = _GENESIS
234
+ for i, rec in enumerate(self._records):
235
+ body = {k: rec[k] for k in
236
+ ("seq", "op", "in_shape", "in_dtype", "eps", "out_digest", "prev")}
237
+ if rec["prev"] != prev or rec["digest"] != self._digest_body(body):
238
+ return (False, len(self._records), i)
239
+ prev = rec["digest"]
240
+ return (True, len(self._records), -1)
241
+
242
+
243
+ # Module-level default chain (opt-in: only written when governed=True is used).
244
+ _DEFAULT_CHAIN: Optional[ReceiptChain] = None
245
+ _chain_lock = threading.Lock()
246
+
247
+
248
+ def default_chain() -> ReceiptChain:
249
+ global _DEFAULT_CHAIN
250
+ with _chain_lock:
251
+ if _DEFAULT_CHAIN is None:
252
+ _DEFAULT_CHAIN = ReceiptChain()
253
+ return _DEFAULT_CHAIN
build/torch-cpu/szl_lambda_gate/governed_norm/layers.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Hub-compliant kernel layers.
4
+
5
+ Per the Kernel Hub `kernel-requirements`, layers exposed for extension must
6
+ be PURE torch.nn.Module subclasses:
7
+ - no custom __init__,
8
+ - no class variables,
9
+ - only a `forward` method,
10
+ - forward signature compatible with the module it extends.
11
+
12
+ These layers therefore read their parameters (weight/bias/eps) off the
13
+ module instance they are bound to (set by the host model), and only define
14
+ `forward`. They are drop-in replacements for an existing RMSNorm/LayerNorm
15
+ module via the `kernels` layer-mapping mechanism.
16
+ """
17
+ import torch
18
+ from torch import nn
19
+
20
+ from ._norm import fused_add_rms_norm, layer_norm, rms_norm
21
+
22
+
23
+ class RMSNorm(nn.Module):
24
+ """Pure RMSNorm layer. Expects the host module to provide `self.weight`
25
+ (optional) and `self.variance_epsilon` or `self.eps`."""
26
+
27
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
28
+ weight = getattr(self, "weight", None)
29
+ eps = getattr(self, "variance_epsilon", None)
30
+ if eps is None:
31
+ eps = getattr(self, "eps", 1e-6)
32
+ return rms_norm(hidden_states, weight=weight, eps=float(eps))
33
+
34
+
35
+ class LayerNorm(nn.Module):
36
+ """Pure LayerNorm layer. Expects the host module to provide `self.weight`
37
+ (optional), `self.bias` (optional), and `self.eps`."""
38
+
39
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
40
+ weight = getattr(self, "weight", None)
41
+ bias = getattr(self, "bias", None)
42
+ eps = getattr(self, "eps", 1e-5)
43
+ return layer_norm(hidden_states, weight=weight, bias=bias, eps=float(eps))
44
+
45
+
46
+ class FusedAddRMSNorm(nn.Module):
47
+ """Pure residual-add + RMSNorm layer for pre-norm transformer blocks.
48
+
49
+ Expects the host module to provide `self.weight` (optional) and
50
+ `self.variance_epsilon` or `self.eps`. Returns `(normalized, new_residual)`
51
+ where `new_residual = hidden_states + residual` is carried forward as the
52
+ next block's residual stream.
53
+ """
54
+
55
+ def forward(self, hidden_states: torch.Tensor, residual: torch.Tensor):
56
+ weight = getattr(self, "weight", None)
57
+ eps = getattr(self, "variance_epsilon", None)
58
+ if eps is None:
59
+ eps = getattr(self, "eps", 1e-6)
60
+ return fused_add_rms_norm(hidden_states, residual, weight=weight, eps=float(eps))
build/torch-cpu/szl_lambda_gate/layers.py CHANGED
@@ -1,51 +1,54 @@
1
- # SPDX-License-Identifier: Apache-2.0
2
- # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
- """Hub-compliant kernel layer for the szl-lambda-gate kernel.
4
-
5
- Per the Kernel Hub `kernel-requirements`, layers exposed for extension must be
6
- PURE torch.nn.Module subclasses:
7
- - no custom __init__,
8
- - no class variables,
9
- - only a `forward` method.
10
-
11
- The layer therefore reads its parameters (weights / threshold) off the module
12
- instance it is bound to (set by the host model) and only defines `forward`.
13
-
14
- HONESTY: `LambdaGate` emits an ADVISORY governance signal (the weighted
15
- geometric mean Λ plus a pass/fail vs threshold). Λ is NOT proven trust; its
16
- uniqueness is Conjecture 1 (open).
17
- """
18
- import torch
19
- from torch import nn
20
-
21
- from ._lambda import lambda_aggregate, lambda_gate
22
-
23
-
24
- class LambdaGate(nn.Module):
25
- """Pure Λ-gate layer.
26
-
27
- Reads optional ``self.weights`` (1-D, length k) and ``self.threshold``
28
- (float, default 0.5) off the bound module instance.
29
-
30
- forward(axes) -> LambdaGateResult(score, passed, threshold, advisory) where
31
- ``score`` = Λ(axes) over the last dim and ``passed`` = score >= threshold.
32
- Differentiable in ``score`` w.r.t. ``axes``.
33
- """
34
-
35
- def forward(self, axes: torch.Tensor):
36
- weights = getattr(self, "weights", None)
37
- threshold = getattr(self, "threshold", 0.5)
38
- return lambda_gate(axes, weights=weights, threshold=float(threshold))
39
-
40
-
41
- class LambdaAggregate(nn.Module):
42
- """Pure Λ-aggregator layer: forward(axes) -> Λ(axes) tensor in [0,1].
43
-
44
- Reads optional ``self.weights`` (1-D, length k) off the bound module
45
- instance; uniform weights when absent. Returns just the score (no gate),
46
- fully differentiable w.r.t. ``axes``.
47
- """
48
-
49
- def forward(self, axes: torch.Tensor) -> torch.Tensor:
50
- weights = getattr(self, "weights", None)
51
- return lambda_aggregate(axes, weights=weights)
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Hub-compliant kernel layer for the szl-lambda-gate kernel.
4
+
5
+ Per the Kernel Hub `kernel-requirements`, layers exposed for extension must be
6
+ PURE torch.nn.Module subclasses:
7
+ - no custom __init__,
8
+ - no class variables,
9
+ - only a `forward` method.
10
+
11
+ The layer therefore reads its parameters (weights / threshold) off the module
12
+ instance it is bound to (set by the host model) and only defines `forward`.
13
+
14
+ HONESTY: `LambdaGate` emits an ADVISORY governance signal (the weighted
15
+ geometric mean Λ plus a pass/fail vs threshold). Λ is NOT proven trust; its
16
+ uniqueness is Conjecture 1 (open).
17
+ """
18
+ import torch
19
+ from torch import nn
20
+
21
+ from ._lambda import lambda_aggregate, lambda_gate
22
+
23
+
24
+ class LambdaGate(nn.Module):
25
+ """Pure Λ-gate layer.
26
+
27
+ Reads optional ``self.weights`` (1-D, length k) and ``self.threshold``
28
+ (float) off the bound module instance. An unset threshold uses the legacy
29
+ 0.5 with a DeprecationWarning (see ``lambda_gate``); set it explicitly.
30
+
31
+ forward(axes) -> LambdaGateResult(score, passed, threshold, advisory) where
32
+ ``score`` = Λ(axes) over the last dim and ``passed`` = score >= threshold.
33
+ Differentiable in ``score`` w.r.t. ``axes``.
34
+ """
35
+
36
+ def forward(self, axes: torch.Tensor):
37
+ weights = getattr(self, "weights", None)
38
+ threshold = getattr(self, "threshold", None)
39
+ if threshold is not None:
40
+ threshold = float(threshold)
41
+ return lambda_gate(axes, weights=weights, threshold=threshold)
42
+
43
+
44
+ class LambdaAggregate(nn.Module):
45
+ """Pure Λ-aggregator layer: forward(axes) -> Λ(axes) tensor in [0,1].
46
+
47
+ Reads optional ``self.weights`` (1-D, length k) off the bound module
48
+ instance; uniform weights when absent. Returns just the score (no gate),
49
+ fully differentiable w.r.t. ``axes``.
50
+ """
51
+
52
+ def forward(self, axes: torch.Tensor) -> torch.Tensor:
53
+ weights = getattr(self, "weights", None)
54
+ return lambda_aggregate(axes, weights=weights)
build/torch-universal/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .szl_lambda_gate import * # noqa: F401,F403
2
+ from .szl_lambda_gate import __all__
build/torch-universal/metadata.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"backend":{"type":"cpu"},"digest":{"algorithm":"sha256","files":{"__init__.py":"NuinjlWRNlWgg0y2D61HEaKtW/VOktRHP8w2Nj3opjQ=","szl_lambda_gate/__init__.py":"QpfkkacuKUGxXitqBYLq0nM4NnCsX7uNFOLHbeye0V0=","szl_lambda_gate/_lambda.py":"+VOjgBnJGm+oqcQR9VuqT18rnnbXFTu6VLuKXZRprzg=","szl_lambda_gate/_ops.py":"at8dxC56nm2pFOME2pcgQ45ZwjQQThHz5cyqRezuI7Y=","szl_lambda_gate/_v1.py":"msLY/gpH/xkeunbmKx6d2bK1T2S6DD2GMG4M3Vi8Row=","szl_lambda_gate/governed_norm/__init__.py":"UP5PsJoWXQrpp4Hw7zUVOIx1KhTN6V9zaHhU9Zp9+tw=","szl_lambda_gate/governed_norm/_norm.py":"z3Ks4oHshsUEQm914j7r22YaHjoS5N/MbIufpjSwOUI=","szl_lambda_gate/governed_norm/_receipt.py":"2xJEvRhK/9ypKb04rHKLJpb4KtVlqvgtFMo4RdTXSKk=","szl_lambda_gate/governed_norm/layers.py":"15yDNVyyMyudDp2YWEuGQ05IZTLifTBlLfEBWLMPw3s=","szl_lambda_gate/layers.py":"UdpHjhhe5NFtqplxvcvc/LsMDFt4N6ACuXzQXLlo6nU="}},"id":"_szl_lambda_gate_universal_7cb79cba7ecb5dbb9da59b2d6b516a98d2a114d6","license":"Apache-2.0","name":"szl-lambda-gate","python-depends":[],"source":"https://github.com/szl-holdings/szl-lambda-gate","universal":true,"version":1}
build/torch-universal/szl_lambda_gate/__init__.py ADDED
@@ -0,0 +1,216 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """szl_lambda_gate — the Lambda-Spine aggregator (Λ) as a universal kernel.
4
+
5
+ A pure-PyTorch (universal) kernel from SZL Holdings for the Hugging Face
6
+ Kernel Hub. It ports the canonical Λ aggregator into a differentiable,
7
+ torch.compile-friendly torch op:
8
+
9
+ Λ(x) = ∏ xᵢ^{wᵢ}, Σwᵢ = 1, wᵢ > 0, xᵢ ∈ [0,1] (weighted geometric mean)
10
+
11
+ plus an ADVISORY governance gate (Λ vs threshold), the four carried axioms as
12
+ real runtime self-checks, and pure nn.Module layers.
13
+
14
+ Load from the Hub:
15
+
16
+ import torch
17
+ from kernels import get_kernel
18
+
19
+ lg = get_kernel("SZLHOLDINGS/szl-lambda-gate")
20
+ axes = torch.tensor([0.9, 0.8, 0.95]) # axis scores in [0,1]
21
+ score = lg.lambda_aggregate(axes) # Λ(x) ∈ [0,1]
22
+ res = lg.lambda_gate(axes, threshold=0.5) # ADVISORY pass/fail
23
+ print(res.score, res.passed, res.advisory)
24
+
25
+ # szl.lambda/v1 strict gate (spec/szl.lambda.v1.json): no clamping, no
26
+ # renormalisation, tau required; bad input -> verdict BLOCK with a code.
27
+ w = torch.tensor([0.4, 0.3, 0.3], dtype=torch.float64)
28
+ v1 = lg.lambda_v1_gate(axes.double(), w, tau=0.8)
29
+ print(v1.verdict, v1.code) # GO / NO_GO / ABSTAIN / BLOCK
30
+
31
+ WHAT Λ IS / IS NOT (HONESTY — SZL Holdings doctrine v11):
32
+ Λ is the weighted-geometric-mean aggregator — a non-compensatory, ADVISORY
33
+ way to roll axis scores in [0,1] into one number (any zeroed axis zeroes the
34
+ aggregate). It is NOT "proven trust" and NOT a closed theorem: Λ-uniqueness
35
+ remains Conjecture 1 (OPEN — an unresolved CAUCHY_ND step plus a missing
36
+ symmetry axiom). Label it honestly everywhere; a gate "pass" is advisory.
37
+
38
+ PROVENANCE: backed by the Lean 4 formalization szl-holdings/lutar-lean
39
+ (749 declarations / 14 axioms / 163 tracked sorries),
40
+ DOI 10.5281/zenodo.20434308 (lutar-lean). Λ uniqueness = Conjecture 1 (open).
41
+ """
42
+ from typing import Optional
43
+
44
+ import torch
45
+
46
+ from . import layers # noqa: F401 (must be importable for Hub layer mapping)
47
+ # CONSOLIDATION (Wave D): the governed-norm universal kernel is folded in here
48
+ # as a subpackage so szl-lambda-gate is the ONE canonical kernels package. The
49
+ # source repo szl-holdings/szl-governed-norm is DEPRECATED and points here;
50
+ # nothing was deleted (additive, reversible copy). Λ stays Conjecture 1.
51
+ from . import governed_norm # noqa: F401 (folded-in governed normalization kernels)
52
+ from ._lambda import YUYAY_AXES, YUYAY_FLOORS, LambdaGateResult
53
+ from ._lambda import _resolve_threshold
54
+ from ._lambda import find_axiom_violation as _find_axiom_violation
55
+ from ._lambda import is_bounded_by_max as _is_bounded_by_max
56
+ from ._lambda import is_egyptian_exact as _is_egyptian_exact
57
+ from ._lambda import is_homogeneous as _is_homogeneous
58
+ from ._lambda import is_monotone as _is_monotone
59
+ from ._lambda import lambda_aggregate as _lambda_aggregate
60
+ from ._lambda import lambda_gate as _lambda_gate
61
+ from ._lambda import lambda_gate_batch as _lambda_gate_batch
62
+ from ._lambda import selfcheck as _selfcheck
63
+ from ._lambda import yuyay_weights as _yuyay_weights
64
+ # szl.lambda/v1 strict entry (spec/szl.lambda.v1.json): validated, coded, tau required.
65
+ from ._v1 import LambdaV1Error, LambdaV1GateResult, lambda_v1, lambda_v1_gate
66
+
67
+ __all__ = [
68
+ "lambda_aggregate",
69
+ "lambda_gate",
70
+ "lambda_gate_batch",
71
+ "LambdaGateResult",
72
+ "lambda_v1",
73
+ "lambda_v1_gate",
74
+ "LambdaV1Error",
75
+ "LambdaV1GateResult",
76
+ "is_monotone",
77
+ "is_egyptian_exact",
78
+ "is_bounded_by_max",
79
+ "is_homogeneous",
80
+ "find_axiom_violation",
81
+ "selfcheck",
82
+ "yuyay_weights",
83
+ "YUYAY_AXES",
84
+ "YUYAY_FLOORS",
85
+ "layers",
86
+ "DOCTRINE_FOOTER",
87
+ "PROVENANCE",
88
+ "__version__",
89
+ # ---- folded-in governed-norm kernels (Wave D consolidation) ----
90
+ "governed_norm",
91
+ "rms_norm",
92
+ "layer_norm",
93
+ "fused_add_rms_norm",
94
+ ]
95
+
96
+ # ---- folded-in governed-norm surface (Wave D consolidation) ---------------- #
97
+ # Convenience top-level re-exports of the governed normalization kernels that
98
+ # were absorbed from szl-governed-norm. The full surface (ReceiptChain,
99
+ # emit_receipt, receipt_* helpers, selfcheck, layers) lives under
100
+ # ``szl_lambda_gate.governed_norm``. These are a DIFFERENT kernel family from Λ
101
+ # (normalization, not the Λ aggregator); Λ itself remains Conjecture 1
102
+ # (advisory, uniqueness OPEN) and is never described as proven trust.
103
+ rms_norm = governed_norm.rms_norm
104
+ layer_norm = governed_norm.layer_norm
105
+ fused_add_rms_norm = governed_norm.fused_add_rms_norm
106
+
107
+ __version__ = "0.2.0"
108
+ DOCTRINE_FOOTER = (
109
+ "SZL Holdings · Λ = Conjecture 1 (ADVISORY, weighted geometric mean) · "
110
+ "uniqueness OPEN · NOT proven trust · honesty over checklist"
111
+ )
112
+ PROVENANCE = {
113
+ "lean_repo": "szl-holdings/lutar-lean",
114
+ "lean_declarations": 749,
115
+ "lean_axioms": 14,
116
+ "lean_tracked_sorries": 163,
117
+ "doi_lutar_lean": "10.5281/zenodo.20434308",
118
+ "lambda_status": "Conjecture 1 (open) — uniqueness unproven; advisory only",
119
+ }
120
+
121
+
122
+ def lambda_aggregate(
123
+ axes: torch.Tensor,
124
+ weights: Optional[torch.Tensor] = None,
125
+ ) -> torch.Tensor:
126
+ """Λ(x) = ∏ xᵢ^{wᵢ}, the weighted geometric mean over the last dim of axes.
127
+
128
+ See ``szl_lambda_gate._lambda.lambda_aggregate``. Axis scores in [0,1],
129
+ uniform weights when ``weights`` is None. Differentiable, batched, and
130
+ torch.compile-friendly. ADVISORY — NOT proven trust.
131
+ """
132
+ return _lambda_aggregate(axes, weights=weights)
133
+
134
+
135
+ def lambda_gate(
136
+ axes: torch.Tensor,
137
+ weights: Optional[torch.Tensor] = None,
138
+ threshold: Optional[float] = None,
139
+ ) -> LambdaGateResult:
140
+ """ADVISORY Λ governance gate: returns LambdaGateResult(score, passed,
141
+ threshold, advisory). ``passed`` = Λ(axes) >= threshold. ``threshold`` must
142
+ lie within Λ's range [0,1] (a value outside it is a misconfiguration — a
143
+ negative threshold would advisory-pass a fully-failing Λ=0 candidate — and
144
+ is rejected). Omitting it uses the legacy 0.5 with a DeprecationWarning
145
+ (policy_tau is 0.8); pass it, or use ``lambda_v1_gate(axes, weights, tau)``.
146
+ A pass is an advisory, non-compensatory signal — NOT proven trust
147
+ (Λ = Conjecture 1).
148
+ """
149
+ threshold = _resolve_threshold(threshold, stacklevel=2)
150
+ return _lambda_gate(axes, weights=weights, threshold=threshold)
151
+
152
+
153
+ def lambda_gate_batch(
154
+ candidates: torch.Tensor,
155
+ weights: Optional[torch.Tensor] = None,
156
+ threshold: Optional[float] = None,
157
+ ) -> LambdaGateResult:
158
+ """ADVISORY batch gate over many candidate action-vectors (shape (..., N, k)).
159
+
160
+ The realistic per-inference-step call: score all N candidates at once and
161
+ return the advisory pass mask. Returns LambdaGateResult(score, passed,
162
+ threshold, advisory) with score/passed of shape (..., N). ``threshold``
163
+ must lie within Λ's range [0,1] (same domain guard as ``lambda_gate``);
164
+ omitting it uses the legacy 0.5 with a DeprecationWarning.
165
+ NOT proven trust.
166
+ """
167
+ threshold = _resolve_threshold(threshold, stacklevel=2)
168
+ return _lambda_gate_batch(candidates, weights=weights, threshold=threshold)
169
+
170
+
171
+ def yuyay_weights(dtype: torch.dtype = torch.float64, device=None) -> torch.Tensor:
172
+ """Canonical 13-axis Yuyay Λ weight vector (uniform 1/13), ADVISORY only.
173
+
174
+ Use as ``weights`` over the 13 ``YUYAY_AXES``. The yuyay_v3 gate is a
175
+ conjunctive AND with per-axis floors (``YUYAY_FLOORS``); this Λ roll-up is
176
+ the weighted geometric mean and is ADVISORY — NOT proven trust.
177
+ """
178
+ return _yuyay_weights(dtype=dtype, device=device)
179
+
180
+
181
+ def find_axiom_violation(k=5, trials=200, weights=None, seed=0, tol=1e-6):
182
+ """Random-search for any A1–A4 violation; returns (axiom, axes, weights) or
183
+ None. An honest falsification attempt — finding nothing is evidence, not a
184
+ proof (Λ-uniqueness is Conjecture 1, open).
185
+ """
186
+ return _find_axiom_violation(k=k, trials=trials, weights=weights, seed=seed, tol=tol)
187
+
188
+
189
+ def selfcheck(k=5, trials=64, seed=0) -> dict:
190
+ """Expose the A1–A4 empirical self-checks + version as a single verdict dict.
191
+
192
+ Callable as get_kernel(...).selfcheck(). EMPIRICAL checks on sampled inputs,
193
+ NOT a proof of Λ-uniqueness (Conjecture 1, open). Advisory only.
194
+ """
195
+ return _selfcheck(k=k, trials=trials, seed=seed)
196
+
197
+
198
+ # ---- axiom runtime self-checks (real, verifiable; NOT a uniqueness proof) -- #
199
+ def is_monotone(axes, weights=None, delta=0.05, tol=1e-7) -> bool:
200
+ """A1 IsMonotone self-check: Λ is non-decreasing in each axis (on this data)."""
201
+ return _is_monotone(axes, weights=weights, delta=delta, tol=tol)
202
+
203
+
204
+ def is_egyptian_exact(c, k=3, weights=None, tol=1e-5) -> bool:
205
+ """A3 IsEgyptianExact self-check: Λ(c, …, c) = c."""
206
+ return _is_egyptian_exact(c, k=k, weights=weights, tol=tol)
207
+
208
+
209
+ def is_bounded_by_max(axes, weights=None, tol=1e-6) -> bool:
210
+ """A4 IsBounded self-check: Λ(x) ≤ maxᵢ xᵢ."""
211
+ return _is_bounded_by_max(axes, weights=weights, tol=tol)
212
+
213
+
214
+ def is_homogeneous(axes, t, weights=None, tol=1e-5) -> bool:
215
+ """A2 IsHomogeneous(degree 1) self-check: Λ(t·x) = t·Λ(x)."""
216
+ return _is_homogeneous(axes, t, weights=weights, tol=tol)
build/torch-universal/szl_lambda_gate/_lambda.py ADDED
@@ -0,0 +1,556 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Pure-PyTorch Lambda-Spine aggregator (Λ) for the szl-lambda-gate kernel.
4
+
5
+ Λ(x) = ∏ xᵢ^{wᵢ}, Σwᵢ = 1, wᵢ > 0, xᵢ ∈ [0,1] (weighted geometric mean)
6
+
7
+ This is a TORCH port of the canonical pure-Python reference
8
+ (packages/puriq-os/puriq_os/lambda_aggregator.py — saved alongside this kernel
9
+ as lambda_aggregator_source.py). It is a correctness reference, computed via
10
+ logs in float32 for stability, differentiable (autograd works), and
11
+ torch.compile-friendly. Depends ONLY on torch + the Python standard library
12
+ (a Kernel Hub requirement for universal kernels).
13
+
14
+ WHAT Λ IS / IS NOT (HONESTY — SZL Holdings doctrine v11):
15
+ Λ is the *weighted-geometric-mean aggregator*: a non-compensatory way to
16
+ combine axis scores in [0,1] into one number. It is ADVISORY governance
17
+ signal — a conservative roll-up where any single zeroed axis drives the
18
+ aggregate to 0. It is NOT "proven trust" and NOT a closed theorem. Its
19
+ *uniqueness* (that the weighted geometric mean is the only aggregator
20
+ satisfying the carried axioms) remains Conjecture 1 — OPEN (an unresolved
21
+ CAUCHY_ND step plus a missing symmetry axiom in the Lean development). Do
22
+ not describe Λ as proven trust anywhere.
23
+
24
+ PRIOR ART (honest attribution): the weighted geometric mean as a *less-
25
+ compensatory* composite-indicator aggregator is established practice — the
26
+ UN HDI (arithmetic→geometric switch, 2010), the OECD Handbook on
27
+ Constructing Composite Indicators (2008), and the UNECE well-being
28
+ guidelines all use it "to limit the compensation effect". The veto / cut-off
29
+ idea (a single failing criterion blocks a pass regardless of the others) is
30
+ the ELECTRE veto threshold / "satisficing" minimum-threshold screen. The
31
+ 13-axis conjunctive form exposed by :func:`yuyay_weights` is SZL's own
32
+ yuyay_v3 "Heart" gate. None of this makes Λ "proven trust"; the gate is
33
+ ADVISORY (a11oy: "the advisory Λ trust score is a research conjecture, not a
34
+ pass/fail oracle").
35
+
36
+ PROVENANCE: backed by the Lean 4 formalization szl-holdings/lutar-lean
37
+ (749 declarations / 14 axioms / 163 tracked sorries),
38
+ DOI 10.5281/zenodo.20434308 (lutar-lean).
39
+ Λ uniqueness = Conjecture 1 (open).
40
+
41
+ Axioms carried (Lutar/Axioms.lean), available below as runtime self-checks:
42
+ A1 IsMonotone — Λ is non-decreasing in each axis
43
+ A2 IsHomogeneous — Λ(t·x) = t·Λ(x) (degree 1)
44
+ A3 IsEgyptianExact — Λ(c,…,c) = c (the uniform-diagonal fixpoint)
45
+ A4 IsBounded(by max) — Λ(x) ≤ maxᵢ xᵢ
46
+ """
47
+ import warnings
48
+ from typing import Optional
49
+
50
+ import torch
51
+
52
+ # ---- the deprecated implicit threshold ------------------------------------- #
53
+ # lambda_gate / lambda_gate_batch / layers.LambdaGate used to default to 0.5.
54
+ # That default stays, so there is no behaviour change, but omitting the
55
+ # threshold now raises a DeprecationWarning. The admit policy value is
56
+ # policy_tau in frontier/model_admit_contract.v1.json, and the strict
57
+ # szl.lambda/v1 gate (_v1.lambda_v1_gate) takes tau as a required argument.
58
+ _LEGACY_DEFAULT_THRESHOLD = 0.5
59
+ _DEFAULT_THRESHOLD_WARNING = (
60
+ "default threshold 0.5 differs from policy_tau 0.8; pass tau. Omitting the "
61
+ "threshold of lambda_gate / lambda_gate_batch / LambdaGate is deprecated: "
62
+ "pass threshold= explicitly (policy_tau is in "
63
+ "frontier/model_admit_contract.v1.json), or use the strict "
64
+ "lambda_v1_gate(axes, weights, tau). The legacy default 0.5 still applies."
65
+ )
66
+
67
+
68
+ def _resolve_threshold(threshold: Optional[float], stacklevel: int) -> float:
69
+ """``None`` (the threshold was omitted) -> the legacy 0.5, with a DeprecationWarning.
70
+
71
+ ``stacklevel`` is what the calling entry point would pass to
72
+ ``warnings.warn`` itself (2 = its caller), so the warning names the line
73
+ that omitted the threshold. Dynamo cannot trace ``warnings.warn`` (a
74
+ fullgraph compile would fail), so the warning is skipped while
75
+ ``torch.compile`` traces; the default is applied either way.
76
+ """
77
+ if threshold is not None:
78
+ return threshold
79
+ if not bool(getattr(torch.compiler, "is_compiling", lambda: False)()):
80
+ warnings.warn(_DEFAULT_THRESHOLD_WARNING, DeprecationWarning, stacklevel=stacklevel + 1)
81
+ return _LEGACY_DEFAULT_THRESHOLD
82
+
83
+
84
+ # Compute reductions/log-sum in float32 for stability when inputs are low
85
+ # precision; keep float64 inputs in float64 (downcasting would break gradcheck
86
+ # and silently lose precision).
87
+ _SUPPORTED_DTYPES = (torch.float16, torch.bfloat16, torch.float32, torch.float64)
88
+
89
+
90
+ def _compute_dtype(in_dtype: torch.dtype) -> torch.dtype:
91
+ return torch.float32 if in_dtype in (torch.float16, torch.bfloat16) else in_dtype
92
+
93
+
94
+ def _check_axes(axes: torch.Tensor) -> None:
95
+ """Cheap, allocation-free metadata guards on the axis-score tensor.
96
+
97
+ Inspects only type / dtype / rank / last-dim, so it constant-folds under
98
+ torch.compile and adds no tensor work on the happy path.
99
+ """
100
+ if not isinstance(axes, torch.Tensor):
101
+ raise TypeError(f"axes must be a torch.Tensor, got {type(axes).__name__}")
102
+ if axes.dtype not in _SUPPORTED_DTYPES:
103
+ raise TypeError(
104
+ f"axes has unsupported dtype {axes.dtype}; "
105
+ f"expected one of {tuple(str(d) for d in _SUPPORTED_DTYPES)}"
106
+ )
107
+ if axes.dim() < 1:
108
+ raise ValueError(
109
+ "axes must have at least 1 dimension (the k axis scores live on "
110
+ f"the last dim); got a {axes.dim()}-d tensor"
111
+ )
112
+ if axes.shape[-1] < 1:
113
+ raise ValueError("axes last dimension (k = number of axes) must be >= 1")
114
+
115
+
116
+ def _resolve_weights(
117
+ axes: torch.Tensor,
118
+ weights: Optional[torch.Tensor],
119
+ cdt: torch.dtype,
120
+ ) -> torch.Tensor:
121
+ """Return a normalized (Σw = 1) weight vector of shape (k,) in compute dtype.
122
+
123
+ ``weights=None`` -> uniform 1/k (the Egyptian-exact diagonal). Otherwise the
124
+ weights must be 1-D of length k, strictly positive, with a positive sum;
125
+ they are normalized so Σwᵢ = 1.
126
+ """
127
+ k = axes.shape[-1]
128
+ if weights is None:
129
+ return torch.full((k,), 1.0 / k, dtype=cdt, device=axes.device)
130
+ if not isinstance(weights, torch.Tensor):
131
+ raise TypeError(f"weights must be a torch.Tensor or None, got {type(weights).__name__}")
132
+ if weights.device != axes.device:
133
+ raise ValueError(
134
+ f"weights is on device {weights.device} but axes is on {axes.device}; "
135
+ "move them to the same device"
136
+ )
137
+ if weights.dim() != 1 or weights.shape[0] != k:
138
+ raise ValueError(
139
+ f"weights must be 1-D with shape ({k},) to match the last dim of axes; "
140
+ f"got shape {tuple(weights.shape)}"
141
+ )
142
+ wf = weights.to(cdt)
143
+ compiling = bool(getattr(torch.compiler, "is_compiling", lambda: False)())
144
+ if not compiling:
145
+ if not bool(torch.all(torch.isfinite(wf))):
146
+ raise ValueError("weights must all be finite (no NaN/Inf)")
147
+ if bool(torch.any(wf <= 0.0)):
148
+ raise ValueError("weights must be strictly positive (wᵢ > 0)")
149
+ sw = wf.sum()
150
+ if not bool(sw > 0.0):
151
+ raise ValueError("weights must sum to a positive value")
152
+ return wf / sw
153
+ # Compiled path stays in tensor-land. Non-positive weights are a misuse;
154
+ # clamp them away from zero so the graph does not break, then normalize.
155
+ # This path is outside szl.lambda/v1; _v1.lambda_v1 validates before it
156
+ # gets here and is not meant to run under torch.compile.
157
+ wf = torch.where(torch.isfinite(wf), wf, torch.ones_like(wf))
158
+ wf = torch.clamp(wf, min=torch.finfo(wf.dtype).tiny)
159
+ return wf / wf.sum()
160
+
161
+
162
+ def lambda_aggregate(
163
+ axes: torch.Tensor,
164
+ weights: Optional[torch.Tensor] = None,
165
+ ) -> torch.Tensor:
166
+ """Weighted geometric mean Λ(x) = ∏ xᵢ^{wᵢ} over the last dim of ``axes``.
167
+
168
+ Λ is the (ADVISORY) Lambda-Spine aggregator. Axis scores are expected in
169
+ [0,1] and are clamped into [0,1]; uniform weights (1/k) are used when
170
+ ``weights`` is None — the Egyptian-exact diagonal. Computed via logs in
171
+ float32 (or float64 for float64 inputs) for numerical stability:
172
+
173
+ Λ(x) = exp( Σᵢ wᵢ · log(clamp(xᵢ, 0, 1)) )
174
+
175
+ Non-compensatory zero-routing (A4-consistent): any axis that is zero, OR
176
+ that is NON-FINITE (NaN / ±Inf), is treated as a FAILING axis and drives
177
+ the whole aggregate to exactly 0. This is the conservative governance
178
+ choice — a garbage/invalid axis must never silently pass as a "perfect"
179
+ (clamped-to-1) axis, and the output (and its gradient) stay finite and in
180
+ [0,1] for every input. Zeros/non-finite axes are routed explicitly so
181
+ log(0) = -inf and log(NaN) = NaN never produce a NaN value or gradient.
182
+
183
+ Args:
184
+ axes: tensor of shape (..., k) of axis scores in [0,1]. Batched:
185
+ the reduction is over the last dim, leading dims are batch.
186
+ weights: optional 1-D tensor of shape (k,); None -> uniform. Normalized
187
+ internally so Σwᵢ = 1.
188
+
189
+ Returns:
190
+ tensor of shape (...) — Λ(x) ∈ [0,1] per batch row. Differentiable
191
+ w.r.t. ``axes`` (and ``weights``).
192
+
193
+ NOT the szl.lambda/v1 contract: this function clamps, zero-routes NaN/±Inf
194
+ and renormalises (pinned in tests/test_lambda_v1_torch_divergence.py). For
195
+ validated, coded errors use :func:`szl_lambda_gate._v1.lambda_v1`.
196
+
197
+ HONESTY: this is a non-compensatory governance roll-up, NOT proven trust.
198
+ Λ-uniqueness is Conjecture 1 (open).
199
+ """
200
+ _check_axes(axes)
201
+ in_dtype = axes.dtype
202
+ cdt = _compute_dtype(in_dtype)
203
+ xf = axes.to(cdt)
204
+ w = _resolve_weights(axes, weights, cdt) # (k,), Σw=1
205
+
206
+ # A "bad" axis is one that fails non-compensatorily: a non-positive score
207
+ # OR a non-finite value (NaN / ±Inf). clamp(+inf)=1 would otherwise count a
208
+ # garbage axis as perfect, and clamp(NaN)=NaN would poison the product — we
209
+ # treat BOTH as failing (zeroing) axes. Detect non-finite on the RAW input.
210
+ finite_mask = torch.isfinite(xf)
211
+ xc = xf.clamp(0.0, 1.0)
212
+ bad_mask = (~finite_mask) | (xc <= 0.0)
213
+ any_bad = torch.any(bad_mask, dim=-1) # (...)
214
+
215
+ # Replace bad axes with 1.0 before the log purely to keep log finite and the
216
+ # gradient well-defined; the bad-axis contribution is reinstated via any_bad.
217
+ safe = torch.where(bad_mask, torch.ones_like(xc), xc)
218
+ logx = torch.log(safe) # (..., k)
219
+ acc = (logx * w).sum(dim=-1) # (...) weighted log-sum
220
+ val = torch.exp(acc) # (...) Λ before zero-routing
221
+
222
+ out = torch.where(any_bad, torch.zeros_like(val), val)
223
+ out = out.clamp(0.0, 1.0)
224
+ return out.to(in_dtype)
225
+
226
+
227
+ def lambda_gate(
228
+ axes: torch.Tensor,
229
+ weights: Optional[torch.Tensor] = None,
230
+ threshold: Optional[float] = None,
231
+ ):
232
+ """ADVISORY governance gate over Λ(x): score plus a pass/fail vs threshold.
233
+
234
+ Computes Λ(x) (see :func:`lambda_aggregate`) and compares it to
235
+ ``threshold``: pass := Λ(x) >= threshold.
236
+
237
+ DEPRECATED DEFAULT: omitting ``threshold`` (or passing ``None``) still uses
238
+ the legacy 0.5 but raises a ``DeprecationWarning``, because 0.5 differs
239
+ from the admit contract's policy_tau (0.8). Pass the threshold explicitly,
240
+ or use the strict szl.lambda/v1 gate
241
+ :func:`szl_lambda_gate._v1.lambda_v1_gate`, where tau is required.
242
+
243
+ ``threshold`` must be a finite float within Λ's range ``[0, 1]`` (Λ is the
244
+ weighted geometric mean over [0,1]). This bound is enforced: a threshold
245
+ below 0 or above 1 is meaningless for the advisory gate and is rejected —
246
+ see the non-compensatory rationale below. The domain edges are valid:
247
+ ``0.0`` admits every candidate (a permissive "no-gate" boundary) and
248
+ ``1.0`` admits only a Λ == 1 candidate.
249
+
250
+ Returns a :class:`LambdaGateResult` namedtuple with fields:
251
+ score — Λ(x) tensor of shape (...), in [0,1]
252
+ passed — boolean tensor of shape (...), Λ(x) >= threshold
253
+ threshold — the float threshold used
254
+ advisory — always True; a STANDING reminder that this is a
255
+ non-compensatory governance signal, NOT proven trust.
256
+
257
+ Non-compensatory threshold hardening: because a failing/garbage candidate
258
+ (a zero, NaN, or ±Inf axis) is routed to Λ = 0, a NEGATIVE threshold would
259
+ advisory-"pass" exactly those fully-failing candidates (0 >= t for t < 0) —
260
+ the opposite of a conservative admission gate. A threshold above 1 can
261
+ never pass. Both are misconfigurations, so the [0,1] domain is enforced up
262
+ front rather than silently producing a wrong pass mask.
263
+
264
+ HONESTY: a "pass" is an ADVISORY signal only. Λ is the weighted-geometric-
265
+ mean aggregator; its uniqueness is Conjecture 1 (open). Do not treat a
266
+ pass as proven trust or a closed theorem.
267
+ """
268
+ threshold = _resolve_threshold(threshold, stacklevel=2)
269
+ t = float(threshold)
270
+ if t != t or t == float("inf") or t == float("-inf"):
271
+ raise ValueError(f"threshold must be a finite float, got {threshold!r}")
272
+ if t < 0.0 or t > 1.0:
273
+ raise ValueError(
274
+ "threshold must be within Λ's range [0, 1] (Λ is the weighted "
275
+ f"geometric mean over [0,1]); got {t!r}. A threshold below 0 would "
276
+ "advisory-pass a fully-failing (Λ=0) candidate and one above 1 can "
277
+ "never pass — both signal a misconfigured gate."
278
+ )
279
+ score = lambda_aggregate(axes, weights)
280
+ passed = score >= t
281
+ return LambdaGateResult(score=score, passed=passed, threshold=t, advisory=True)
282
+
283
+
284
+ def lambda_gate_batch(
285
+ candidates: torch.Tensor,
286
+ weights: Optional[torch.Tensor] = None,
287
+ threshold: Optional[float] = None,
288
+ ):
289
+ """ADVISORY batch gate: score MANY candidate action-vectors in one call.
290
+
291
+ This is the realistic way a model/agent uses the gate — one call per
292
+ inference step that scores every proposed action-vector at once and returns
293
+ the advisory pass mask (which candidates clear the threshold).
294
+
295
+ ``candidates`` is a tensor of shape (..., N, k): the last dim ``k`` holds
296
+ the per-axis scores of a single candidate, and the second-to-last dim ``N``
297
+ enumerates the candidates (any leading dims are extra batch). Equivalent to
298
+ calling :func:`lambda_gate` on the whole tensor — the reduction is over the
299
+ last dim — but named to make the agent-loop intent explicit. ``threshold``
300
+ inherits the same [0,1] domain guard as :func:`lambda_gate` (a threshold
301
+ outside Λ's range is a misconfiguration and is rejected). Omitting it uses
302
+ the legacy 0.5 with a ``DeprecationWarning``, as in :func:`lambda_gate`.
303
+
304
+ Returns a :class:`LambdaGateResult` with:
305
+ score — Λ tensor of shape (..., N), one score per candidate
306
+ passed — boolean mask of shape (..., N): score >= threshold
307
+ threshold — the float threshold used
308
+ advisory — always True (NOT proven trust)
309
+
310
+ HONESTY: the pass mask is an ADVISORY, non-compensatory signal. A "pass"
311
+ is not proven trust; Λ-uniqueness is Conjecture 1 (open).
312
+ """
313
+ threshold = _resolve_threshold(threshold, stacklevel=2)
314
+ _check_axes(candidates)
315
+ if candidates.dim() < 2:
316
+ raise ValueError(
317
+ "candidates must be at least 2-D, shape (..., N, k): the last dim is "
318
+ f"the k axis scores and the one before it enumerates the N candidates; "
319
+ f"got a {candidates.dim()}-d tensor"
320
+ )
321
+ # Reuse the single-call gate — its reduction over the last dim already gives
322
+ # one score per candidate, so the (..., N) layout falls out for free.
323
+ return lambda_gate(candidates, weights=weights, threshold=threshold)
324
+
325
+
326
+ # ---- A1..A4 axiom RUNTIME self-checks (real, verifiable) ------------------- #
327
+ # These are honest empirical checks callers can run on concrete inputs. They
328
+ # verify the carried axioms hold for THIS implementation on the given data —
329
+ # they are NOT a proof of Λ-uniqueness (that is Conjecture 1, open).
330
+
331
+ def is_egyptian_exact(
332
+ c: float,
333
+ k: int = 3,
334
+ weights: Optional[torch.Tensor] = None,
335
+ tol: float = 1e-5,
336
+ ) -> bool:
337
+ """A3 IsEgyptianExact: Λ(c, …, c) = c for a constant axis vector of length k.
338
+
339
+ Builds the uniform vector (c repeated k times) and checks Λ equals c within
340
+ ``tol``. ``c`` is clamped into [0,1] to match the aggregator's domain.
341
+ """
342
+ if k < 1:
343
+ raise ValueError("k must be >= 1")
344
+ cc = min(max(float(c), 0.0), 1.0)
345
+ axes = torch.full((k,), cc, dtype=torch.float64)
346
+ val = lambda_aggregate(axes, weights)
347
+ return bool(torch.abs(val - cc) <= tol)
348
+
349
+
350
+ def is_bounded_by_max(
351
+ axes: torch.Tensor,
352
+ weights: Optional[torch.Tensor] = None,
353
+ tol: float = 1e-6,
354
+ ) -> bool:
355
+ """A4 IsBounded: Λ(x) ≤ maxᵢ xᵢ (over the last dim), within ``tol``.
356
+
357
+ Returns True iff the bound holds for every batch row. Non-finite axis
358
+ values are clamped/zero-routed the same way the aggregator treats them, so
359
+ the bound is checked on the conservative (finite) domain.
360
+ """
361
+ _check_axes(axes)
362
+ val = lambda_aggregate(axes, weights) # (...)
363
+ xf = axes.to(_compute_dtype(axes.dtype))
364
+ # Mirror the aggregator: non-finite axes are failing (treated as 0) for the
365
+ # purposes of the max bound, so the check matches the routed semantics.
366
+ xf = torch.where(torch.isfinite(xf), xf, torch.zeros_like(xf))
367
+ mx = xf.clamp(0.0, 1.0).amax(dim=-1) # (...)
368
+ return bool(torch.all(val.to(mx.dtype) <= mx + tol))
369
+
370
+
371
+ def is_homogeneous(
372
+ axes: torch.Tensor,
373
+ t: float,
374
+ weights: Optional[torch.Tensor] = None,
375
+ tol: float = 1e-5,
376
+ ) -> bool:
377
+ """A2 IsHomogeneous (degree 1): Λ(t·x) = t·Λ(x) for scalar t in [0,1].
378
+
379
+ Verified on the clamped domain: both ``axes`` and ``t*axes`` must remain in
380
+ [0,1] for the identity to be meaningful, so ``axes`` is clamped to [0,1] and
381
+ ``t`` to [0,1] before the comparison.
382
+ """
383
+ _check_axes(axes)
384
+ tt = min(max(float(t), 0.0), 1.0)
385
+ x = axes.to(torch.float64).clamp(0.0, 1.0)
386
+ lhs = lambda_aggregate(x * tt, weights)
387
+ rhs = tt * lambda_aggregate(x, weights)
388
+ return bool(torch.all(torch.abs(lhs - rhs) <= tol))
389
+
390
+
391
+ def is_monotone(
392
+ axes: torch.Tensor,
393
+ weights: Optional[torch.Tensor] = None,
394
+ delta: float = 0.05,
395
+ tol: float = 1e-7,
396
+ ) -> bool:
397
+ """A1 IsMonotone: Λ is non-decreasing in each axis.
398
+
399
+ For each axis j, nudges that axis UP by ``delta`` (clamped to stay ≤ 1) on
400
+ every batch row and checks Λ does not decrease (within ``tol``). Rows that
401
+ cannot move (already at 1) are skipped for that axis. A real check on the
402
+ given data — not a symbolic proof.
403
+ """
404
+ _check_axes(axes)
405
+ x = axes.to(torch.float64).clamp(0.0, 1.0)
406
+ base = lambda_aggregate(x, weights)
407
+ k = x.shape[-1]
408
+ ok = True
409
+ for j in range(k):
410
+ bumped = x.clone()
411
+ bumped[..., j] = (bumped[..., j] + float(delta)).clamp(0.0, 1.0)
412
+ bumped_val = lambda_aggregate(bumped, weights)
413
+ # Λ must not go DOWN when an axis goes UP.
414
+ ok = ok and bool(torch.all(bumped_val - base >= -tol))
415
+ return ok
416
+
417
+
418
+ # ---- Adversarial axiom search (honest: a falsification attempt) ------------ #
419
+ def find_axiom_violation(
420
+ k: int = 5,
421
+ trials: int = 200,
422
+ weights: Optional[torch.Tensor] = None,
423
+ seed: Optional[int] = 0,
424
+ tol: float = 1e-6,
425
+ ):
426
+ """Random-search for ANY A1–A4 violation on random axis/weight draws.
427
+
428
+ Returns the first ``(axiom, axes, weights)`` triple that violates a carried
429
+ axiom within ``tol``, or ``None`` if none is found in ``trials`` draws. This
430
+ is an honest FALSIFICATION attempt on this implementation — finding nothing
431
+ is empirical evidence, NOT a proof (Λ-uniqueness is Conjecture 1, open).
432
+ """
433
+ gen = torch.Generator()
434
+ if seed is not None:
435
+ gen.manual_seed(int(seed))
436
+ for _ in range(int(trials)):
437
+ x = torch.rand(k, generator=gen, dtype=torch.float64)
438
+ w = weights
439
+ if w is None:
440
+ w = torch.rand(k, generator=gen, dtype=torch.float64) + 1e-3
441
+ # A3 on a constant draw
442
+ c = float(torch.rand(1, generator=gen).item())
443
+ if not is_egyptian_exact(c, k=k, weights=w, tol=max(tol, 1e-5)):
444
+ return ("A3_IsEgyptianExact", torch.full((k,), c, dtype=torch.float64), w)
445
+ # A4 bounded-by-max
446
+ if not is_bounded_by_max(x, w, tol=max(tol, 1e-6)):
447
+ return ("A4_IsBounded", x, w)
448
+ # A2 homogeneous at a random t
449
+ t = float(torch.rand(1, generator=gen).item())
450
+ if not is_homogeneous(x, t, weights=w, tol=max(tol, 1e-5)):
451
+ return ("A2_IsHomogeneous", x, w)
452
+ # A1 monotone (leave headroom so an up-bump stays in range)
453
+ if not is_monotone(x * 0.9, w, tol=max(tol, 1e-7)):
454
+ return ("A1_IsMonotone", x * 0.9, w)
455
+ return None
456
+
457
+
458
+ # ---- Canonical 13-axis Yuyay preset (ADVISORY ONLY) ------------------------ #
459
+ # SZL's own yuyay_v3 "Heart" gate is a 13-axis CONJUNCTIVE-AND screen (each axis
460
+ # independently clears its floor — no compensation). We expose its published
461
+ # axis NAMES and per-axis FLOORS as advisory metadata, and a uniform Λ weight
462
+ # vector over the 13 axes. This is ADVISORY: Λ here is still the weighted
463
+ # geometric mean, and a "pass" is a research-conjecture signal, NOT proven
464
+ # trust. Source: yuyay_v3 spec (Lutar, 2026).
465
+ YUYAY_AXES = (
466
+ "moralGrounding",
467
+ "measurabilityHonesty",
468
+ "empiricalGrounding",
469
+ "logicalConsistency",
470
+ "sourceTransparency",
471
+ "reproducibility",
472
+ "licenseHygiene",
473
+ "scopeDiscipline",
474
+ "claimCalibration",
475
+ "evalAwareness",
476
+ "deceptionKeywords",
477
+ "conflictingDirectives",
478
+ "reversalDirective",
479
+ )
480
+ # Published per-axis advisory floors for the CONJUNCTIVE screen: two "sacred"
481
+ # axes at 0.95, seven "structural" at 0.90, four "introspection" at 0.90.
482
+ YUYAY_FLOORS = (
483
+ 0.95, 0.95, # sacred
484
+ 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, 0.90, # structural (7)
485
+ 0.90, 0.90, 0.90, 0.90, # introspection (4)
486
+ )
487
+
488
+
489
+ def yuyay_weights(
490
+ dtype: torch.dtype = torch.float64,
491
+ device: Optional[torch.device] = None,
492
+ ) -> torch.Tensor:
493
+ """Canonical 13-axis Yuyay Λ weight vector (uniform 1/13), ADVISORY only.
494
+
495
+ Returns a length-13 weight tensor for use as the ``weights`` argument to
496
+ :func:`lambda_aggregate` / :func:`lambda_gate` over the 13 :data:`YUYAY_AXES`.
497
+ Uniform by default (the Egyptian-exact diagonal). The published yuyay_v3
498
+ gate is a conjunctive AND with per-axis floors (:data:`YUYAY_FLOORS`); the
499
+ Λ roll-up here is the weighted geometric mean and is ADVISORY — NOT proven
500
+ trust (Λ-uniqueness is Conjecture 1, open).
501
+ """
502
+ k = len(YUYAY_AXES)
503
+ return torch.full((k,), 1.0 / k, dtype=dtype, device=device)
504
+
505
+
506
+ # ---- Kernel self-check surface --------------------------------------------- #
507
+ def selfcheck(
508
+ k: int = 5,
509
+ trials: int = 64,
510
+ seed: Optional[int] = 0,
511
+ ) -> dict:
512
+ """Run the A1–A4 empirical self-checks and report a verdict + version.
513
+
514
+ Returns a dict:
515
+ version — kernel version string
516
+ axioms — {A1..A4: bool} empirical pass on sampled inputs
517
+ all_axioms_hold — bool, every sampled axiom check passed
518
+ adversarial — {trials, violation} from a random falsification search
519
+ (violation is None when no violation was found)
520
+ advisory — always True
521
+ lambda_status — Conjecture 1 (open) honesty string
522
+
523
+ HONESTY: these are EMPIRICAL checks on sampled inputs, NOT a proof of
524
+ Λ-uniqueness (Conjecture 1, open). A clean run is evidence, not proof.
525
+ """
526
+ x = torch.rand(k, dtype=torch.float64) * 0.9 # headroom for the A1 up-bump
527
+ w = torch.rand(k, dtype=torch.float64) + 1e-3
528
+ axioms = {
529
+ "A1_IsMonotone": is_monotone(x, w),
530
+ "A2_IsHomogeneous": is_homogeneous(x, float(torch.rand(1).item()), weights=w),
531
+ "A3_IsEgyptianExact": is_egyptian_exact(float(torch.rand(1).item()), k=k, weights=w),
532
+ "A4_IsBounded": is_bounded_by_max(x, w),
533
+ }
534
+ violation = find_axiom_violation(k=k, trials=trials, seed=seed)
535
+ return {
536
+ "version": __version__,
537
+ "axioms": axioms,
538
+ "all_axioms_hold": all(axioms.values()) and violation is None,
539
+ "adversarial": {"trials": int(trials), "violation": violation},
540
+ "advisory": True,
541
+ "lambda_status": "Conjecture 1 (open) — uniqueness unproven; advisory only",
542
+ }
543
+
544
+
545
+ # Kept in sync with the package __version__ (single source of truth lives in
546
+ # __init__; duplicated here so _lambda is importable/selfcheck-able standalone).
547
+ __version__ = "0.2.0"
548
+
549
+
550
+ # Namedtuple result type for the gate. Defined after functions so docstrings
551
+ # above can reference it; imported by __init__ and layers.
552
+ from collections import namedtuple # noqa: E402
553
+
554
+ LambdaGateResult = namedtuple(
555
+ "LambdaGateResult", ["score", "passed", "threshold", "advisory"]
556
+ )
build/torch-universal/szl_lambda_gate/_ops.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # Auto-style ops namespace shim for the universal kernel. Unique suffix lets
3
+ # multiple versions load in the same process (Kernel Hub requirement).
4
+ import torch
5
+
6
+ ops = torch.ops._szl_lambda_gate_20260623081355
7
+
8
+
9
+ def add_op_namespace_prefix(op_name: str) -> str:
10
+ return f"_szl_lambda_gate_20260623081355::{op_name}"
build/torch-universal/szl_lambda_gate/_v1.py ADDED
@@ -0,0 +1,221 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """szl.lambda/v1 strict kernel entry: Λ and its gate on tensors, with no clamping or defaults.
4
+
5
+ This is the torch port of ``reference/szl_lambda_v1.py`` and follows
6
+ ``spec/szl.lambda.v1.json``. An input outside the contract makes ``lambda_v1``
7
+ raise ``LambdaV1Error(code)`` and makes ``lambda_v1_gate`` return verdict BLOCK
8
+ with that code. Nothing is clamped, renormalised, defaulted or rounded before
9
+ the compare::
10
+
11
+ lambda_v1(axes, weights) -> 0-d float64 tensor, Λ in [0, 1]
12
+ lambda_v1_gate(axes, weights, tau) -> LambdaV1GateResult(verdict, code, score, tau, advisory)
13
+
14
+ The legacy ``lambda_aggregate`` / ``lambda_gate`` are unchanged. They clamp
15
+ x > 1 to 1, route NaN and ±Inf to 0 and renormalise weights, and
16
+ ``lambda_gate`` falls back to a threshold of 0.5, which is now deprecated.
17
+ Use this module when a verdict must follow szl.lambda/v1.
18
+
19
+ Inputs
20
+ ``axes`` and ``weights`` are 1-D tensors of a real dtype (floating or
21
+ integer). bool and complex are not numbers. A Python list, None, or a 0-d
22
+ or 2-D tensor is LAMBDA_TYPE_INVALID; build the tensor with
23
+ ``torch.tensor(values, dtype=torch.float64)``. ``weights`` is moved to the
24
+ device of ``axes``. Inputs are read and never modified.
25
+
26
+ ``tau`` is a Python int or float (not bool), finite, with 0 < tau <= 1. It
27
+ is required and has no default. The policy value is ``policy_tau`` in
28
+ frontier/model_admit_contract.v1.json.
29
+
30
+ Checks run in phases, in the reference's order, so the reported code does not
31
+ depend on axis order::
32
+
33
+ LAMBDA_TYPE_INVALID (container) > LAMBDA_EMPTY > LAMBDA_LENGTH_MISMATCH
34
+ > LAMBDA_TYPE_INVALID (dtype) > LAMBDA_NONFINITE_AXIS
35
+ > LAMBDA_AXIS_OUT_OF_RANGE > LAMBDA_NONFINITE_WEIGHT
36
+ > LAMBDA_WEIGHT_NONPOSITIVE > LAMBDA_WEIGHT_SUM
37
+
38
+ The gate checks tau first (LAMBDA_TAU_INVALID). The element checks and the
39
+ weight sum (``math.fsum``) run on the float64 values exactly as the reference
40
+ runs them, so every error code agrees with the reference.
41
+
42
+ How the numbers are computed
43
+ * Λ, which is ``lambda_v1`` and the gate's ``score``, comes from
44
+ ``_lambda.lambda_aggregate`` in float64, so it stays a differentiable
45
+ tensor. On validated input that function's clamp and NaN routing change
46
+ nothing, and a zero axis gives exactly 0. Its renormalisation divides by
47
+ a sum within 1e-12 of 1, which moves Λ by at most Λ·|log Λ|·1e-12
48
+ (<= 3.7e-13) plus float64 rounding. The vectors' value_tol is 1e-12.
49
+ * The verdict comes from log Λ = fsum(w_k · log x_k) over the same float64
50
+ values, as in the reference, so it never depends on how Λ rounds (a
51
+ subnormal Λ has little relative precision). A zero axis gives
52
+ log Λ = -inf and the verdict NO_GO / ZERO_VETO, a veto rather than an
53
+ error. |log Λ - log tau| <= TIE_EPS gives ABSTAIN / NUMERIC_TIE. Above
54
+ the band the verdict is GO, and below it NO_GO / BELOW_TAU.
55
+
56
+ The checks depend on the data and the verdict is a Python string, so this
57
+ entry is not meant to run inside ``torch.compile``. The legacy compiled weight
58
+ path in ``_lambda._resolve_weights``, which clamps weights to ``finfo.tiny``,
59
+ is outside szl.lambda/v1.
60
+
61
+ Λ is advisory. Λ uniqueness is Conjecture 1 (open), and nothing here depends on it.
62
+ """
63
+ from __future__ import annotations
64
+
65
+ import math
66
+ from collections import namedtuple
67
+ from typing import Any, List, Optional, Tuple
68
+
69
+ import torch
70
+
71
+ from ._lambda import lambda_aggregate
72
+
73
+ SCHEMA = "szl.lambda/v1"
74
+ UNIQUENESS = "CONJECTURE_1_NOT_USED"
75
+ WEIGHT_SUM_TOL = 1e-12
76
+ TIE_EPS = 1e-9
77
+
78
+ TYPE_INVALID = "LAMBDA_TYPE_INVALID"
79
+ EMPTY = "LAMBDA_EMPTY"
80
+ LENGTH_MISMATCH = "LAMBDA_LENGTH_MISMATCH"
81
+ NONFINITE_AXIS = "LAMBDA_NONFINITE_AXIS"
82
+ AXIS_OUT_OF_RANGE = "LAMBDA_AXIS_OUT_OF_RANGE"
83
+ NONFINITE_WEIGHT = "LAMBDA_NONFINITE_WEIGHT"
84
+ WEIGHT_NONPOSITIVE = "LAMBDA_WEIGHT_NONPOSITIVE"
85
+ WEIGHT_SUM = "LAMBDA_WEIGHT_SUM"
86
+ TAU_INVALID = "LAMBDA_TAU_INVALID"
87
+
88
+ #: Every error code, in precedence order (tau is checked first by the gate).
89
+ ERROR_CODES = (
90
+ TYPE_INVALID,
91
+ EMPTY,
92
+ LENGTH_MISMATCH,
93
+ NONFINITE_AXIS,
94
+ AXIS_OUT_OF_RANGE,
95
+ NONFINITE_WEIGHT,
96
+ WEIGHT_NONPOSITIVE,
97
+ WEIGHT_SUM,
98
+ TAU_INVALID,
99
+ )
100
+
101
+ GO = "GO"
102
+ NO_GO = "NO_GO"
103
+ ABSTAIN = "ABSTAIN"
104
+ BLOCK = "BLOCK"
105
+ VERDICTS = (GO, NO_GO, ABSTAIN, BLOCK)
106
+
107
+ ZERO_VETO = "ZERO_VETO"
108
+ BELOW_TAU = "BELOW_TAU"
109
+ NUMERIC_TIE = "NUMERIC_TIE"
110
+
111
+ _INTEGER_DTYPES = (torch.uint8, torch.int8, torch.int16, torch.int32, torch.int64)
112
+
113
+
114
+ class LambdaV1Error(ValueError):
115
+ """An input outside the szl.lambda/v1 contract. ``code`` is one of ERROR_CODES."""
116
+
117
+ def __init__(self, code: str, detail: str = "") -> None:
118
+ self.code = code
119
+ self.detail = detail
120
+ super().__init__(f"{code}: {detail}" if detail else code)
121
+
122
+
123
+ #: verdict in VERDICTS; code as in the spec's gate rules; score is Λ as a 0-d
124
+ #: float64 tensor (None on BLOCK); tau is the validated float (None when tau
125
+ #: itself is invalid); advisory is always True.
126
+ LambdaV1GateResult = namedtuple(
127
+ "LambdaV1GateResult", ["verdict", "code", "score", "tau", "advisory"]
128
+ )
129
+
130
+
131
+ def _is_real(value: Any) -> bool:
132
+ return isinstance(value, (int, float)) and not isinstance(value, bool)
133
+
134
+
135
+ def _is_real_dtype(dtype: torch.dtype) -> bool:
136
+ return dtype.is_floating_point or dtype in _INTEGER_DTYPES
137
+
138
+
139
+ def _validate(
140
+ axes: Any, weights: Any
141
+ ) -> Tuple[torch.Tensor, torch.Tensor, List[float], List[float]]:
142
+ """Float64 tensors and their values, or LambdaV1Error in the reference's phase order."""
143
+ for name, t in (("axes", axes), ("weights", weights)):
144
+ if not isinstance(t, torch.Tensor):
145
+ raise LambdaV1Error(TYPE_INVALID, f"{name} must be a 1-D torch.Tensor, got {type(t).__name__}")
146
+ if t.dim() != 1:
147
+ raise LambdaV1Error(TYPE_INVALID, f"{name} must be a 1-D tensor, got {t.dim()}-D")
148
+ k, m = axes.shape[0], weights.shape[0]
149
+ if k == 0 or m == 0:
150
+ raise LambdaV1Error(EMPTY, f"len(axes)={k}, len(weights)={m}")
151
+ if k != m:
152
+ raise LambdaV1Error(LENGTH_MISMATCH, f"len(axes)={k} != len(weights)={m}")
153
+ for name, t in (("axes", axes), ("weights", weights)):
154
+ if not _is_real_dtype(t.dtype):
155
+ raise LambdaV1Error(TYPE_INVALID, f"{name} has dtype {t.dtype}, not a real number type")
156
+ x = axes.to(torch.float64)
157
+ w = weights.to(device=x.device, dtype=torch.float64)
158
+ xs, ws = x.tolist(), w.tolist()
159
+ for i, v in enumerate(xs):
160
+ if not math.isfinite(v):
161
+ raise LambdaV1Error(NONFINITE_AXIS, f"axes[{i}]={v!r}")
162
+ for i, v in enumerate(xs):
163
+ if not 0.0 <= v <= 1.0:
164
+ raise LambdaV1Error(AXIS_OUT_OF_RANGE, f"axes[{i}]={v!r} is outside [0, 1]")
165
+ for i, v in enumerate(ws):
166
+ if not math.isfinite(v):
167
+ raise LambdaV1Error(NONFINITE_WEIGHT, f"weights[{i}]={v!r}")
168
+ for i, v in enumerate(ws):
169
+ if not v > 0.0:
170
+ raise LambdaV1Error(WEIGHT_NONPOSITIVE, f"weights[{i}]={v!r} is not > 0")
171
+ try:
172
+ total = math.fsum(ws)
173
+ except OverflowError:
174
+ raise LambdaV1Error(WEIGHT_SUM, "sum of weights overflows a float") from None
175
+ if not abs(total - 1.0) <= WEIGHT_SUM_TOL:
176
+ raise LambdaV1Error(WEIGHT_SUM, f"fsum(weights)={total!r} is not within {WEIGHT_SUM_TOL} of 1")
177
+ return x, w, xs, ws
178
+
179
+
180
+ def lambda_v1(axes: torch.Tensor, weights: torch.Tensor) -> torch.Tensor:
181
+ """Λ_w(axes) as a 0-d float64 tensor in [0, 1]; exactly 0 iff some axis is 0.
182
+
183
+ Raises ``LambdaV1Error(code)`` for any input outside szl.lambda/v1.
184
+ Differentiable with respect to ``axes``.
185
+ """
186
+ x, w, _, _ = _validate(axes, weights)
187
+ return lambda_aggregate(x, w)
188
+
189
+
190
+ def _check_tau(tau: Any) -> float:
191
+ if not _is_real(tau):
192
+ raise LambdaV1Error(TAU_INVALID, f"tau is {type(tau).__name__}, not a real number")
193
+ if isinstance(tau, float) and not math.isfinite(tau):
194
+ raise LambdaV1Error(TAU_INVALID, f"tau={tau!r} is not finite")
195
+ if not 0 < tau <= 1:
196
+ raise LambdaV1Error(TAU_INVALID, f"tau={tau!r} is outside (0, 1]")
197
+ return float(tau)
198
+
199
+
200
+ def lambda_v1_gate(axes: torch.Tensor, weights: torch.Tensor, tau: float) -> LambdaV1GateResult:
201
+ """The szl.lambda/v1 gate. It never raises on bad input; it returns BLOCK with the code.
202
+
203
+ tau is required. The compare is in log space on the unrounded value, and a
204
+ tie within TIE_EPS is ABSTAIN. A verdict is ADVISORY.
205
+ """
206
+ t: Optional[float] = None
207
+ try:
208
+ t = _check_tau(tau)
209
+ x, w, xs, ws = _validate(axes, weights)
210
+ except LambdaV1Error as err:
211
+ return LambdaV1GateResult(BLOCK, err.code, None, t, True)
212
+ score = lambda_aggregate(x, w)
213
+ if any(v == 0.0 for v in xs):
214
+ return LambdaV1GateResult(NO_GO, ZERO_VETO, score, t, True)
215
+ log_lam = math.fsum(wk * math.log(xk) for xk, wk in zip(xs, ws))
216
+ delta = log_lam - math.log(t)
217
+ if abs(delta) <= TIE_EPS:
218
+ return LambdaV1GateResult(ABSTAIN, NUMERIC_TIE, score, t, True)
219
+ if delta > 0:
220
+ return LambdaV1GateResult(GO, None, score, t, True)
221
+ return LambdaV1GateResult(NO_GO, BELOW_TAU, score, t, True)
build/torch-universal/szl_lambda_gate/governed_norm/__init__.py ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """szl_lambda_gate.governed_norm — governed normalization kernels (folded in).
4
+
5
+ CONSOLIDATION (Wave D): this subpackage is the ``szl-governed-norm`` universal
6
+ kernel folded into the canonical ``szl-lambda-gate`` kernels package so the two
7
+ duplicate micro-repos become ONE canonical home. The source repo
8
+ ``szl-holdings/szl-governed-norm`` is DEPRECATED (see its DEPRECATED.md) and
9
+ points here; nothing was deleted — this is the additive, reversible copy.
10
+
11
+ It provides correctness-verified RMSNorm and LayerNorm that run on CPU and CUDA
12
+ and are torch.compile-friendly, plus an optional *governed* path that emits
13
+ content-addressed, SHA3-256 hash-chained receipts of each call — provenance at
14
+ the kernel layer, in the spirit of the a11oy governed-AI platform
15
+ (https://a-11-oy.com).
16
+
17
+ Usage (as a subpackage of the canonical kernel)::
18
+
19
+ import torch
20
+ from szl_lambda_gate import governed_norm as gn
21
+
22
+ print(gn.selfcheck()) # one-shot correctness + receipt check
23
+ x = torch.randn(4, 1024, dtype=torch.float16)
24
+ y = gn.rms_norm(x, eps=1e-6) # plain path
25
+ y2 = gn.rms_norm(x, eps=1e-6, governed=True) # records to the default chain
26
+ chain = gn.ReceiptChain()
27
+ y3 = gn.rms_norm(x, eps=1e-6, chain=chain) # records into YOUR chain only
28
+ print(chain.verify()) # (ok, depth, first_break_seq)
29
+
30
+ Honesty: this is a universal (pure-Python) kernel — a correctness reference,
31
+ not a hand-tuned CUDA speed record. No fabricated benchmarks. Its
32
+ differentiator is verifiable governance, not raw FLOPs. Λ = Conjecture 1
33
+ (advisory, uniqueness OPEN) — never described as proven trust anywhere.
34
+
35
+ Note on torch.compile: every op is torch.compile(fullgraph=True)-compatible.
36
+ Receipt emission is an eager-only side effect (it hashes materialized tensor
37
+ bytes), so when a *governed* call is captured into a compiled graph the
38
+ numerics are unchanged but NO receipt is recorded — govern at the eager audit
39
+ boundary. This is documented honestly and covered by tests.
40
+ """
41
+ from typing import Any, Dict, List, Optional, Tuple
42
+
43
+ import torch
44
+
45
+ from . import layers # noqa: F401 (must be importable for Hub layer mapping)
46
+ from ._norm import fused_add_rms_norm as _fused_add_rms_norm
47
+ from ._norm import layer_norm as _layer_norm
48
+ from ._norm import rms_norm as _rms_norm
49
+ from ._receipt import _GENESIS as _GENESIS_HEAD
50
+ from ._receipt import ReceiptChain, default_chain, emit_receipt
51
+
52
+ __all__ = [
53
+ "rms_norm",
54
+ "layer_norm",
55
+ "fused_add_rms_norm",
56
+ "layers",
57
+ "ReceiptChain",
58
+ "emit_receipt",
59
+ "receipt_head",
60
+ "receipt_count",
61
+ "receipt_tail",
62
+ "receipt_verify",
63
+ "selfcheck",
64
+ "DOCTRINE_FOOTER",
65
+ "__version__",
66
+ ]
67
+
68
+ __version__ = "0.2.0"
69
+ DOCTRINE_FOOTER = (
70
+ "SZL Holdings · governed normalization · provenance at the kernel layer · "
71
+ "Lambda = Conjecture 1 (advisory) · honesty over checklist"
72
+ )
73
+
74
+
75
+ def _is_tracing() -> bool:
76
+ """True while torch.compile / Dynamo is tracing this code.
77
+
78
+ Receipt emission reads materialized tensor bytes (hashing on CPU), which is
79
+ an inherently eager, side-effecting host operation that cannot live inside
80
+ a traced FX graph — so under torch.compile we skip the emit. This keeps
81
+ EVERY op torch.compile(fullgraph=True)-compatible while remaining honest:
82
+ when a governed call is captured into a compiled graph, NO receipt is
83
+ recorded (the numerics are unchanged and identical to the eager path).
84
+ Governance is intended for the eager audit boundary; record receipts there.
85
+ """
86
+ is_compiling = getattr(torch.compiler, "is_compiling", None)
87
+ return bool(is_compiling()) if is_compiling is not None else False
88
+
89
+
90
+ def _emit(
91
+ chain: Optional[ReceiptChain],
92
+ op: str,
93
+ x: torch.Tensor,
94
+ out: torch.Tensor,
95
+ eps: float,
96
+ sign_key: Optional[Any] = None,
97
+ organ: str = "szl-governed-norm",
98
+ ) -> None:
99
+ """Append a receipt to ``chain`` (or the process default chain if None).
100
+
101
+ No-op while torch.compile is tracing (see ``_is_tracing``). When
102
+ ``sign_key`` (a PEM ECDSA-P256 private key) is supplied and szl-receipt is
103
+ installed, the receipt carries an additive DSSE ``signature`` envelope;
104
+ keyless is UNSIGNED-honest.
105
+ """
106
+ if _is_tracing():
107
+ return
108
+ target = chain if chain is not None else default_chain()
109
+ target.emit(op, x, out, eps, sign_key=sign_key, organ=organ)
110
+
111
+
112
+ def rms_norm(
113
+ x: torch.Tensor,
114
+ weight: Optional[torch.Tensor] = None,
115
+ eps: float = 1e-6,
116
+ governed: bool = False,
117
+ chain: Optional[ReceiptChain] = None,
118
+ sign_key: Optional[Any] = None,
119
+ organ: str = "szl-governed-norm",
120
+ ) -> torch.Tensor:
121
+ """RMSNorm over the last dim.
122
+
123
+ If ``governed=True``, append an audit receipt. By default the receipt goes
124
+ to the process-wide default chain (convenient). Pass your own ``chain`` (a
125
+ ``ReceiptChain`` instance) to record into a caller-owned chain instead —
126
+ this avoids global-state contention when many threads/requests govern
127
+ independently. Passing ``chain`` implies governance even if
128
+ ``governed=False`` is left at its default. Pass ``sign_key`` (PEM
129
+ ECDSA-P256) to additively sign the receipt via szl-receipt.
130
+ """
131
+ out = _rms_norm(x, weight=weight, eps=eps)
132
+ if governed or chain is not None:
133
+ _emit(chain, "rms_norm", x, out, eps, sign_key=sign_key, organ=organ)
134
+ return out
135
+
136
+
137
+ def layer_norm(
138
+ x: torch.Tensor,
139
+ weight: Optional[torch.Tensor] = None,
140
+ bias: Optional[torch.Tensor] = None,
141
+ eps: float = 1e-5,
142
+ governed: bool = False,
143
+ chain: Optional[ReceiptChain] = None,
144
+ sign_key: Optional[Any] = None,
145
+ organ: str = "szl-governed-norm",
146
+ ) -> torch.Tensor:
147
+ """LayerNorm over the last dim.
148
+
149
+ If ``governed=True`` (or a ``chain`` is supplied), append an audit receipt
150
+ to ``chain`` when given, otherwise to the process default chain. See
151
+ ``rms_norm`` for the per-call ``chain`` rationale and ``sign_key``.
152
+ """
153
+ out = _layer_norm(x, weight=weight, bias=bias, eps=eps)
154
+ if governed or chain is not None:
155
+ _emit(chain, "layer_norm", x, out, eps, sign_key=sign_key, organ=organ)
156
+ return out
157
+
158
+
159
+ def fused_add_rms_norm(
160
+ x: torch.Tensor,
161
+ residual: torch.Tensor,
162
+ weight: Optional[torch.Tensor] = None,
163
+ eps: float = 1e-6,
164
+ governed: bool = False,
165
+ chain: Optional[ReceiptChain] = None,
166
+ sign_key: Optional[Any] = None,
167
+ organ: str = "szl-governed-norm",
168
+ ) -> Tuple[torch.Tensor, torch.Tensor]:
169
+ """Residual-add + RMSNorm (transformer block pattern).
170
+
171
+ Returns ``(y, new_residual)`` where ``new_residual = x + residual`` and
172
+ ``y = rms_norm(new_residual, weight, eps)``. If ``governed=True`` (or a
173
+ ``chain`` is supplied), append an audit receipt over the normalized output
174
+ to ``chain`` when given, otherwise to the process default chain. Pass
175
+ ``sign_key`` to additively sign the receipt via szl-receipt.
176
+ """
177
+ out, new_residual = _fused_add_rms_norm(x, residual, weight=weight, eps=eps)
178
+ if governed or chain is not None:
179
+ _emit(chain, "fused_add_rms_norm", x, out, eps, sign_key=sign_key, organ=organ)
180
+ return out, new_residual
181
+
182
+
183
+ # ---- governance receipt surface (operates on the default in-process chain) --
184
+ def receipt_head() -> str:
185
+ """SHA3-256 head of the governed-call receipt chain ('0'*64 if empty)."""
186
+ return default_chain().head()
187
+
188
+
189
+ def receipt_count() -> int:
190
+ """Number of governed calls recorded."""
191
+ return default_chain().count()
192
+
193
+
194
+ def receipt_tail(n: int = 10) -> List[Dict[str, Any]]:
195
+ """Last n receipts."""
196
+ return default_chain().tail(n)
197
+
198
+
199
+ def receipt_verify() -> Dict[str, Any]:
200
+ """Re-walk the receipt chain. Returns {ok, depth, first_break_seq}."""
201
+ ok, depth, brk = default_chain().verify()
202
+ return {"ok": ok, "depth": depth, "first_break_seq": brk, "head": default_chain().head()}
203
+
204
+
205
+ # ---- one-shot self-verification --------------------------------------------
206
+ def selfcheck() -> Dict[str, Any]:
207
+ """Verify correctness + governance in a single call; never raises.
208
+
209
+ Runs a tiny, self-contained, CPU-only smoke test against PyTorch references
210
+ so downstream code (and SZL's own a11oy / hatun-mcp) can confirm the loaded
211
+ kernel is the real, working article before trusting it.
212
+
213
+ Checks (all on a *private, throwaway* ReceiptChain so the process default
214
+ chain is never touched):
215
+ * ``rms_norm`` matches a Llama-style float32 reference,
216
+ * ``layer_norm`` matches ``torch.nn.functional.layer_norm``,
217
+ * ``fused_add_rms_norm`` matches the unfused add-then-norm path,
218
+ * a governed call emits exactly one receipt and the chain verifies.
219
+
220
+ Returns a JSON-able dict:
221
+ ``{ok, version, checks: {name: bool}, receipt_ok, receipt_head, error}``
222
+ ``ok`` is True iff every check passed. On unexpected failure ``ok`` is
223
+ False and ``error`` carries the message — this function is designed to be
224
+ safe to call in a health probe and will not raise.
225
+ """
226
+ checks: Dict[str, bool] = {}
227
+ receipt_ok = False
228
+ receipt_head = _GENESIS_HEAD
229
+ error = None
230
+ try:
231
+ torch.manual_seed(0)
232
+ x = torch.randn(4, 64, dtype=torch.float32)
233
+ w = torch.randn(64, dtype=torch.float32)
234
+ b = torch.randn(64, dtype=torch.float32)
235
+ res = torch.randn(4, 64, dtype=torch.float32)
236
+ eps_r, eps_l = 1e-6, 1e-5
237
+
238
+ # rms_norm vs Llama-style fp32 reference
239
+ xf = x.to(torch.float32)
240
+ ref_rms = (xf * torch.rsqrt(xf.pow(2).mean(-1, keepdim=True) + eps_r)) * w
241
+ checks["rms_norm"] = bool(
242
+ torch.allclose(rms_norm(x, weight=w, eps=eps_r), ref_rms, rtol=1e-5, atol=1e-5)
243
+ )
244
+
245
+ # layer_norm vs torch reference
246
+ ref_ln = torch.nn.functional.layer_norm(x, (64,), weight=w, bias=b, eps=eps_l)
247
+ checks["layer_norm"] = bool(
248
+ torch.allclose(layer_norm(x, weight=w, bias=b, eps=eps_l), ref_ln,
249
+ rtol=1e-5, atol=1e-5)
250
+ )
251
+
252
+ # fused_add_rms_norm vs unfused path
253
+ y_f, new_res = fused_add_rms_norm(x, res, weight=w, eps=eps_r)
254
+ h = x.to(torch.float32) + res.to(torch.float32)
255
+ ref_y = rms_norm(h.to(x.dtype), weight=w, eps=eps_r)
256
+ checks["fused_add_rms_norm"] = bool(
257
+ torch.allclose(y_f, ref_y, rtol=1e-5, atol=1e-5)
258
+ and torch.allclose(new_res, h.to(x.dtype), rtol=1e-6, atol=1e-6)
259
+ )
260
+
261
+ # governance on a private chain: one emit, chain verifies
262
+ probe_chain = ReceiptChain()
263
+ rms_norm(x, weight=w, eps=eps_r, chain=probe_chain)
264
+ ok, depth, brk = probe_chain.verify()
265
+ receipt_ok = bool(ok and depth == 1 and brk == -1)
266
+ receipt_head = probe_chain.head()
267
+ checks["governance"] = receipt_ok
268
+ except Exception as exc: # never raise from a health probe
269
+ error = f"{type(exc).__name__}: {exc}"
270
+
271
+ ok = bool(checks) and all(checks.values()) and error is None
272
+ return {
273
+ "ok": ok,
274
+ "version": __version__,
275
+ "checks": checks,
276
+ "receipt_ok": receipt_ok,
277
+ "receipt_head": receipt_head,
278
+ "error": error,
279
+ }
build/torch-universal/szl_lambda_gate/governed_norm/_norm.py ADDED
@@ -0,0 +1,246 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Pure-PyTorch normalization primitives for the SZL governed-norm kernel.
4
+
5
+ These are correctness-verified reference implementations (RMSNorm, LayerNorm,
6
+ and the residual-fused RMSNorm pattern used by transformer blocks) written in
7
+ pure PyTorch. They run on CPU and CUDA, are torch.compile-friendly, and depend
8
+ ONLY on torch + the Python standard library (a Kernel Hub requirement for
9
+ universal kernels).
10
+
11
+ HONESTY: this is a *universal* (pure-Python) kernel. It does NOT ship a
12
+ hand-tuned CUDA/Triton binary, so it is a correctness reference, not a
13
+ speed record. We make no fabricated benchmark claims. Where it adds value
14
+ is the optional *governed* path (see _receipt.py): every normalization call
15
+ can emit a content-addressed, hash-chained receipt of its inputs/outputs so
16
+ the operation is auditable — SZL Holdings' provenance doctrine applied at
17
+ the kernel layer.
18
+
19
+ Numerical convention (all ops): reductions and the normalization math are
20
+ computed in float32 for stability, then the result is cast back to the input
21
+ dtype. This is the standard Llama-style convention and is what makes
22
+ float16 / bfloat16 inputs numerically well-behaved.
23
+
24
+ Validation convention: guards below are cheap, branch-only checks on metadata
25
+ (dtype / ndim / shape / device) — they allocate nothing on the happy path and
26
+ constant-fold away under torch.compile, so they do not perturb traced graphs.
27
+ They exist to turn silent broadcasting / device-mismatch bugs into clear,
28
+ early errors. A zero-size normalized last dimension is rejected (normalizing
29
+ over zero elements is undefined); a single-element last dimension is allowed
30
+ (RMSNorm yields sign(x); LayerNorm yields 0, matching F.layer_norm).
31
+
32
+ Non-finite convention (NaN / Inf inputs): these ops do NOT sanitize their
33
+ input. A NaN or Inf in the input propagates through the reduction and appears
34
+ in the output, exactly as it would in torch.nn.functional.layer_norm / a
35
+ hand-written kernel. We deliberately do NOT silently replace non-finite values
36
+ (that would hide upstream numerical bugs); detecting/handling them is the
37
+ caller's responsibility. This propagation behavior is covered by regression
38
+ tests so it cannot change unnoticed.
39
+ """
40
+ from typing import Optional
41
+
42
+ import torch
43
+
44
+ # Floating dtypes this kernel supports. Integer / complex inputs are rejected
45
+ # early with a clear message rather than silently producing garbage.
46
+ _SUPPORTED_DTYPES = (torch.float16, torch.bfloat16, torch.float32, torch.float64)
47
+
48
+
49
+ def _compute_dtype(in_dtype: torch.dtype) -> torch.dtype:
50
+ """Reduction/normalization compute dtype.
51
+
52
+ Low-precision inputs (fp16/bf16) are upcast to float32 for stability — the
53
+ standard Llama-style convention. float64 inputs are NOT downcast: doing so
54
+ would silently lose precision (and break gradcheck), so we keep float64.
55
+ """
56
+ return torch.float32 if in_dtype in (torch.float16, torch.bfloat16) else in_dtype
57
+
58
+
59
+ def _check_input(x: torch.Tensor, name: str = "x") -> None:
60
+ """Cheap, allocation-free guards on the primary input tensor.
61
+
62
+ Only inspects metadata (type / dtype / ndim), so it is constant-folded by
63
+ torch.compile and adds no runtime tensor work on the happy path.
64
+ """
65
+ if not isinstance(x, torch.Tensor):
66
+ raise TypeError(f"{name} must be a torch.Tensor, got {type(x).__name__}")
67
+ if x.dtype not in _SUPPORTED_DTYPES:
68
+ raise TypeError(
69
+ f"{name} has unsupported dtype {x.dtype}; "
70
+ f"expected one of {tuple(str(d) for d in _SUPPORTED_DTYPES)}"
71
+ )
72
+ if x.dim() < 1:
73
+ raise ValueError(
74
+ f"{name} must have at least 1 dimension (the normalized dim); "
75
+ f"got a {x.dim()}-d tensor"
76
+ )
77
+ # A zero-size normalized (last) dimension is mathematically undefined:
78
+ # mean/RMS over zero elements is NaN, so normalization has no meaning.
79
+ # Reject it early with a clear message instead of silently returning an
80
+ # empty/NaN tensor (the classic shape-bug-masquerading-as-success case).
81
+ if x.shape[-1] == 0:
82
+ raise ValueError(
83
+ f"{name} has a zero-size normalized last dimension {tuple(x.shape)}; "
84
+ f"normalization over zero elements is undefined"
85
+ )
86
+
87
+
88
+ def _check_affine(
89
+ x: torch.Tensor,
90
+ param: Optional[torch.Tensor],
91
+ name: str,
92
+ ) -> None:
93
+ """Validate an optional affine parameter (weight/bias/residual peer).
94
+
95
+ Enforces that the parameter is 1-D and matches the normalized (last)
96
+ dimension, and lives on the same device as ``x``. This catches the
97
+ classic silent-broadcast bug where a mis-shaped weight would broadcast
98
+ instead of erroring. Metadata-only: no allocations.
99
+ """
100
+ if param is None:
101
+ return
102
+ if not isinstance(param, torch.Tensor):
103
+ raise TypeError(f"{name} must be a torch.Tensor or None, got {type(param).__name__}")
104
+ if param.device != x.device:
105
+ raise ValueError(
106
+ f"{name} is on device {param.device} but x is on {x.device}; "
107
+ f"move them to the same device"
108
+ )
109
+ last = x.shape[-1]
110
+ if param.dim() != 1 or param.shape[0] != last:
111
+ raise ValueError(
112
+ f"{name} must be 1-D with shape ({last},) to match the normalized "
113
+ f"last dimension of x; got shape {tuple(param.shape)}"
114
+ )
115
+
116
+
117
+ def _check_eps(eps: float) -> None:
118
+ """eps must be a positive, finite scalar (rsqrt(var+eps) must be safe)."""
119
+ e = float(eps)
120
+ if not (e > 0.0) or e != e or e == float("inf"):
121
+ raise ValueError(f"eps must be a positive finite float, got {eps!r}")
122
+
123
+
124
+ def rms_norm(
125
+ x: torch.Tensor,
126
+ weight: Optional[torch.Tensor] = None,
127
+ eps: float = 1e-6,
128
+ ) -> torch.Tensor:
129
+ """Root-mean-square layer normalization over the last dimension.
130
+
131
+ y = x / sqrt(mean(x^2, dim=-1) + eps) * weight
132
+
133
+ Computed in float32 for numerical stability, then cast back to the input
134
+ dtype (the standard, correctness-preserving convention used by Llama-style
135
+ RMSNorm). `weight` is optional; when omitted, no affine scale is applied.
136
+
137
+ Raises clear TypeError/ValueError on bad dtype, rank, eps, or a weight
138
+ whose shape/device does not match x's normalized dimension.
139
+ """
140
+ _check_input(x)
141
+ _check_eps(eps)
142
+ _check_affine(x, weight, "weight")
143
+
144
+ in_dtype = x.dtype
145
+ xf = x.to(_compute_dtype(in_dtype))
146
+ variance = xf.pow(2).mean(dim=-1, keepdim=True)
147
+ xf = xf * torch.rsqrt(variance + eps)
148
+ out = xf.to(in_dtype)
149
+ if weight is not None:
150
+ out = out * weight
151
+ return out
152
+
153
+
154
+ def layer_norm(
155
+ x: torch.Tensor,
156
+ weight: Optional[torch.Tensor] = None,
157
+ bias: Optional[torch.Tensor] = None,
158
+ eps: float = 1e-5,
159
+ ) -> torch.Tensor:
160
+ """Standard layer normalization over the last dimension.
161
+
162
+ Mean/variance computed in float32 for stability, then cast back. Matches
163
+ torch.nn.functional.layer_norm semantics for the normalized-shape = last
164
+ dim case; verified against it in the test suite.
165
+
166
+ Raises clear TypeError/ValueError on bad dtype, rank, eps, or a
167
+ weight/bias whose shape/device does not match x's normalized dimension.
168
+ """
169
+ _check_input(x)
170
+ _check_eps(eps)
171
+ _check_affine(x, weight, "weight")
172
+ _check_affine(x, bias, "bias")
173
+
174
+ in_dtype = x.dtype
175
+ xf = x.to(_compute_dtype(in_dtype))
176
+ mean = xf.mean(dim=-1, keepdim=True)
177
+ # Biased (population) variance = mean of squared deviations. We compute it
178
+ # directly rather than via Tensor.var(unbiased=False): torch's .var emits a
179
+ # "degrees of freedom <= 0" UserWarning when the normalized dim has a single
180
+ # element, even though unbiased=False is well-defined there (variance 0).
181
+ # Computing it ourselves matches F.layer_norm exactly and stays silent and
182
+ # torch.compile(fullgraph=True)-clean for the single-element edge case.
183
+ centered = xf - mean
184
+ var = centered.pow(2).mean(dim=-1, keepdim=True)
185
+ xf = centered * torch.rsqrt(var + eps)
186
+ out = xf.to(in_dtype)
187
+ if weight is not None:
188
+ out = out * weight
189
+ if bias is not None:
190
+ out = out + bias
191
+ return out
192
+
193
+
194
+ def fused_add_rms_norm(
195
+ x: torch.Tensor,
196
+ residual: torch.Tensor,
197
+ weight: Optional[torch.Tensor] = None,
198
+ eps: float = 1e-6,
199
+ ):
200
+ """Residual-add followed by RMSNorm — the canonical transformer block pattern.
201
+
202
+ h = x + residual # updated residual stream
203
+ y = rms_norm(h, weight, eps)
204
+ return y, h
205
+
206
+ This mirrors the `fused_add_rms_norm` used in real LLM inference stacks
207
+ (e.g. the pre-norm transformer block: the normalized output `y` feeds the
208
+ sublayer, while the un-normalized sum `h` is carried forward as the next
209
+ residual). We return BOTH so callers can thread the residual stream, which
210
+ is exactly why the fused form exists.
211
+
212
+ HONESTY: "fused" here means *logically* fused (one Python op, one float32
213
+ cast path, the add done in float32 alongside the norm) — it is a correct,
214
+ allocation-conscious pure-PyTorch reference, not a hand-written fused CUDA
215
+ kernel. No speed claims are made.
216
+
217
+ The add is performed in float32 so that, for float16/bfloat16 inputs, the
218
+ residual accumulation does not lose precision before normalization — this
219
+ matches high-quality reference implementations.
220
+ """
221
+ _check_input(x, "x")
222
+ _check_input(residual, "residual")
223
+ _check_eps(eps)
224
+ if residual.shape != x.shape:
225
+ raise ValueError(
226
+ f"residual shape {tuple(residual.shape)} must equal x shape "
227
+ f"{tuple(x.shape)} for the residual add"
228
+ )
229
+ if residual.device != x.device:
230
+ raise ValueError(
231
+ f"residual is on device {residual.device} but x is on {x.device}; "
232
+ f"move them to the same device"
233
+ )
234
+ _check_affine(x, weight, "weight")
235
+
236
+ in_dtype = x.dtype
237
+ cdt = _compute_dtype(in_dtype)
238
+ # Add in compute dtype, keep both the normalized output and the residual.
239
+ hf = x.to(cdt) + residual.to(cdt)
240
+ new_residual = hf.to(in_dtype)
241
+ variance = hf.pow(2).mean(dim=-1, keepdim=True)
242
+ yf = hf * torch.rsqrt(variance + eps)
243
+ out = yf.to(in_dtype)
244
+ if weight is not None:
245
+ out = out * weight
246
+ return out, new_residual
build/torch-universal/szl_lambda_gate/governed_norm/_receipt.py ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Content-addressed governance receipts for normalization calls.
4
+
5
+ SZL Holdings' provenance doctrine applied at the kernel layer: when a
6
+ normalization runs in *governed* mode, it emits a small, deterministic
7
+ receipt describing the call — input shape/dtype, eps, and a SHA3-256 digest
8
+ of the (quantized) output tensor — and hash-chains it to the previous
9
+ receipt. This makes a sequence of kernel calls independently auditable
10
+ without trusting the caller.
11
+
12
+ HONESTY:
13
+ - The digest is a real SHA3-256 over the output bytes (rounded to a fixed
14
+ decimal precision so it is reproducible across runs/devices). It is an
15
+ integrity fingerprint, NOT a cryptographic signature — we never claim
16
+ it proves authorship. DSSE signing is a separate, out-of-band concern.
17
+ - Receipts are kept in an in-process, append-only chain. Nothing is written
18
+ to disk or the network from inside the kernel.
19
+ - Stdlib + torch (+ numpy for the output digest) only — Kernel Hub
20
+ universal-kernel requirement.
21
+ - The canonical szl-receipt v0.2.0 evidence binding (``emit_receipt``) is
22
+ ADDITIVE and IMPORT-GUARDED: with szl-receipt absent it returns ``None`` and
23
+ the kernel runs unchanged. It binds subject / input-digest / output-digest /
24
+ policy-id / energy; energy is the literal string "UNAVAILABLE" because this
25
+ kernel measures NO joules — a value is never fabricated. Like the SHA3-256
26
+ chain, it is an EVIDENCE trail, NOT a proof of correctness.
27
+ """
28
+ import hashlib
29
+ import json
30
+ import threading
31
+ import time
32
+ from typing import Any, Dict, List, Optional, Union
33
+
34
+ import torch
35
+
36
+ _GENESIS = "0" * 64
37
+
38
+ # Logical signing-authority label stamped onto signature envelopes.
39
+ _ORGAN = "szl-governed-norm"
40
+
41
+ # Governing policy id bound into every canonical szl-receipt evidence binding.
42
+ _POLICY_ID = "szl-governed-norm/provenance@v1"
43
+
44
+ # This universal kernel measures NO joules. The honesty doctrine forbids
45
+ # fabricating an energy value, so the canonical binding records the literal
46
+ # string "UNAVAILABLE" rather than a placeholder number.
47
+ _ENERGY_UNAVAILABLE = "UNAVAILABLE"
48
+
49
+
50
+ def _maybe_sign(
51
+ body: Dict[str, Any],
52
+ sign_key: Optional[Union[str, bytes]],
53
+ organ: str,
54
+ ) -> Optional[Dict[str, Any]]:
55
+ """ADDITIVE szl-receipt signature layer over the receipt *body*.
56
+
57
+ Returns a DSSE envelope (from ``szl_receipt.sign_receipt``) covering the
58
+ exact canonical body, or ``None`` when szl-receipt is not installed (the
59
+ kernel then behaves exactly as before). Doctrine: with no *sign_key* the
60
+ envelope is UNSIGNED-honest (``signed=False``); a signature is NEVER
61
+ fabricated. This is distinct from and additive to the SHA3-256 chain
62
+ integrity hash (``digest``) — szl-receipt's envelope carries its own
63
+ SHA-256 ``digest``/``algo`` so the two integrity hashes are explicit.
64
+ """
65
+ try:
66
+ from szl_receipt import Receipt, sign_receipt
67
+ except Exception: # noqa: BLE001 - signing is optional; absence is honest
68
+ return None
69
+ env = sign_receipt(Receipt(kind="governed-norm", body=body),
70
+ sign_key, organ=organ)
71
+ return env
72
+
73
+
74
+ def _tensor_digest(t: torch.Tensor, decimals: int = 6) -> str:
75
+ """Deterministic SHA3-256 over a tensor's rounded float32 contents.
76
+
77
+ Rounding to a fixed number of decimals makes the digest stable across
78
+ devices/dtypes for the same logical values (tiny FP noise won't change
79
+ it). This is an integrity fingerprint, not a signature.
80
+ """
81
+ flat = t.detach().to(torch.float32).reshape(-1)
82
+ # Round to `decimals` places, integerize, hash the raw bytes. CPU move is
83
+ # required to read bytes; kept O(n) and allocation-light.
84
+ scaled = torch.round(flat * (10 ** decimals)).to(torch.int64).cpu().numpy().tobytes()
85
+ h = hashlib.sha3_256()
86
+ h.update(scaled)
87
+ return h.hexdigest()
88
+
89
+
90
+ def _input_digest(x: torch.Tensor, eps: float) -> str:
91
+ """SHA3-256 over the canonical JSON of a call's input spec.
92
+
93
+ Binds {input shape, dtype, eps} — the *shape* of the call, not the input
94
+ bytes — so the receipt is a compact fingerprint of what produced the
95
+ output. Deterministic and stdlib-only (json + hashlib).
96
+ """
97
+ spec = {
98
+ "in_shape": list(x.shape),
99
+ "in_dtype": str(x.dtype).replace("torch.", ""),
100
+ "eps": float(eps),
101
+ }
102
+ raw = json.dumps(spec, sort_keys=True, separators=(",", ":")).encode("utf-8")
103
+ return hashlib.sha3_256(raw).hexdigest()
104
+
105
+
106
+ def emit_receipt(
107
+ op: str,
108
+ x: torch.Tensor,
109
+ out: torch.Tensor,
110
+ eps: float,
111
+ subject: Optional[str] = None,
112
+ policy_id: str = _POLICY_ID,
113
+ sign_key: Optional[Union[str, bytes]] = None,
114
+ organ: str = _ORGAN,
115
+ ) -> Optional[Dict[str, Any]]:
116
+ """Canonical szl-receipt v0.2.0 evidence binding for a governed-norm call.
117
+
118
+ ADDITIVE and IMPORT-GUARDED: returns ``None`` when szl-receipt is not
119
+ installed, so this universal Kernel-Hub kernel still imports and runs on
120
+ stdlib + torch + numpy alone. When szl-receipt is present it binds an
121
+ EVIDENCE trail and wraps it in a DSSE envelope via ``sign_receipt``:
122
+
123
+ subject organ / norm-call id (who/what emitted this)
124
+ input_digest SHA3-256 over canonical {input shape, dtype, eps}
125
+ output_digest the EXISTING SHA3-256 rounded-tensor digest of ``out``
126
+ policy_id the governing policy id
127
+ energy the literal string "UNAVAILABLE"
128
+
129
+ Doctrine (non-negotiable):
130
+ * A receipt is an integrity/EVIDENCE trail, NOT a proof of correctness.
131
+ * ``energy == "UNAVAILABLE"`` — this kernel measures NO joules; a joule is
132
+ NEVER fabricated.
133
+ * Keyless => UNSIGNED-honest (``signature["signed"] is False``); a
134
+ signature is NEVER fabricated. A real ``sign_key`` yields a real DSSE
135
+ signature over the exact canonical binding.
136
+
137
+ Returns the binding dict (subject/input_digest/output_digest/policy_id/
138
+ energy) with the DSSE envelope under ``signature``, or ``None`` when
139
+ szl-receipt is absent.
140
+ """
141
+ try:
142
+ from szl_receipt import Receipt, sign_receipt
143
+ except Exception: # noqa: BLE001 - canonical binding is optional; absence is honest
144
+ return None
145
+ body = {
146
+ "subject": subject if subject is not None else f"{organ}/{op}",
147
+ "input_digest": _input_digest(x, eps),
148
+ "output_digest": _tensor_digest(out),
149
+ "policy_id": policy_id,
150
+ "energy": _ENERGY_UNAVAILABLE,
151
+ }
152
+ env = sign_receipt(Receipt(kind="governed-norm", body=body), sign_key, organ=organ)
153
+ return dict(body, signature=env)
154
+
155
+
156
+ class ReceiptChain:
157
+ """Append-only, SHA3-256 hash-chained log of normalization receipts.
158
+
159
+ Each receipt: {seq, op, in_shape, in_dtype, eps, out_digest, prev, digest, ts}
160
+ digest = SHA3-256 over the canonical JSON body (excluding digest/ts).
161
+ verify() re-walks the chain and returns (ok, depth, first_break_seq).
162
+ """
163
+
164
+ def __init__(self) -> None:
165
+ self._lock = threading.RLock()
166
+ self._records: List[Dict[str, Any]] = []
167
+
168
+ @staticmethod
169
+ def _digest_body(body: Dict[str, Any]) -> str:
170
+ raw = json.dumps(body, sort_keys=True, separators=(",", ":")).encode("utf-8")
171
+ return hashlib.sha3_256(raw).hexdigest()
172
+
173
+ def emit(
174
+ self,
175
+ op: str,
176
+ x: torch.Tensor,
177
+ out: torch.Tensor,
178
+ eps: float,
179
+ sign_key: Optional[Union[str, bytes]] = None,
180
+ organ: str = _ORGAN,
181
+ policy_id: str = _POLICY_ID,
182
+ ) -> Dict[str, Any]:
183
+ with self._lock:
184
+ prev = self._records[-1]["digest"] if self._records else _GENESIS
185
+ seq = len(self._records)
186
+ body = {
187
+ "seq": seq,
188
+ "op": op,
189
+ "in_shape": list(x.shape),
190
+ "in_dtype": str(x.dtype).replace("torch.", ""),
191
+ "eps": float(eps),
192
+ "out_digest": _tensor_digest(out),
193
+ "prev": prev,
194
+ }
195
+ digest = self._digest_body(body)
196
+ rec = dict(body, digest=digest, ts=time.time())
197
+ sig = _maybe_sign(body, sign_key, organ)
198
+ if sig is not None:
199
+ rec["signature"] = sig
200
+ # ADDITIVE canonical szl-receipt v0.2.0 evidence binding. Import-
201
+ # guarded: None when szl-receipt is absent, so the universal kernel
202
+ # keeps working on stdlib + torch + numpy only. Binds subject /
203
+ # input-digest / output-digest / policy-id / energy; energy is
204
+ # "UNAVAILABLE" (no joules measured here). It does NOT enter the
205
+ # SHA3-256 chain body, so verify() is unaffected.
206
+ binding = emit_receipt(
207
+ op, x, out, eps,
208
+ subject=f"{organ}/{op}#{seq}",
209
+ policy_id=policy_id,
210
+ sign_key=sign_key,
211
+ organ=organ,
212
+ )
213
+ if binding is not None:
214
+ rec["receipt"] = binding
215
+ self._records.append(rec)
216
+ return rec
217
+
218
+ def head(self) -> str:
219
+ with self._lock:
220
+ return self._records[-1]["digest"] if self._records else _GENESIS
221
+
222
+ def count(self) -> int:
223
+ with self._lock:
224
+ return len(self._records)
225
+
226
+ def tail(self, n: int = 10) -> List[Dict[str, Any]]:
227
+ with self._lock:
228
+ return list(self._records[-n:])
229
+
230
+ def verify(self):
231
+ """Re-walk the chain. Returns (ok: bool, depth: int, first_break: int)."""
232
+ with self._lock:
233
+ prev = _GENESIS
234
+ for i, rec in enumerate(self._records):
235
+ body = {k: rec[k] for k in
236
+ ("seq", "op", "in_shape", "in_dtype", "eps", "out_digest", "prev")}
237
+ if rec["prev"] != prev or rec["digest"] != self._digest_body(body):
238
+ return (False, len(self._records), i)
239
+ prev = rec["digest"]
240
+ return (True, len(self._records), -1)
241
+
242
+
243
+ # Module-level default chain (opt-in: only written when governed=True is used).
244
+ _DEFAULT_CHAIN: Optional[ReceiptChain] = None
245
+ _chain_lock = threading.Lock()
246
+
247
+
248
+ def default_chain() -> ReceiptChain:
249
+ global _DEFAULT_CHAIN
250
+ with _chain_lock:
251
+ if _DEFAULT_CHAIN is None:
252
+ _DEFAULT_CHAIN = ReceiptChain()
253
+ return _DEFAULT_CHAIN
build/torch-universal/szl_lambda_gate/governed_norm/layers.py ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Hub-compliant kernel layers.
4
+
5
+ Per the Kernel Hub `kernel-requirements`, layers exposed for extension must
6
+ be PURE torch.nn.Module subclasses:
7
+ - no custom __init__,
8
+ - no class variables,
9
+ - only a `forward` method,
10
+ - forward signature compatible with the module it extends.
11
+
12
+ These layers therefore read their parameters (weight/bias/eps) off the
13
+ module instance they are bound to (set by the host model), and only define
14
+ `forward`. They are drop-in replacements for an existing RMSNorm/LayerNorm
15
+ module via the `kernels` layer-mapping mechanism.
16
+ """
17
+ import torch
18
+ from torch import nn
19
+
20
+ from ._norm import fused_add_rms_norm, layer_norm, rms_norm
21
+
22
+
23
+ class RMSNorm(nn.Module):
24
+ """Pure RMSNorm layer. Expects the host module to provide `self.weight`
25
+ (optional) and `self.variance_epsilon` or `self.eps`."""
26
+
27
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
28
+ weight = getattr(self, "weight", None)
29
+ eps = getattr(self, "variance_epsilon", None)
30
+ if eps is None:
31
+ eps = getattr(self, "eps", 1e-6)
32
+ return rms_norm(hidden_states, weight=weight, eps=float(eps))
33
+
34
+
35
+ class LayerNorm(nn.Module):
36
+ """Pure LayerNorm layer. Expects the host module to provide `self.weight`
37
+ (optional), `self.bias` (optional), and `self.eps`."""
38
+
39
+ def forward(self, hidden_states: torch.Tensor) -> torch.Tensor:
40
+ weight = getattr(self, "weight", None)
41
+ bias = getattr(self, "bias", None)
42
+ eps = getattr(self, "eps", 1e-5)
43
+ return layer_norm(hidden_states, weight=weight, bias=bias, eps=float(eps))
44
+
45
+
46
+ class FusedAddRMSNorm(nn.Module):
47
+ """Pure residual-add + RMSNorm layer for pre-norm transformer blocks.
48
+
49
+ Expects the host module to provide `self.weight` (optional) and
50
+ `self.variance_epsilon` or `self.eps`. Returns `(normalized, new_residual)`
51
+ where `new_residual = hidden_states + residual` is carried forward as the
52
+ next block's residual stream.
53
+ """
54
+
55
+ def forward(self, hidden_states: torch.Tensor, residual: torch.Tensor):
56
+ weight = getattr(self, "weight", None)
57
+ eps = getattr(self, "variance_epsilon", None)
58
+ if eps is None:
59
+ eps = getattr(self, "eps", 1e-6)
60
+ return fused_add_rms_norm(hidden_states, residual, weight=weight, eps=float(eps))
build/torch-universal/szl_lambda_gate/layers.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """Hub-compliant kernel layer for the szl-lambda-gate kernel.
4
+
5
+ Per the Kernel Hub `kernel-requirements`, layers exposed for extension must be
6
+ PURE torch.nn.Module subclasses:
7
+ - no custom __init__,
8
+ - no class variables,
9
+ - only a `forward` method.
10
+
11
+ The layer therefore reads its parameters (weights / threshold) off the module
12
+ instance it is bound to (set by the host model) and only defines `forward`.
13
+
14
+ HONESTY: `LambdaGate` emits an ADVISORY governance signal (the weighted
15
+ geometric mean Λ plus a pass/fail vs threshold). Λ is NOT proven trust; its
16
+ uniqueness is Conjecture 1 (open).
17
+ """
18
+ import torch
19
+ from torch import nn
20
+
21
+ from ._lambda import lambda_aggregate, lambda_gate
22
+
23
+
24
+ class LambdaGate(nn.Module):
25
+ """Pure Λ-gate layer.
26
+
27
+ Reads optional ``self.weights`` (1-D, length k) and ``self.threshold``
28
+ (float) off the bound module instance. An unset threshold uses the legacy
29
+ 0.5 with a DeprecationWarning (see ``lambda_gate``); set it explicitly.
30
+
31
+ forward(axes) -> LambdaGateResult(score, passed, threshold, advisory) where
32
+ ``score`` = Λ(axes) over the last dim and ``passed`` = score >= threshold.
33
+ Differentiable in ``score`` w.r.t. ``axes``.
34
+ """
35
+
36
+ def forward(self, axes: torch.Tensor):
37
+ weights = getattr(self, "weights", None)
38
+ threshold = getattr(self, "threshold", None)
39
+ if threshold is not None:
40
+ threshold = float(threshold)
41
+ return lambda_gate(axes, weights=weights, threshold=threshold)
42
+
43
+
44
+ class LambdaAggregate(nn.Module):
45
+ """Pure Λ-aggregator layer: forward(axes) -> Λ(axes) tensor in [0,1].
46
+
47
+ Reads optional ``self.weights`` (1-D, length k) off the bound module
48
+ instance; uniform weights when absent. Returns just the score (no gate),
49
+ fully differentiable w.r.t. ``axes``.
50
+ """
51
+
52
+ def forward(self, axes: torch.Tensor) -> torch.Tensor:
53
+ weights = getattr(self, "weights", None)
54
+ return lambda_aggregate(axes, weights=weights)
distribution.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {"files":{"build.toml":"5c5ebbfe83770a898b8b8893e342c2c5547c65cd2b5a96146b14e3abb9411f3b","build/torch-cpu/__init__.py":"36e8a78e55913655a0834cb60fad4711a2ad5bf54e92d4473fcc36363de8a634","build/torch-cpu/metadata.json":"d15c8285af060f9c1e43ff269650508fe0f31a0297cfbd309aff552e9de8d3d4","build/torch-cpu/szl_lambda_gate/__init__.py":"4297e491a72e2941b15e2b6a0582ead273383670ac5fbb8d14e2c76dec9ed15d","build/torch-cpu/szl_lambda_gate/_lambda.py":"f953a38019c91a6fa8a9c411f55baa4f5f2b9e76d7153bba54bb8a5d9469af38","build/torch-cpu/szl_lambda_gate/_ops.py":"6adf1dc42e7a9e6da914e304da9720438e59c234104e11f3e5ccaa45ecee23b6","build/torch-cpu/szl_lambda_gate/_v1.py":"9ac2d8fe0a47ff191eba76e62b1e9dd9b2b54f64ba0c3d86306e0cdd58bc468c","build/torch-cpu/szl_lambda_gate/governed_norm/__init__.py":"50fe4fb09a165d0ae9a781f0ef3515388c752a14cde95f73687854f59a7dfadc","build/torch-cpu/szl_lambda_gate/governed_norm/_norm.py":"cf72ace281ec86c504426f75e23eebdb661a1e3a12e4dfcc6c8b9fa634b03942","build/torch-cpu/szl_lambda_gate/governed_norm/_receipt.py":"db1244bd184affdca929bd38ac728b2696f82ad565aaf82d14ca3845d4d748a9","build/torch-cpu/szl_lambda_gate/governed_norm/layers.py":"d79c83355cb2332b9d0e9d98584b86434e486532e27d30652df10158b30fc37b","build/torch-cpu/szl_lambda_gate/layers.py":"51da478e185ee4d16daa9971bdcbdcfcbb0c0c5b7837a002b97cd05cb968ea75","build/torch-universal/__init__.py":"36e8a78e55913655a0834cb60fad4711a2ad5bf54e92d4473fcc36363de8a634","build/torch-universal/metadata.json":"448ed5fb0c866455d045cdc7a75e1bbcaccc8d9f323039daf62cda1f5a35e0b4","build/torch-universal/szl_lambda_gate/__init__.py":"4297e491a72e2941b15e2b6a0582ead273383670ac5fbb8d14e2c76dec9ed15d","build/torch-universal/szl_lambda_gate/_lambda.py":"f953a38019c91a6fa8a9c411f55baa4f5f2b9e76d7153bba54bb8a5d9469af38","build/torch-universal/szl_lambda_gate/_ops.py":"6adf1dc42e7a9e6da914e304da9720438e59c234104e11f3e5ccaa45ecee23b6","build/torch-universal/szl_lambda_gate/_v1.py":"9ac2d8fe0a47ff191eba76e62b1e9dd9b2b54f64ba0c3d86306e0cdd58bc468c","build/torch-universal/szl_lambda_gate/governed_norm/__init__.py":"50fe4fb09a165d0ae9a781f0ef3515388c752a14cde95f73687854f59a7dfadc","build/torch-universal/szl_lambda_gate/governed_norm/_norm.py":"cf72ace281ec86c504426f75e23eebdb661a1e3a12e4dfcc6c8b9fa634b03942","build/torch-universal/szl_lambda_gate/governed_norm/_receipt.py":"db1244bd184affdca929bd38ac728b2696f82ad565aaf82d14ca3845d4d748a9","build/torch-universal/szl_lambda_gate/governed_norm/layers.py":"d79c83355cb2332b9d0e9d98584b86434e486532e27d30652df10158b30fc37b","build/torch-universal/szl_lambda_gate/layers.py":"51da478e185ee4d16daa9971bdcbdcfcbb0c0c5b7837a002b97cd05cb968ea75","reference/szl_lambda_v1.py":"57b264fa96056d1f2d77b797ba80eab087a729283f16416196fdd1423c9c532f","source/LICENSE":"bc8cef3450d423b046a3ba2b1a03089c8c795302f502cabbdbef055a68f0b1e7","spec/lambda_v1_vectors.json":"460bb966ff2bec4fd99e03d267b721f22c5fad731e0667723407a6909bd4dcec","spec/szl.lambda.v1.json":"04a8368568d59509c8603cdc45cf80f6b1395e751c77eabb1957bbe12906f2d9"},"packager":"scripts/build_lambda_distribution.py","schema":"szl.lambda/distribution.v1","source_commit":"7cb79cba7ecb5dbb9da59b2d6b516a98d2a114d6","source_files":{"LICENSE":"bc8cef3450d423b046a3ba2b1a03089c8c795302f502cabbdbef055a68f0b1e7","build.toml":"5c5ebbfe83770a898b8b8893e342c2c5547c65cd2b5a96146b14e3abb9411f3b","reference/szl_lambda_v1.py":"57b264fa96056d1f2d77b797ba80eab087a729283f16416196fdd1423c9c532f","spec/lambda_v1_vectors.json":"460bb966ff2bec4fd99e03d267b721f22c5fad731e0667723407a6909bd4dcec","spec/szl.lambda.v1.json":"04a8368568d59509c8603cdc45cf80f6b1395e751c77eabb1957bbe12906f2d9","torch-ext/szl_lambda_gate/__init__.py":"4297e491a72e2941b15e2b6a0582ead273383670ac5fbb8d14e2c76dec9ed15d","torch-ext/szl_lambda_gate/_lambda.py":"f953a38019c91a6fa8a9c411f55baa4f5f2b9e76d7153bba54bb8a5d9469af38","torch-ext/szl_lambda_gate/_ops.py":"6adf1dc42e7a9e6da914e304da9720438e59c234104e11f3e5ccaa45ecee23b6","torch-ext/szl_lambda_gate/_v1.py":"9ac2d8fe0a47ff191eba76e62b1e9dd9b2b54f64ba0c3d86306e0cdd58bc468c","torch-ext/szl_lambda_gate/governed_norm/__init__.py":"50fe4fb09a165d0ae9a781f0ef3515388c752a14cde95f73687854f59a7dfadc","torch-ext/szl_lambda_gate/governed_norm/_norm.py":"cf72ace281ec86c504426f75e23eebdb661a1e3a12e4dfcc6c8b9fa634b03942","torch-ext/szl_lambda_gate/governed_norm/_receipt.py":"db1244bd184affdca929bd38ac728b2696f82ad565aaf82d14ca3845d4d748a9","torch-ext/szl_lambda_gate/governed_norm/layers.py":"d79c83355cb2332b9d0e9d98584b86434e486532e27d30652df10158b30fc37b","torch-ext/szl_lambda_gate/layers.py":"51da478e185ee4d16daa9971bdcbdcfcbb0c0c5b7837a002b97cd05cb968ea75"},"source_repository":"https://github.com/szl-holdings/szl-lambda-gate","vectors_count":60,"vectors_sha256":"61bfb0410b9f0eaab0eb9f22f29cb7cb13cfde8c083fe308d895565d6ba9ebd4"}
reference/szl_lambda_v1.py ADDED
@@ -0,0 +1,205 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # SPDX-License-Identifier: Apache-2.0
2
+ # © 2026 SZL Holdings · Stephen P. Lutar · ORCID 0009-0001-0110-4173
3
+ """szl.lambda/v1 stdlib reference: Λ and its gate, exactly as spec/szl.lambda.v1.json says.
4
+
5
+ Λ_w(x) = ∏_k x_k^{w_k} = exp(fsum_k(w_k · log x_k)), Λ = 0 if some x_k == 0
6
+
7
+ Contract (every violation raises ``LambdaV1Error(code)``; nothing is clamped,
8
+ renormalised, defaulted or rounded):
9
+
10
+ * ``axes`` and ``weights`` are lists or tuples of real numbers (``bool`` is not
11
+ a number), of equal, non-zero length.
12
+ * every axis is finite and 0 <= x_k <= 1;
13
+ * every weight is finite and w_k > 0, and |fsum(w) - 1| <= 1e-12.
14
+
15
+ Checks run in phases, each over every element, so the code reported for an
16
+ input with several faults does not depend on axis order::
17
+
18
+ LAMBDA_TYPE_INVALID (container) > LAMBDA_EMPTY > LAMBDA_LENGTH_MISMATCH
19
+ > LAMBDA_TYPE_INVALID (element) > LAMBDA_NONFINITE_AXIS
20
+ > LAMBDA_AXIS_OUT_OF_RANGE > LAMBDA_NONFINITE_WEIGHT
21
+ > LAMBDA_WEIGHT_NONPOSITIVE > LAMBDA_WEIGHT_SUM
22
+
23
+ ``gate_v1(axes, weights, tau)`` takes tau as a required argument (no implicit
24
+ default; the policy value lives in frontier/model_admit_contract.v1.json) and
25
+ returns ``(verdict, code)``:
26
+
27
+ * BLOCK with the error code if tau is invalid (checked first: real, finite,
28
+ 0 < tau <= 1) or Λ raises;
29
+ * NO_GO / ZERO_VETO if some axis is 0 (log Λ = -inf; a veto, not an error);
30
+ * ABSTAIN / NUMERIC_TIE if |log Λ - log tau| <= TIE_EPS (1e-9);
31
+ * GO / None if log Λ > log tau, otherwise NO_GO / BELOW_TAU.
32
+
33
+ The compare is in log space on the unrounded value. Λ is advisory. Λ
34
+ uniqueness is Conjecture 1 (open) and nothing here depends on it.
35
+
36
+ Stdlib only. Other implementations port this file; they must agree on every
37
+ error code and verdict, and on values within each vector's ``value_tol``.
38
+ """
39
+ from __future__ import annotations
40
+
41
+ import hashlib
42
+ import json
43
+ import math
44
+ import struct
45
+ from typing import Any, Optional, Tuple
46
+
47
+ SCHEMA = "szl.lambda/v1"
48
+ WEIGHT_SUM_TOL = 1e-12
49
+ TIE_EPS = 1e-9
50
+
51
+ TYPE_INVALID = "LAMBDA_TYPE_INVALID"
52
+ EMPTY = "LAMBDA_EMPTY"
53
+ LENGTH_MISMATCH = "LAMBDA_LENGTH_MISMATCH"
54
+ NONFINITE_AXIS = "LAMBDA_NONFINITE_AXIS"
55
+ AXIS_OUT_OF_RANGE = "LAMBDA_AXIS_OUT_OF_RANGE"
56
+ NONFINITE_WEIGHT = "LAMBDA_NONFINITE_WEIGHT"
57
+ WEIGHT_NONPOSITIVE = "LAMBDA_WEIGHT_NONPOSITIVE"
58
+ WEIGHT_SUM = "LAMBDA_WEIGHT_SUM"
59
+ TAU_INVALID = "LAMBDA_TAU_INVALID"
60
+
61
+ #: Every error code, in precedence order (tau is checked first by the gate).
62
+ ERROR_CODES = (
63
+ TYPE_INVALID,
64
+ EMPTY,
65
+ LENGTH_MISMATCH,
66
+ NONFINITE_AXIS,
67
+ AXIS_OUT_OF_RANGE,
68
+ NONFINITE_WEIGHT,
69
+ WEIGHT_NONPOSITIVE,
70
+ WEIGHT_SUM,
71
+ TAU_INVALID,
72
+ )
73
+
74
+ GO = "GO"
75
+ NO_GO = "NO_GO"
76
+ ABSTAIN = "ABSTAIN"
77
+ BLOCK = "BLOCK"
78
+ VERDICTS = (GO, NO_GO, ABSTAIN, BLOCK)
79
+
80
+ ZERO_VETO = "ZERO_VETO"
81
+ BELOW_TAU = "BELOW_TAU"
82
+ NUMERIC_TIE = "NUMERIC_TIE"
83
+
84
+
85
+ class LambdaV1Error(ValueError):
86
+ """An input outside the szl.lambda/v1 contract. ``code`` is one of ERROR_CODES."""
87
+
88
+ def __init__(self, code: str, detail: str = "") -> None:
89
+ self.code = code
90
+ self.detail = detail
91
+ super().__init__(f"{code}: {detail}" if detail else code)
92
+
93
+
94
+ def _is_real(value: Any) -> bool:
95
+ return isinstance(value, (int, float)) and not isinstance(value, bool)
96
+
97
+
98
+ def _is_nonfinite(value: Any) -> bool:
99
+ # ints are always finite; only floats can be NaN or ±Inf.
100
+ return isinstance(value, float) and not math.isfinite(value)
101
+
102
+
103
+ def _validate(axes: Any, weights: Any) -> None:
104
+ for name, seq in (("axes", axes), ("weights", weights)):
105
+ if not isinstance(seq, (list, tuple)):
106
+ raise LambdaV1Error(TYPE_INVALID, f"{name} must be a list or tuple, got {type(seq).__name__}")
107
+ if len(axes) == 0 or len(weights) == 0:
108
+ raise LambdaV1Error(EMPTY, f"len(axes)={len(axes)}, len(weights)={len(weights)}")
109
+ if len(axes) != len(weights):
110
+ raise LambdaV1Error(LENGTH_MISMATCH, f"len(axes)={len(axes)} != len(weights)={len(weights)}")
111
+ for name, seq in (("axes", axes), ("weights", weights)):
112
+ for i, value in enumerate(seq):
113
+ if not _is_real(value):
114
+ raise LambdaV1Error(TYPE_INVALID, f"{name}[{i}] is {type(value).__name__}, not a real number")
115
+ for i, x in enumerate(axes):
116
+ if _is_nonfinite(x):
117
+ raise LambdaV1Error(NONFINITE_AXIS, f"axes[{i}]={x!r}")
118
+ for i, x in enumerate(axes):
119
+ if not 0 <= x <= 1:
120
+ raise LambdaV1Error(AXIS_OUT_OF_RANGE, f"axes[{i}]={x!r} is outside [0, 1]")
121
+ for i, w in enumerate(weights):
122
+ if _is_nonfinite(w):
123
+ raise LambdaV1Error(NONFINITE_WEIGHT, f"weights[{i}]={w!r}")
124
+ for i, w in enumerate(weights):
125
+ if not w > 0:
126
+ raise LambdaV1Error(WEIGHT_NONPOSITIVE, f"weights[{i}]={w!r} is not > 0")
127
+ try:
128
+ total = math.fsum(weights)
129
+ except OverflowError:
130
+ raise LambdaV1Error(WEIGHT_SUM, "sum of weights overflows a float") from None
131
+ if not abs(total - 1.0) <= WEIGHT_SUM_TOL:
132
+ raise LambdaV1Error(WEIGHT_SUM, f"fsum(weights)={total!r} is not within {WEIGHT_SUM_TOL} of 1")
133
+
134
+
135
+ def log_lambda_v1(axes: Any, weights: Any) -> float:
136
+ """log Λ_w(x) = fsum(w_k · log x_k); -inf if some axis is 0. Raises LambdaV1Error."""
137
+ _validate(axes, weights)
138
+ if any(x == 0 for x in axes):
139
+ return -math.inf
140
+ return math.fsum(float(w) * math.log(float(x)) for x, w in zip(axes, weights))
141
+
142
+
143
+ def lambda_v1(axes: Any, weights: Any) -> float:
144
+ """Λ_w(x) in [0, 1]; exactly 0.0 iff some axis is 0. Raises LambdaV1Error."""
145
+ log_lam = log_lambda_v1(axes, weights)
146
+ if log_lam == -math.inf:
147
+ return 0.0
148
+ return math.exp(log_lam)
149
+
150
+
151
+ def _check_tau(tau: Any) -> float:
152
+ if not _is_real(tau):
153
+ raise LambdaV1Error(TAU_INVALID, f"tau is {type(tau).__name__}, not a real number")
154
+ if _is_nonfinite(tau):
155
+ raise LambdaV1Error(TAU_INVALID, f"tau={tau!r} is not finite")
156
+ if not 0 < tau <= 1:
157
+ raise LambdaV1Error(TAU_INVALID, f"tau={tau!r} is outside (0, 1]")
158
+ return float(tau)
159
+
160
+
161
+ def gate_v1(axes: Any, weights: Any, tau: Any) -> Tuple[str, Optional[str]]:
162
+ """(verdict, code) for Λ_w(axes) against tau. Never raises on bad input: it BLOCKs."""
163
+ try:
164
+ t = _check_tau(tau)
165
+ log_lam = log_lambda_v1(axes, weights)
166
+ except LambdaV1Error as err:
167
+ return BLOCK, err.code
168
+ if log_lam == -math.inf:
169
+ return NO_GO, ZERO_VETO
170
+ delta = log_lam - math.log(t)
171
+ if abs(delta) <= TIE_EPS:
172
+ return ABSTAIN, NUMERIC_TIE
173
+ if delta > 0:
174
+ return GO, None
175
+ return NO_GO, BELOW_TAU
176
+
177
+
178
+ # ------------------------------------------------ canonical numbers and bytes --
179
+
180
+
181
+ def encode_f64(x: float) -> str:
182
+ """'f64:' + the 16 lowercase hex digits of the IEEE-754 binary64 bits (big-endian)."""
183
+ return "f64:" + struct.pack(">d", float(x)).hex()
184
+
185
+
186
+ def decode_f64(text: str) -> float:
187
+ """Inverse of encode_f64. Rejects anything that is not exactly 'f64:' + 16 lowercase hex."""
188
+ if not isinstance(text, str) or len(text) != 20 or not text.startswith("f64:"):
189
+ raise ValueError(f"not an f64 literal: {text!r}")
190
+ digits = text[4:]
191
+ if any(c not in "0123456789abcdef" for c in digits):
192
+ raise ValueError(f"not an f64 literal: {text!r}")
193
+ return struct.unpack(">d", bytes.fromhex(digits))[0]
194
+
195
+
196
+ def canonical_json_bytes(obj: Any) -> bytes:
197
+ """Canonical JSON: sorted keys, compact separators, UTF-8, no NaN/Infinity."""
198
+ return json.dumps(
199
+ obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False, allow_nan=False
200
+ ).encode("utf-8")
201
+
202
+
203
+ def canonical_sha256(obj: Any) -> str:
204
+ """SHA-256 hex over canonical_json_bytes(obj): stable across CRLF/LF checkouts."""
205
+ return hashlib.sha256(canonical_json_bytes(obj)).hexdigest()
source/LICENSE ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright 2026 SZL Holdings
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
spec/lambda_v1_vectors.json ADDED
@@ -0,0 +1,730 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema": "szl.lambda/v1.vectors",
3
+ "spec": "spec/szl.lambda.v1.json",
4
+ "float_encoding": "Every float is \"f64:<16 lowercase hex digits of the IEEE-754 binary64 bits, big-endian>\"; the *_decimal fields are Python repr() for humans. A JSON value that is not an f64 string (true, null, another string, an integer) is passed to the implementation unchanged.",
5
+ "expect": "value_f64 or error describes lambda_v1(axes, weights); verdict and code describe gate_v1(axes, weights, tau).",
6
+ "value_tol": "Absolute tolerance on Λ for implementations other than reference/szl_lambda_v1.py, which must match value_f64 bit for bit. Error codes and verdicts are always exact.",
7
+ "vectors": [
8
+ {
9
+ "id": "nominal",
10
+ "source": "szl-math-core.md §3 differential table (nominal)",
11
+ "axes": ["f64:3fee666666666666", "f64:3fed70a3d70a3d71", "f64:3fec28f5c28f5c29", "f64:3feccccccccccccd"],
12
+ "axes_decimal": ["0.95", "0.92", "0.88", "0.9"],
13
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
14
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
15
+ "tau": "f64:3fe999999999999a",
16
+ "tau_decimal": "0.8",
17
+ "value_tol": 1e-12,
18
+ "expect": {"value_f64": "f64:3fed3035e27f23fe", "value_decimal": "0.9121350692522581", "verdict": "GO", "code": null}
19
+ },
20
+ {
21
+ "id": "hidden_weak",
22
+ "source": "szl-math-core.md §3 differential table (hidden_weak); admit contract hidden_weak_lock gm 0.7653",
23
+ "note": "the arithmetic mean 0.8125 would pass tau 0.8; the geometric mean does not",
24
+ "axes": ["f64:3fee666666666666", "f64:3fee666666666666", "f64:3fee666666666666", "f64:3fd999999999999a"],
25
+ "axes_decimal": ["0.95", "0.95", "0.95", "0.4"],
26
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
27
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
28
+ "tau": "f64:3fe999999999999a",
29
+ "tau_decimal": "0.8",
30
+ "value_tol": 1e-12,
31
+ "expect": {"value_f64": "f64:3fe87cfdb14e60f2", "value_decimal": "0.7652576888094968", "verdict": "NO_GO", "code": "BELOW_TAU"}
32
+ },
33
+ {
34
+ "id": "hidden_weak_permuted",
35
+ "source": "szl.lambda/v1 domain: a permutation of hidden_weak gives identical bits (fsum)",
36
+ "axes": ["f64:3fd999999999999a", "f64:3fee666666666666", "f64:3fee666666666666", "f64:3fee666666666666"],
37
+ "axes_decimal": ["0.4", "0.95", "0.95", "0.95"],
38
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
39
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
40
+ "tau": "f64:3fe999999999999a",
41
+ "tau_decimal": "0.8",
42
+ "value_tol": 1e-12,
43
+ "expect": {"value_f64": "f64:3fe87cfdb14e60f2", "value_decimal": "0.7652576888094968", "verdict": "NO_GO", "code": "BELOW_TAU"}
44
+ },
45
+ {
46
+ "id": "x_gt_1",
47
+ "source": "szl-math-core.md §3 differential table (x>1 [1.5, .9])",
48
+ "note": "torch and the legacy Python source clamp to 0.948683; szl-formulas and szl-khipu return 1.1619",
49
+ "axes": ["f64:3ff8000000000000", "f64:3feccccccccccccd"],
50
+ "axes_decimal": ["1.5", "0.9"],
51
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
52
+ "weights_decimal": ["0.5", "0.5"],
53
+ "tau": "f64:3fe999999999999a",
54
+ "tau_decimal": "0.8",
55
+ "value_tol": 1e-12,
56
+ "expect": {"error": "LAMBDA_AXIS_OUT_OF_RANGE", "verdict": "BLOCK", "code": "LAMBDA_AXIS_OUT_OF_RANGE"}
57
+ },
58
+ {
59
+ "id": "nan_axis",
60
+ "source": "szl-math-core.md §3 differential table (NaN axis)",
61
+ "axes": ["f64:7ff8000000000000", "f64:3feccccccccccccd"],
62
+ "axes_decimal": ["nan", "0.9"],
63
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
64
+ "weights_decimal": ["0.5", "0.5"],
65
+ "tau": "f64:3fe999999999999a",
66
+ "tau_decimal": "0.8",
67
+ "value_tol": 1e-12,
68
+ "expect": {"error": "LAMBDA_NONFINITE_AXIS", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_AXIS"}
69
+ },
70
+ {
71
+ "id": "pos_inf_axis",
72
+ "source": "szl-math-core.md §3 differential table (+Inf axis)",
73
+ "note": "the legacy Python source treats +Inf as 1 (0.948683)",
74
+ "axes": ["f64:7ff0000000000000", "f64:3feccccccccccccd"],
75
+ "axes_decimal": ["inf", "0.9"],
76
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
77
+ "weights_decimal": ["0.5", "0.5"],
78
+ "tau": "f64:3fe999999999999a",
79
+ "tau_decimal": "0.8",
80
+ "value_tol": 1e-12,
81
+ "expect": {"error": "LAMBDA_NONFINITE_AXIS", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_AXIS"}
82
+ },
83
+ {
84
+ "id": "neg_inf_axis",
85
+ "source": "szl-math-core.md §3 differential table (-Inf axis)",
86
+ "axes": ["f64:fff0000000000000", "f64:3feccccccccccccd"],
87
+ "axes_decimal": ["-inf", "0.9"],
88
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
89
+ "weights_decimal": ["0.5", "0.5"],
90
+ "tau": "f64:3fe999999999999a",
91
+ "tau_decimal": "0.8",
92
+ "value_tol": 1e-12,
93
+ "expect": {"error": "LAMBDA_NONFINITE_AXIS", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_AXIS"}
94
+ },
95
+ {
96
+ "id": "negative_axis",
97
+ "source": "szl-math-core.md §3 differential table (negative axis)",
98
+ "axes": ["f64:bfb999999999999a", "f64:3feccccccccccccd"],
99
+ "axes_decimal": ["-0.1", "0.9"],
100
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
101
+ "weights_decimal": ["0.5", "0.5"],
102
+ "tau": "f64:3fe999999999999a",
103
+ "tau_decimal": "0.8",
104
+ "value_tol": 1e-12,
105
+ "expect": {"error": "LAMBDA_AXIS_OUT_OF_RANGE", "verdict": "BLOCK", "code": "LAMBDA_AXIS_OUT_OF_RANGE"}
106
+ },
107
+ {
108
+ "id": "zero_axis",
109
+ "source": "szl-math-core.md §3 differential table (zero axis)",
110
+ "note": "a veto, not an error: log Λ = -inf gives NO_GO",
111
+ "axes": ["f64:0000000000000000", "f64:3feccccccccccccd"],
112
+ "axes_decimal": ["0.0", "0.9"],
113
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
114
+ "weights_decimal": ["0.5", "0.5"],
115
+ "tau": "f64:3fe999999999999a",
116
+ "tau_decimal": "0.8",
117
+ "value_tol": 1e-12,
118
+ "expect": {"value_f64": "f64:0000000000000000", "value_decimal": "0.0", "verdict": "NO_GO", "code": "ZERO_VETO"}
119
+ },
120
+ {
121
+ "id": "negative_zero_axis",
122
+ "source": "szl.lambda/v1 domain: -0.0 is a zero axis",
123
+ "axes": ["f64:8000000000000000", "f64:3feccccccccccccd"],
124
+ "axes_decimal": ["-0.0", "0.9"],
125
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
126
+ "weights_decimal": ["0.5", "0.5"],
127
+ "tau": "f64:3fe999999999999a",
128
+ "tau_decimal": "0.8",
129
+ "value_tol": 1e-12,
130
+ "expect": {"value_f64": "f64:0000000000000000", "value_decimal": "0.0", "verdict": "NO_GO", "code": "ZERO_VETO"}
131
+ },
132
+ {
133
+ "id": "zero_axis_min_subnormal_tau",
134
+ "source": "szl.lambda/v1 domain: the zero-axis veto holds for every valid tau",
135
+ "axes": ["f64:0000000000000000", "f64:3ff0000000000000"],
136
+ "axes_decimal": ["0.0", "1.0"],
137
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
138
+ "weights_decimal": ["0.5", "0.5"],
139
+ "tau": "f64:0000000000000001",
140
+ "tau_decimal": "5e-324",
141
+ "value_tol": 1e-12,
142
+ "expect": {"value_f64": "f64:0000000000000000", "value_decimal": "0.0", "verdict": "NO_GO", "code": "ZERO_VETO"}
143
+ },
144
+ {
145
+ "id": "w_unnormalised_2_2",
146
+ "source": "szl-math-core.md §3 differential table (unnormalised w=[2,2] on [.81,.64])",
147
+ "note": "never renormalised (torch returns 0.72)",
148
+ "axes": ["f64:3fe9eb851eb851ec", "f64:3fe47ae147ae147b"],
149
+ "axes_decimal": ["0.81", "0.64"],
150
+ "weights": ["f64:4000000000000000", "f64:4000000000000000"],
151
+ "weights_decimal": ["2.0", "2.0"],
152
+ "tau": "f64:3fe999999999999a",
153
+ "tau_decimal": "0.8",
154
+ "value_tol": 1e-12,
155
+ "expect": {"error": "LAMBDA_WEIGHT_SUM", "verdict": "BLOCK", "code": "LAMBDA_WEIGHT_SUM"}
156
+ },
157
+ {
158
+ "id": "w_zero_weight",
159
+ "source": "szl-math-core.md §3 differential table (zero weight w=[1,0] on [.5,.9])",
160
+ "axes": ["f64:3fe0000000000000", "f64:3feccccccccccccd"],
161
+ "axes_decimal": ["0.5", "0.9"],
162
+ "weights": ["f64:3ff0000000000000", "f64:0000000000000000"],
163
+ "weights_decimal": ["1.0", "0.0"],
164
+ "tau": "f64:3fe999999999999a",
165
+ "tau_decimal": "0.8",
166
+ "value_tol": 1e-12,
167
+ "expect": {"error": "LAMBDA_WEIGHT_NONPOSITIVE", "verdict": "BLOCK", "code": "LAMBDA_WEIGHT_NONPOSITIVE"}
168
+ },
169
+ {
170
+ "id": "empty",
171
+ "source": "szl-math-core.md §3 differential table (empty)",
172
+ "note": "never 0.0",
173
+ "axes": [],
174
+ "axes_decimal": [],
175
+ "weights": [],
176
+ "weights_decimal": [],
177
+ "tau": "f64:3fe999999999999a",
178
+ "tau_decimal": "0.8",
179
+ "value_tol": 1e-12,
180
+ "expect": {"error": "LAMBDA_EMPTY", "verdict": "BLOCK", "code": "LAMBDA_EMPTY"}
181
+ },
182
+ {
183
+ "id": "empty_axes_nonempty_weights",
184
+ "source": "szl.lambda/v1 domain: empty axes",
185
+ "axes": [],
186
+ "axes_decimal": [],
187
+ "weights": ["f64:3ff0000000000000"],
188
+ "weights_decimal": ["1.0"],
189
+ "tau": "f64:3fe999999999999a",
190
+ "tau_decimal": "0.8",
191
+ "value_tol": 1e-12,
192
+ "expect": {"error": "LAMBDA_EMPTY", "verdict": "BLOCK", "code": "LAMBDA_EMPTY"}
193
+ },
194
+ {
195
+ "id": "e5_round_4dp_not_a_pass",
196
+ "source": "FUSION_BRIEF.md E5 (4-dp rounding before the compare)",
197
+ "note": "round(Λ, 4) = 0.65 would pass tau 0.65; the unrounded Λ is below it",
198
+ "axes": ["f64:3fe4cc660a201472"],
199
+ "axes_decimal": ["0.649951"],
200
+ "weights": ["f64:3ff0000000000000"],
201
+ "weights_decimal": ["1.0"],
202
+ "tau": "f64:3fe4cccccccccccd",
203
+ "tau_decimal": "0.65",
204
+ "value_tol": 1e-12,
205
+ "expect": {"value_f64": "f64:3fe4cc660a201472", "value_decimal": "0.649951", "verdict": "NO_GO", "code": "BELOW_TAU"}
206
+ },
207
+ {
208
+ "id": "e5_dropped_axis_present",
209
+ "source": "FUSION_BRIEF.md E5 (triage weights, integrity = 0.1 present)",
210
+ "note": "weights from szl-typesafe-triage src/szl_triage/data/triage_policy.v3.json",
211
+ "axes": ["f64:3feb26e978d4fdf4", "f64:3feb26e978d4fdf4", "f64:3fb999999999999a", "f64:3feb26e978d4fdf4"],
212
+ "axes_decimal": ["0.8485", "0.8485", "0.1", "0.8485"],
213
+ "weights": ["f64:3fd0000000000000", "f64:3fd999999999999a", "f64:3fc999999999999a", "f64:3fc3333333333333"],
214
+ "weights_decimal": ["0.25", "0.4", "0.2", "0.15"],
215
+ "tau": "f64:3fe999999999999a",
216
+ "tau_decimal": "0.8",
217
+ "value_tol": 1e-12,
218
+ "expect": {"value_f64": "f64:3fe1b4397d7da1fc", "value_decimal": "0.5532500697127598", "verdict": "NO_GO", "code": "BELOW_TAU"}
219
+ },
220
+ {
221
+ "id": "e5_dropped_axis_renormalised",
222
+ "source": "FUSION_BRIEF.md E5 (integrity axis dropped)",
223
+ "note": "renormalising over the present axes would give 0.8485",
224
+ "axes": ["f64:3feb26e978d4fdf4", "f64:3feb26e978d4fdf4", "f64:3feb26e978d4fdf4"],
225
+ "axes_decimal": ["0.8485", "0.8485", "0.8485"],
226
+ "weights": ["f64:3fd0000000000000", "f64:3fd999999999999a", "f64:3fc999999999999a", "f64:3fc3333333333333"],
227
+ "weights_decimal": ["0.25", "0.4", "0.2", "0.15"],
228
+ "tau": "f64:3fe999999999999a",
229
+ "tau_decimal": "0.8",
230
+ "value_tol": 1e-12,
231
+ "expect": {"error": "LAMBDA_LENGTH_MISMATCH", "verdict": "BLOCK", "code": "LAMBDA_LENGTH_MISMATCH"}
232
+ },
233
+ {
234
+ "id": "e5_negative_weight",
235
+ "source": "FUSION_BRIEF.md E5 (w = (1.5, -0.5) breaks monotonicity)",
236
+ "note": "the weights sum to 1; szl-formulas accepts them and returns 0.3727",
237
+ "axes": ["f64:3fe0000000000000", "f64:3feccccccccccccd"],
238
+ "axes_decimal": ["0.5", "0.9"],
239
+ "weights": ["f64:3ff8000000000000", "f64:bfe0000000000000"],
240
+ "weights_decimal": ["1.5", "-0.5"],
241
+ "tau": "f64:3fe999999999999a",
242
+ "tau_decimal": "0.8",
243
+ "value_tol": 1e-12,
244
+ "expect": {"error": "LAMBDA_WEIGHT_NONPOSITIVE", "verdict": "BLOCK", "code": "LAMBDA_WEIGHT_NONPOSITIVE"}
245
+ },
246
+ {
247
+ "id": "length_mismatch_extra_weight",
248
+ "source": "szl.lambda/v1 domain: more weights than axes",
249
+ "axes": ["f64:3feccccccccccccd"],
250
+ "axes_decimal": ["0.9"],
251
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
252
+ "weights_decimal": ["0.5", "0.5"],
253
+ "tau": "f64:3fe999999999999a",
254
+ "tau_decimal": "0.8",
255
+ "value_tol": 1e-12,
256
+ "expect": {"error": "LAMBDA_LENGTH_MISMATCH", "verdict": "BLOCK", "code": "LAMBDA_LENGTH_MISMATCH"}
257
+ },
258
+ {
259
+ "id": "tie_exact",
260
+ "source": "INVENTION.md §2.3 tie band (TIE_EPS = 1e-9, log space)",
261
+ "axes": ["f64:3fe999999999999a"],
262
+ "axes_decimal": ["0.8"],
263
+ "weights": ["f64:3ff0000000000000"],
264
+ "weights_decimal": ["1.0"],
265
+ "tau": "f64:3fe999999999999a",
266
+ "tau_decimal": "0.8",
267
+ "value_tol": 1e-12,
268
+ "expect": {"value_f64": "f64:3fe999999999999a", "value_decimal": "0.8", "verdict": "ABSTAIN", "code": "NUMERIC_TIE"}
269
+ },
270
+ {
271
+ "id": "tie_inside_above",
272
+ "source": "INVENTION.md §2.3 tie band (TIE_EPS = 1e-9, log space): log Λ - log tau ≈ +5e-10",
273
+ "axes": ["f64:3fe9999999d0935a"],
274
+ "axes_decimal": ["0.8000000004000001"],
275
+ "weights": ["f64:3ff0000000000000"],
276
+ "weights_decimal": ["1.0"],
277
+ "tau": "f64:3fe999999999999a",
278
+ "tau_decimal": "0.8",
279
+ "value_tol": 1e-12,
280
+ "expect": {"value_f64": "f64:3fe9999999d0935a", "value_decimal": "0.8000000004000001", "verdict": "ABSTAIN", "code": "NUMERIC_TIE"}
281
+ },
282
+ {
283
+ "id": "tie_inside_below",
284
+ "source": "INVENTION.md §2.3 tie band (TIE_EPS = 1e-9, log space): log Λ - log tau ≈ -5e-10",
285
+ "axes": ["f64:3fe9999999629fda"],
286
+ "axes_decimal": ["0.7999999996"],
287
+ "weights": ["f64:3ff0000000000000"],
288
+ "weights_decimal": ["1.0"],
289
+ "tau": "f64:3fe999999999999a",
290
+ "tau_decimal": "0.8",
291
+ "value_tol": 1e-12,
292
+ "expect": {"value_f64": "f64:3fe9999999629fda", "value_decimal": "0.7999999996", "verdict": "ABSTAIN", "code": "NUMERIC_TIE"}
293
+ },
294
+ {
295
+ "id": "tie_outside_above",
296
+ "source": "INVENTION.md §2.3 tie band (TIE_EPS = 1e-9, log space): log Λ - log tau ≈ +2e-9",
297
+ "axes": ["f64:3fe999999a758098"],
298
+ "axes_decimal": ["0.8000000016"],
299
+ "weights": ["f64:3ff0000000000000"],
300
+ "weights_decimal": ["1.0"],
301
+ "tau": "f64:3fe999999999999a",
302
+ "tau_decimal": "0.8",
303
+ "value_tol": 1e-12,
304
+ "expect": {"value_f64": "f64:3fe999999a758098", "value_decimal": "0.8000000016", "verdict": "GO", "code": null}
305
+ },
306
+ {
307
+ "id": "tie_outside_below",
308
+ "source": "INVENTION.md §2.3 tie band (TIE_EPS = 1e-9, log space): log Λ - log tau ≈ -2e-9",
309
+ "axes": ["f64:3fe9999998bdb29b"],
310
+ "axes_decimal": ["0.7999999984"],
311
+ "weights": ["f64:3ff0000000000000"],
312
+ "weights_decimal": ["1.0"],
313
+ "tau": "f64:3fe999999999999a",
314
+ "tau_decimal": "0.8",
315
+ "value_tol": 1e-12,
316
+ "expect": {"value_f64": "f64:3fe9999998bdb29b", "value_decimal": "0.7999999984", "verdict": "NO_GO", "code": "BELOW_TAU"}
317
+ },
318
+ {
319
+ "id": "tie_multi_axis_at_own_value",
320
+ "source": "INVENTION.md §2.3 tie band (TIE_EPS = 1e-9, log space): hidden_weak against tau = its own Λ",
321
+ "axes": ["f64:3fee666666666666", "f64:3fee666666666666", "f64:3fee666666666666", "f64:3fd999999999999a"],
322
+ "axes_decimal": ["0.95", "0.95", "0.95", "0.4"],
323
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
324
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
325
+ "tau": "f64:3fe87cfdb14e60f2",
326
+ "tau_decimal": "0.7652576888094968",
327
+ "value_tol": 1e-12,
328
+ "expect": {"value_f64": "f64:3fe87cfdb14e60f2", "value_decimal": "0.7652576888094968", "verdict": "ABSTAIN", "code": "NUMERIC_TIE"}
329
+ },
330
+ {
331
+ "id": "all_ones_thirds",
332
+ "source": "szl.lambda/v1 domain: weights 1/3 each (fsum within 1e-12 of 1)",
333
+ "axes": ["f64:3ff0000000000000", "f64:3ff0000000000000", "f64:3ff0000000000000"],
334
+ "axes_decimal": ["1.0", "1.0", "1.0"],
335
+ "weights": ["f64:3fd5555555555555", "f64:3fd5555555555555", "f64:3fd5555555555555"],
336
+ "weights_decimal": ["0.3333333333333333", "0.3333333333333333", "0.3333333333333333"],
337
+ "tau": "f64:3fe999999999999a",
338
+ "tau_decimal": "0.8",
339
+ "value_tol": 1e-12,
340
+ "expect": {"value_f64": "f64:3ff0000000000000", "value_decimal": "1.0", "verdict": "GO", "code": null}
341
+ },
342
+ {
343
+ "id": "int_axes_accepted",
344
+ "source": "szl.lambda/v1 type contract: integers are real numbers",
345
+ "axes": [1, 1],
346
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
347
+ "weights_decimal": ["0.5", "0.5"],
348
+ "tau": "f64:3fe999999999999a",
349
+ "tau_decimal": "0.8",
350
+ "value_tol": 1e-12,
351
+ "expect": {"value_f64": "f64:3ff0000000000000", "value_decimal": "1.0", "verdict": "GO", "code": null}
352
+ },
353
+ {
354
+ "id": "subnormal_axis",
355
+ "source": "szl.lambda/v1 domain: the smallest positive axis is not a zero axis",
356
+ "axes": ["f64:0000000000000001", "f64:3ff0000000000000"],
357
+ "axes_decimal": ["5e-324", "1.0"],
358
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
359
+ "weights_decimal": ["0.5", "0.5"],
360
+ "tau": "f64:3fe999999999999a",
361
+ "tau_decimal": "0.8",
362
+ "value_tol": 1e-12,
363
+ "expect": {"value_f64": "f64:1e60000000000064", "value_decimal": "2.222758749485127e-162", "verdict": "NO_GO", "code": "BELOW_TAU"}
364
+ },
365
+ {
366
+ "id": "weight_sum_within_tol",
367
+ "source": "szl.lambda/v1 domain: |fsum(w) - 1| = 4e-13 <= 1e-12",
368
+ "axes": ["f64:3feccccccccccccd", "f64:3fe0000000000000"],
369
+ "axes_decimal": ["0.9", "0.5"],
370
+ "weights": ["f64:3fe0000000000e13", "f64:3fe0000000000000"],
371
+ "weights_decimal": ["0.5000000000004", "0.5"],
372
+ "tau": "f64:3fe999999999999a",
373
+ "tau_decimal": "0.8",
374
+ "value_tol": 1e-12,
375
+ "expect": {"value_f64": "f64:3fe5775c544ff164", "value_decimal": "0.6708203932499086", "verdict": "NO_GO", "code": "BELOW_TAU"}
376
+ },
377
+ {
378
+ "id": "weight_sum_outside_tol",
379
+ "source": "szl.lambda/v1 domain: |fsum(w) - 1| = 3e-12 > 1e-12",
380
+ "axes": ["f64:3feccccccccccccd", "f64:3fe0000000000000"],
381
+ "axes_decimal": ["0.9", "0.5"],
382
+ "weights": ["f64:3fe000000000698e", "f64:3fe0000000000000"],
383
+ "weights_decimal": ["0.500000000003", "0.5"],
384
+ "tau": "f64:3fe999999999999a",
385
+ "tau_decimal": "0.8",
386
+ "value_tol": 1e-12,
387
+ "expect": {"error": "LAMBDA_WEIGHT_SUM", "verdict": "BLOCK", "code": "LAMBDA_WEIGHT_SUM"}
388
+ },
389
+ {
390
+ "id": "weight_nan",
391
+ "source": "szl.lambda/v1 domain: NaN weight",
392
+ "axes": ["f64:3fe0000000000000", "f64:3feccccccccccccd"],
393
+ "axes_decimal": ["0.5", "0.9"],
394
+ "weights": ["f64:7ff8000000000000", "f64:3fe0000000000000"],
395
+ "weights_decimal": ["nan", "0.5"],
396
+ "tau": "f64:3fe999999999999a",
397
+ "tau_decimal": "0.8",
398
+ "value_tol": 1e-12,
399
+ "expect": {"error": "LAMBDA_NONFINITE_WEIGHT", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_WEIGHT"}
400
+ },
401
+ {
402
+ "id": "weight_pos_inf",
403
+ "source": "szl.lambda/v1 domain: +Inf weight",
404
+ "axes": ["f64:3fe0000000000000", "f64:3feccccccccccccd"],
405
+ "axes_decimal": ["0.5", "0.9"],
406
+ "weights": ["f64:7ff0000000000000", "f64:3fe0000000000000"],
407
+ "weights_decimal": ["inf", "0.5"],
408
+ "tau": "f64:3fe999999999999a",
409
+ "tau_decimal": "0.8",
410
+ "value_tol": 1e-12,
411
+ "expect": {"error": "LAMBDA_NONFINITE_WEIGHT", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_WEIGHT"}
412
+ },
413
+ {
414
+ "id": "weight_neg_inf",
415
+ "source": "szl.lambda/v1 domain: -Inf weight",
416
+ "axes": ["f64:3fe0000000000000", "f64:3feccccccccccccd"],
417
+ "axes_decimal": ["0.5", "0.9"],
418
+ "weights": ["f64:fff0000000000000", "f64:3fe0000000000000"],
419
+ "weights_decimal": ["-inf", "0.5"],
420
+ "tau": "f64:3fe999999999999a",
421
+ "tau_decimal": "0.8",
422
+ "value_tol": 1e-12,
423
+ "expect": {"error": "LAMBDA_NONFINITE_WEIGHT", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_WEIGHT"}
424
+ },
425
+ {
426
+ "id": "precedence_nonfinite_before_range_a",
427
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant)",
428
+ "axes": ["f64:3ff8000000000000", "f64:7ff8000000000000"],
429
+ "axes_decimal": ["1.5", "nan"],
430
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
431
+ "weights_decimal": ["0.5", "0.5"],
432
+ "tau": "f64:3fe999999999999a",
433
+ "tau_decimal": "0.8",
434
+ "value_tol": 1e-12,
435
+ "expect": {"error": "LAMBDA_NONFINITE_AXIS", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_AXIS"}
436
+ },
437
+ {
438
+ "id": "precedence_nonfinite_before_range_b",
439
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant)",
440
+ "axes": ["f64:7ff8000000000000", "f64:3ff8000000000000"],
441
+ "axes_decimal": ["nan", "1.5"],
442
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
443
+ "weights_decimal": ["0.5", "0.5"],
444
+ "tau": "f64:3fe999999999999a",
445
+ "tau_decimal": "0.8",
446
+ "value_tol": 1e-12,
447
+ "expect": {"error": "LAMBDA_NONFINITE_AXIS", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_AXIS"}
448
+ },
449
+ {
450
+ "id": "precedence_axis_before_weight",
451
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant)",
452
+ "axes": ["f64:3ff8000000000000", "f64:3feccccccccccccd"],
453
+ "axes_decimal": ["1.5", "0.9"],
454
+ "weights": ["f64:4000000000000000", "f64:4000000000000000"],
455
+ "weights_decimal": ["2.0", "2.0"],
456
+ "tau": "f64:3fe999999999999a",
457
+ "tau_decimal": "0.8",
458
+ "value_tol": 1e-12,
459
+ "expect": {"error": "LAMBDA_AXIS_OUT_OF_RANGE", "verdict": "BLOCK", "code": "LAMBDA_AXIS_OUT_OF_RANGE"}
460
+ },
461
+ {
462
+ "id": "precedence_zero_does_not_mask_nan_a",
463
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
464
+ "axes": ["f64:0000000000000000", "f64:7ff8000000000000"],
465
+ "axes_decimal": ["0.0", "nan"],
466
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
467
+ "weights_decimal": ["0.5", "0.5"],
468
+ "tau": "f64:3fe0000000000000",
469
+ "tau_decimal": "0.5",
470
+ "value_tol": 1e-12,
471
+ "expect": {"error": "LAMBDA_NONFINITE_AXIS", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_AXIS"}
472
+ },
473
+ {
474
+ "id": "precedence_zero_does_not_mask_nan_b",
475
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
476
+ "axes": ["f64:7ff8000000000000", "f64:0000000000000000"],
477
+ "axes_decimal": ["nan", "0.0"],
478
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
479
+ "weights_decimal": ["0.5", "0.5"],
480
+ "tau": "f64:3fe0000000000000",
481
+ "tau_decimal": "0.5",
482
+ "value_tol": 1e-12,
483
+ "expect": {"error": "LAMBDA_NONFINITE_AXIS", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_AXIS"}
484
+ },
485
+ {
486
+ "id": "precedence_zero_does_not_mask_pos_inf_a",
487
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
488
+ "axes": ["f64:0000000000000000", "f64:7ff0000000000000"],
489
+ "axes_decimal": ["0.0", "inf"],
490
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
491
+ "weights_decimal": ["0.5", "0.5"],
492
+ "tau": "f64:3fe0000000000000",
493
+ "tau_decimal": "0.5",
494
+ "value_tol": 1e-12,
495
+ "expect": {"error": "LAMBDA_NONFINITE_AXIS", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_AXIS"}
496
+ },
497
+ {
498
+ "id": "precedence_zero_does_not_mask_pos_inf_b",
499
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
500
+ "axes": ["f64:7ff0000000000000", "f64:0000000000000000"],
501
+ "axes_decimal": ["inf", "0.0"],
502
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
503
+ "weights_decimal": ["0.5", "0.5"],
504
+ "tau": "f64:3fe0000000000000",
505
+ "tau_decimal": "0.5",
506
+ "value_tol": 1e-12,
507
+ "expect": {"error": "LAMBDA_NONFINITE_AXIS", "verdict": "BLOCK", "code": "LAMBDA_NONFINITE_AXIS"}
508
+ },
509
+ {
510
+ "id": "precedence_zero_does_not_mask_x_gt_1_a",
511
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
512
+ "axes": ["f64:0000000000000000", "f64:3ff8000000000000"],
513
+ "axes_decimal": ["0.0", "1.5"],
514
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
515
+ "weights_decimal": ["0.5", "0.5"],
516
+ "tau": "f64:3fe0000000000000",
517
+ "tau_decimal": "0.5",
518
+ "value_tol": 1e-12,
519
+ "expect": {"error": "LAMBDA_AXIS_OUT_OF_RANGE", "verdict": "BLOCK", "code": "LAMBDA_AXIS_OUT_OF_RANGE"}
520
+ },
521
+ {
522
+ "id": "precedence_zero_does_not_mask_x_gt_1_b",
523
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
524
+ "axes": ["f64:3ff8000000000000", "f64:0000000000000000"],
525
+ "axes_decimal": ["1.5", "0.0"],
526
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
527
+ "weights_decimal": ["0.5", "0.5"],
528
+ "tau": "f64:3fe0000000000000",
529
+ "tau_decimal": "0.5",
530
+ "value_tol": 1e-12,
531
+ "expect": {"error": "LAMBDA_AXIS_OUT_OF_RANGE", "verdict": "BLOCK", "code": "LAMBDA_AXIS_OUT_OF_RANGE"}
532
+ },
533
+ {
534
+ "id": "precedence_zero_does_not_mask_negative_a",
535
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
536
+ "axes": ["f64:0000000000000000", "f64:bfb999999999999a"],
537
+ "axes_decimal": ["0.0", "-0.1"],
538
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
539
+ "weights_decimal": ["0.5", "0.5"],
540
+ "tau": "f64:3fe0000000000000",
541
+ "tau_decimal": "0.5",
542
+ "value_tol": 1e-12,
543
+ "expect": {"error": "LAMBDA_AXIS_OUT_OF_RANGE", "verdict": "BLOCK", "code": "LAMBDA_AXIS_OUT_OF_RANGE"}
544
+ },
545
+ {
546
+ "id": "precedence_zero_does_not_mask_negative_b",
547
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
548
+ "axes": ["f64:bfb999999999999a", "f64:0000000000000000"],
549
+ "axes_decimal": ["-0.1", "0.0"],
550
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
551
+ "weights_decimal": ["0.5", "0.5"],
552
+ "tau": "f64:3fe0000000000000",
553
+ "tau_decimal": "0.5",
554
+ "value_tol": 1e-12,
555
+ "expect": {"error": "LAMBDA_AXIS_OUT_OF_RANGE", "verdict": "BLOCK", "code": "LAMBDA_AXIS_OUT_OF_RANGE"}
556
+ },
557
+ {
558
+ "id": "precedence_zero_does_not_mask_bool_a",
559
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
560
+ "axes": ["f64:0000000000000000", true],
561
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
562
+ "weights_decimal": ["0.5", "0.5"],
563
+ "tau": "f64:3fe0000000000000",
564
+ "tau_decimal": "0.5",
565
+ "value_tol": 1e-12,
566
+ "expect": {"error": "LAMBDA_TYPE_INVALID", "verdict": "BLOCK", "code": "LAMBDA_TYPE_INVALID"}
567
+ },
568
+ {
569
+ "id": "precedence_zero_does_not_mask_bool_b",
570
+ "source": "szl.lambda/v1 error precedence (phases, permutation-invariant): every axis is validated before the zero veto (szl-receipt#38, FF-03b)",
571
+ "axes": [true, "f64:0000000000000000"],
572
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
573
+ "weights_decimal": ["0.5", "0.5"],
574
+ "tau": "f64:3fe0000000000000",
575
+ "tau_decimal": "0.5",
576
+ "value_tol": 1e-12,
577
+ "expect": {"error": "LAMBDA_TYPE_INVALID", "verdict": "BLOCK", "code": "LAMBDA_TYPE_INVALID"}
578
+ },
579
+ {
580
+ "id": "type_bool_axis",
581
+ "source": "szl.lambda/v1 type contract: bool is not a number",
582
+ "axes": [true, "f64:3feccccccccccccd"],
583
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
584
+ "weights_decimal": ["0.5", "0.5"],
585
+ "tau": "f64:3fe999999999999a",
586
+ "tau_decimal": "0.8",
587
+ "value_tol": 1e-12,
588
+ "expect": {"error": "LAMBDA_TYPE_INVALID", "verdict": "BLOCK", "code": "LAMBDA_TYPE_INVALID"}
589
+ },
590
+ {
591
+ "id": "type_null_axis",
592
+ "source": "szl.lambda/v1 type contract: null axis",
593
+ "axes": [null, "f64:3feccccccccccccd"],
594
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
595
+ "weights_decimal": ["0.5", "0.5"],
596
+ "tau": "f64:3fe999999999999a",
597
+ "tau_decimal": "0.8",
598
+ "value_tol": 1e-12,
599
+ "expect": {"error": "LAMBDA_TYPE_INVALID", "verdict": "BLOCK", "code": "LAMBDA_TYPE_INVALID"}
600
+ },
601
+ {
602
+ "id": "type_string_axis",
603
+ "source": "szl.lambda/v1 type contract: a string is not a number",
604
+ "axes": ["0.9", "f64:3feccccccccccccd"],
605
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
606
+ "weights_decimal": ["0.5", "0.5"],
607
+ "tau": "f64:3fe999999999999a",
608
+ "tau_decimal": "0.8",
609
+ "value_tol": 1e-12,
610
+ "expect": {"error": "LAMBDA_TYPE_INVALID", "verdict": "BLOCK", "code": "LAMBDA_TYPE_INVALID"}
611
+ },
612
+ {
613
+ "id": "type_axes_not_array",
614
+ "source": "szl.lambda/v1 type contract: axes must be an array",
615
+ "axes": null,
616
+ "weights": ["f64:3ff0000000000000"],
617
+ "weights_decimal": ["1.0"],
618
+ "tau": "f64:3fe999999999999a",
619
+ "tau_decimal": "0.8",
620
+ "value_tol": 1e-12,
621
+ "expect": {"error": "LAMBDA_TYPE_INVALID", "verdict": "BLOCK", "code": "LAMBDA_TYPE_INVALID"}
622
+ },
623
+ {
624
+ "id": "type_bool_weight",
625
+ "source": "szl.lambda/v1 type contract: bool weight",
626
+ "note": "the element type is checked before the weight value",
627
+ "axes": ["f64:3fe0000000000000", "f64:3feccccccccccccd"],
628
+ "axes_decimal": ["0.5", "0.9"],
629
+ "weights": [true, "f64:0000000000000000"],
630
+ "tau": "f64:3fe999999999999a",
631
+ "tau_decimal": "0.8",
632
+ "value_tol": 1e-12,
633
+ "expect": {"error": "LAMBDA_TYPE_INVALID", "verdict": "BLOCK", "code": "LAMBDA_TYPE_INVALID"}
634
+ },
635
+ {
636
+ "id": "tau_one",
637
+ "source": "szl.lambda/v1 tau domain (0, 1], required, checked first",
638
+ "axes": ["f64:3fee666666666666", "f64:3fed70a3d70a3d71", "f64:3fec28f5c28f5c29", "f64:3feccccccccccccd"],
639
+ "axes_decimal": ["0.95", "0.92", "0.88", "0.9"],
640
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
641
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
642
+ "tau": "f64:3ff0000000000000",
643
+ "tau_decimal": "1.0",
644
+ "value_tol": 1e-12,
645
+ "expect": {"value_f64": "f64:3fed3035e27f23fe", "value_decimal": "0.9121350692522581", "verdict": "NO_GO", "code": "BELOW_TAU"}
646
+ },
647
+ {
648
+ "id": "tau_nan",
649
+ "source": "szl.lambda/v1 tau domain (0, 1], required, checked first",
650
+ "axes": ["f64:3fee666666666666", "f64:3fed70a3d70a3d71", "f64:3fec28f5c28f5c29", "f64:3feccccccccccccd"],
651
+ "axes_decimal": ["0.95", "0.92", "0.88", "0.9"],
652
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
653
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
654
+ "tau": "f64:7ff8000000000000",
655
+ "tau_decimal": "nan",
656
+ "value_tol": 1e-12,
657
+ "expect": {"value_f64": "f64:3fed3035e27f23fe", "value_decimal": "0.9121350692522581", "verdict": "BLOCK", "code": "LAMBDA_TAU_INVALID"}
658
+ },
659
+ {
660
+ "id": "tau_zero_would_admit_veto",
661
+ "source": "szl.lambda/v1 tau domain (0, 1], required, checked first: tau 0 would pass a vetoed Λ = 0",
662
+ "axes": ["f64:0000000000000000", "f64:3feccccccccccccd"],
663
+ "axes_decimal": ["0.0", "0.9"],
664
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
665
+ "weights_decimal": ["0.5", "0.5"],
666
+ "tau": "f64:0000000000000000",
667
+ "tau_decimal": "0.0",
668
+ "value_tol": 1e-12,
669
+ "expect": {"value_f64": "f64:0000000000000000", "value_decimal": "0.0", "verdict": "BLOCK", "code": "LAMBDA_TAU_INVALID"}
670
+ },
671
+ {
672
+ "id": "tau_above_one",
673
+ "source": "szl.lambda/v1 tau domain (0, 1], required, checked first",
674
+ "axes": ["f64:3fee666666666666", "f64:3fed70a3d70a3d71", "f64:3fec28f5c28f5c29", "f64:3feccccccccccccd"],
675
+ "axes_decimal": ["0.95", "0.92", "0.88", "0.9"],
676
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
677
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
678
+ "tau": "f64:3ff8000000000000",
679
+ "tau_decimal": "1.5",
680
+ "value_tol": 1e-12,
681
+ "expect": {"value_f64": "f64:3fed3035e27f23fe", "value_decimal": "0.9121350692522581", "verdict": "BLOCK", "code": "LAMBDA_TAU_INVALID"}
682
+ },
683
+ {
684
+ "id": "tau_negative",
685
+ "source": "szl.lambda/v1 tau domain (0, 1], required, checked first",
686
+ "axes": ["f64:3fee666666666666", "f64:3fed70a3d70a3d71", "f64:3fec28f5c28f5c29", "f64:3feccccccccccccd"],
687
+ "axes_decimal": ["0.95", "0.92", "0.88", "0.9"],
688
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
689
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
690
+ "tau": "f64:bfb999999999999a",
691
+ "tau_decimal": "-0.1",
692
+ "value_tol": 1e-12,
693
+ "expect": {"value_f64": "f64:3fed3035e27f23fe", "value_decimal": "0.9121350692522581", "verdict": "BLOCK", "code": "LAMBDA_TAU_INVALID"}
694
+ },
695
+ {
696
+ "id": "tau_bool",
697
+ "source": "szl.lambda/v1 tau domain (0, 1], required, checked first: bool is not a number",
698
+ "axes": ["f64:3fee666666666666", "f64:3fed70a3d70a3d71", "f64:3fec28f5c28f5c29", "f64:3feccccccccccccd"],
699
+ "axes_decimal": ["0.95", "0.92", "0.88", "0.9"],
700
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
701
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
702
+ "tau": true,
703
+ "value_tol": 1e-12,
704
+ "expect": {"value_f64": "f64:3fed3035e27f23fe", "value_decimal": "0.9121350692522581", "verdict": "BLOCK", "code": "LAMBDA_TAU_INVALID"}
705
+ },
706
+ {
707
+ "id": "tau_null",
708
+ "source": "szl.lambda/v1 tau domain (0, 1], required, checked first: tau is required",
709
+ "axes": ["f64:3fee666666666666", "f64:3fed70a3d70a3d71", "f64:3fec28f5c28f5c29", "f64:3feccccccccccccd"],
710
+ "axes_decimal": ["0.95", "0.92", "0.88", "0.9"],
711
+ "weights": ["f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000", "f64:3fd0000000000000"],
712
+ "weights_decimal": ["0.25", "0.25", "0.25", "0.25"],
713
+ "tau": null,
714
+ "value_tol": 1e-12,
715
+ "expect": {"value_f64": "f64:3fed3035e27f23fe", "value_decimal": "0.9121350692522581", "verdict": "BLOCK", "code": "LAMBDA_TAU_INVALID"}
716
+ },
717
+ {
718
+ "id": "tau_precedes_axis_error",
719
+ "source": "szl.lambda/v1 tau domain (0, 1], required, checked first: tau is checked before Λ",
720
+ "axes": ["f64:3ff8000000000000", "f64:3feccccccccccccd"],
721
+ "axes_decimal": ["1.5", "0.9"],
722
+ "weights": ["f64:3fe0000000000000", "f64:3fe0000000000000"],
723
+ "weights_decimal": ["0.5", "0.5"],
724
+ "tau": "f64:7ff8000000000000",
725
+ "tau_decimal": "nan",
726
+ "value_tol": 1e-12,
727
+ "expect": {"error": "LAMBDA_AXIS_OUT_OF_RANGE", "verdict": "BLOCK", "code": "LAMBDA_TAU_INVALID"}
728
+ }
729
+ ]
730
+ }
spec/szl.lambda.v1.json ADDED
@@ -0,0 +1,133 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema": "szl.lambda/v1",
3
+ "title": "Λ, the weighted geometric mean, as a validated contract",
4
+ "status": "ADVISORY",
5
+ "uniqueness": "CONJECTURE_1_NOT_USED",
6
+ "honesty": "Λ is an advisory, non-compensatory roll-up. Λ uniqueness is Conjecture 1 (open); nothing in this contract depends on it.",
7
+ "form": "weighted_geometric_mean",
8
+ "definition": "Λ_w(x) = ∏_k x_k^{w_k}",
9
+ "algorithm": {
10
+ "log_lambda": "-inf if some x_k == 0, else math.fsum(w_k * math.log(x_k))",
11
+ "lambda": "0.0 if log_lambda == -inf, else math.exp(log_lambda)",
12
+ "weight_sum": "math.fsum(weights)",
13
+ "why_fsum": "fsum is correctly rounded, so Λ is bitwise invariant under a permutation of (axes, weights)"
14
+ },
15
+ "domain": {
16
+ "axes": "list or tuple of real numbers (bool is not a number); every x_k finite and 0 <= x_k <= 1",
17
+ "weights": "list or tuple of real numbers, the same length as axes; every w_k finite and w_k > 0; |fsum(weights) - 1| <= weight_sum_tol",
18
+ "empty": "error LAMBDA_EMPTY, never 0.0",
19
+ "renormalisation": "never: weights are used as declared",
20
+ "clamping": "never: a non-finite or out-of-range value is an error",
21
+ "rounding": "never before the compare",
22
+ "output": "Λ in [0, 1]; exactly 0.0 iff some x_k == 0 (a veto, not an error)"
23
+ },
24
+ "weight_sum_tol": 1e-12,
25
+ "error_codes": [
26
+ {
27
+ "code": "LAMBDA_TYPE_INVALID",
28
+ "when": "axes or weights is not a list/tuple (checked first), or an element is not a real number (checked after LAMBDA_LENGTH_MISMATCH)"
29
+ },
30
+ {
31
+ "code": "LAMBDA_EMPTY",
32
+ "when": "axes or weights is empty"
33
+ },
34
+ {
35
+ "code": "LAMBDA_LENGTH_MISMATCH",
36
+ "when": "len(axes) != len(weights); a dropped axis is never renormalised away"
37
+ },
38
+ {
39
+ "code": "LAMBDA_NONFINITE_AXIS",
40
+ "when": "some x_k is NaN, +Inf or -Inf"
41
+ },
42
+ {
43
+ "code": "LAMBDA_AXIS_OUT_OF_RANGE",
44
+ "when": "some x_k < 0 or x_k > 1"
45
+ },
46
+ {
47
+ "code": "LAMBDA_NONFINITE_WEIGHT",
48
+ "when": "some w_k is NaN, +Inf or -Inf"
49
+ },
50
+ {
51
+ "code": "LAMBDA_WEIGHT_NONPOSITIVE",
52
+ "when": "some w_k <= 0"
53
+ },
54
+ {
55
+ "code": "LAMBDA_WEIGHT_SUM",
56
+ "when": "|fsum(weights) - 1| > weight_sum_tol, or the sum overflows"
57
+ },
58
+ {
59
+ "code": "LAMBDA_TAU_INVALID",
60
+ "when": "gate only: tau is not a real number, not finite, or outside (0, 1]; checked before Λ"
61
+ }
62
+ ],
63
+ "precedence": "Checks run in the order of error_codes, each over every element, so the reported code does not depend on axis order. The gate checks tau first.",
64
+ "gate": {
65
+ "signature": "gate_v1(axes, weights, tau) -> (verdict, code)",
66
+ "verdicts": [
67
+ "GO",
68
+ "NO_GO",
69
+ "ABSTAIN",
70
+ "BLOCK"
71
+ ],
72
+ "tau": {
73
+ "required": true,
74
+ "implicit_default": null,
75
+ "domain": "real, finite, 0 < tau <= 1 (tau = 0 would pass a vetoed Λ = 0)",
76
+ "error": "LAMBDA_TAU_INVALID",
77
+ "default_source": "frontier/model_admit_contract.v1.json#/policy_tau",
78
+ "policy_tau_at_authoring": 0.8
79
+ },
80
+ "compare": "log space on the unrounded value: delta = log_lambda - log(tau)",
81
+ "tie_eps": 1e-09,
82
+ "rules": [
83
+ {
84
+ "if": "tau invalid, or Λ raises",
85
+ "verdict": "BLOCK",
86
+ "code": "the error code"
87
+ },
88
+ {
89
+ "if": "log_lambda == -inf (some axis is 0)",
90
+ "verdict": "NO_GO",
91
+ "code": "ZERO_VETO"
92
+ },
93
+ {
94
+ "if": "abs(delta) <= tie_eps",
95
+ "verdict": "ABSTAIN",
96
+ "code": "NUMERIC_TIE"
97
+ },
98
+ {
99
+ "if": "delta > 0",
100
+ "verdict": "GO",
101
+ "code": null
102
+ },
103
+ {
104
+ "if": "otherwise",
105
+ "verdict": "NO_GO",
106
+ "code": "BELOW_TAU"
107
+ }
108
+ ]
109
+ },
110
+ "canonical_float": "f64:<16 lowercase hex digits of the IEEE-754 binary64 bits, big-endian>",
111
+ "vectors": {
112
+ "path": "spec/lambda_v1_vectors.json",
113
+ "count": 60,
114
+ "sha256": "61bfb0410b9f0eaab0eb9f22f29cb7cb13cfde8c083fe308d895565d6ba9ebd4",
115
+ "digest": {
116
+ "algorithm": "sha256",
117
+ "over": "canonical_json",
118
+ "sort_keys": true,
119
+ "separators": [
120
+ ",",
121
+ ":"
122
+ ],
123
+ "ensure_ascii": false,
124
+ "allow_nan": false,
125
+ "encoding": "utf-8"
126
+ }
127
+ },
128
+ "reference": "reference/szl_lambda_v1.py",
129
+ "legacy_not_canonical": [
130
+ "tests/lambda_aggregator_source.py: +Inf counts as 1, NaN leaks, empty gives 0.0, weights are renormalised",
131
+ "torch-ext/szl_lambda_gate/_lambda.py lambda_aggregate: clamps, routes NaN/Inf to 0, renormalises; pinned in tests/test_lambda_v1_torch_divergence.py"
132
+ ]
133
+ }