invarlock 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- invarlock/__init__.py +33 -0
- invarlock/__main__.py +10 -0
- invarlock/_data/runtime/profiles/ci_cpu.yaml +15 -0
- invarlock/_data/runtime/profiles/release.yaml +23 -0
- invarlock/_data/runtime/tiers.yaml +76 -0
- invarlock/adapters/__init__.py +102 -0
- invarlock/adapters/_capabilities.py +45 -0
- invarlock/adapters/auto.py +99 -0
- invarlock/adapters/base.py +530 -0
- invarlock/adapters/base_types.py +85 -0
- invarlock/adapters/hf_bert.py +852 -0
- invarlock/adapters/hf_gpt2.py +403 -0
- invarlock/adapters/hf_llama.py +485 -0
- invarlock/adapters/hf_mixin.py +383 -0
- invarlock/adapters/hf_onnx.py +112 -0
- invarlock/adapters/hf_t5.py +137 -0
- invarlock/adapters/py.typed +1 -0
- invarlock/assurance/__init__.py +43 -0
- invarlock/cli/__init__.py +8 -0
- invarlock/cli/__main__.py +8 -0
- invarlock/cli/_evidence.py +25 -0
- invarlock/cli/_json.py +75 -0
- invarlock/cli/adapter_auto.py +162 -0
- invarlock/cli/app.py +287 -0
- invarlock/cli/commands/__init__.py +26 -0
- invarlock/cli/commands/certify.py +403 -0
- invarlock/cli/commands/doctor.py +1358 -0
- invarlock/cli/commands/explain_gates.py +151 -0
- invarlock/cli/commands/export_html.py +100 -0
- invarlock/cli/commands/plugins.py +1331 -0
- invarlock/cli/commands/report.py +354 -0
- invarlock/cli/commands/run.py +4146 -0
- invarlock/cli/commands/verify.py +1040 -0
- invarlock/cli/config.py +396 -0
- invarlock/cli/constants.py +68 -0
- invarlock/cli/device.py +92 -0
- invarlock/cli/doctor_helpers.py +74 -0
- invarlock/cli/errors.py +6 -0
- invarlock/cli/overhead_utils.py +60 -0
- invarlock/cli/provenance.py +66 -0
- invarlock/cli/utils.py +41 -0
- invarlock/config.py +56 -0
- invarlock/core/__init__.py +62 -0
- invarlock/core/abi.py +15 -0
- invarlock/core/api.py +274 -0
- invarlock/core/auto_tuning.py +317 -0
- invarlock/core/bootstrap.py +226 -0
- invarlock/core/checkpoint.py +221 -0
- invarlock/core/contracts.py +73 -0
- invarlock/core/error_utils.py +64 -0
- invarlock/core/events.py +298 -0
- invarlock/core/exceptions.py +95 -0
- invarlock/core/registry.py +481 -0
- invarlock/core/retry.py +146 -0
- invarlock/core/runner.py +2041 -0
- invarlock/core/types.py +154 -0
- invarlock/edits/__init__.py +12 -0
- invarlock/edits/_edit_utils.py +249 -0
- invarlock/edits/_external_utils.py +268 -0
- invarlock/edits/noop.py +47 -0
- invarlock/edits/py.typed +1 -0
- invarlock/edits/quant_rtn.py +801 -0
- invarlock/edits/registry.py +166 -0
- invarlock/eval/__init__.py +23 -0
- invarlock/eval/bench.py +1207 -0
- invarlock/eval/bootstrap.py +50 -0
- invarlock/eval/data.py +2052 -0
- invarlock/eval/metrics.py +2167 -0
- invarlock/eval/primary_metric.py +767 -0
- invarlock/eval/probes/__init__.py +24 -0
- invarlock/eval/probes/fft.py +139 -0
- invarlock/eval/probes/mi.py +213 -0
- invarlock/eval/probes/post_attention.py +323 -0
- invarlock/eval/providers/base.py +67 -0
- invarlock/eval/providers/seq2seq.py +111 -0
- invarlock/eval/providers/text_lm.py +113 -0
- invarlock/eval/providers/vision_text.py +93 -0
- invarlock/eval/py.typed +1 -0
- invarlock/guards/__init__.py +18 -0
- invarlock/guards/_contracts.py +9 -0
- invarlock/guards/invariants.py +640 -0
- invarlock/guards/policies.py +805 -0
- invarlock/guards/py.typed +1 -0
- invarlock/guards/rmt.py +2097 -0
- invarlock/guards/spectral.py +1419 -0
- invarlock/guards/tier_config.py +354 -0
- invarlock/guards/variance.py +3298 -0
- invarlock/guards_ref/__init__.py +15 -0
- invarlock/guards_ref/rmt_ref.py +40 -0
- invarlock/guards_ref/spectral_ref.py +135 -0
- invarlock/guards_ref/variance_ref.py +60 -0
- invarlock/model_profile.py +353 -0
- invarlock/model_utils.py +221 -0
- invarlock/observability/__init__.py +10 -0
- invarlock/observability/alerting.py +535 -0
- invarlock/observability/core.py +546 -0
- invarlock/observability/exporters.py +565 -0
- invarlock/observability/health.py +588 -0
- invarlock/observability/metrics.py +457 -0
- invarlock/observability/py.typed +1 -0
- invarlock/observability/utils.py +553 -0
- invarlock/plugins/__init__.py +12 -0
- invarlock/plugins/hello_guard.py +33 -0
- invarlock/plugins/hf_awq_adapter.py +82 -0
- invarlock/plugins/hf_bnb_adapter.py +79 -0
- invarlock/plugins/hf_gptq_adapter.py +78 -0
- invarlock/plugins/py.typed +1 -0
- invarlock/py.typed +1 -0
- invarlock/reporting/__init__.py +7 -0
- invarlock/reporting/certificate.py +3221 -0
- invarlock/reporting/certificate_schema.py +244 -0
- invarlock/reporting/dataset_hashing.py +215 -0
- invarlock/reporting/guards_analysis.py +948 -0
- invarlock/reporting/html.py +32 -0
- invarlock/reporting/normalizer.py +235 -0
- invarlock/reporting/policy_utils.py +517 -0
- invarlock/reporting/primary_metric_utils.py +265 -0
- invarlock/reporting/render.py +1442 -0
- invarlock/reporting/report.py +903 -0
- invarlock/reporting/report_types.py +278 -0
- invarlock/reporting/utils.py +175 -0
- invarlock/reporting/validate.py +631 -0
- invarlock/security.py +176 -0
- invarlock/sparsity_utils.py +323 -0
- invarlock/utils/__init__.py +150 -0
- invarlock/utils/digest.py +45 -0
- invarlock-0.2.0.dist-info/METADATA +586 -0
- invarlock-0.2.0.dist-info/RECORD +132 -0
- invarlock-0.2.0.dist-info/WHEEL +5 -0
- invarlock-0.2.0.dist-info/entry_points.txt +20 -0
- invarlock-0.2.0.dist-info/licenses/LICENSE +201 -0
- invarlock-0.2.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Minimal HTML exporter for certificates.
|
|
3
|
+
|
|
4
|
+
This implementation wraps the Markdown rendering in a simple HTML template so
|
|
5
|
+
that the numbers and core content remain identical across formats.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from html import escape
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from .render import render_certificate_markdown
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def render_certificate_html(certificate: dict[str, Any]) -> str:
|
|
17
|
+
"""Render a certificate as a simple HTML document.
|
|
18
|
+
|
|
19
|
+
Uses the Markdown renderer and embeds the content in a <pre> block to ensure
|
|
20
|
+
stable parity for snapshot tests without extra dependencies.
|
|
21
|
+
"""
|
|
22
|
+
md = render_certificate_markdown(certificate)
|
|
23
|
+
body = f'<pre class="invarlock-md">{escape(md)}</pre>'
|
|
24
|
+
return (
|
|
25
|
+
'<!DOCTYPE html><html><head><meta charset="utf-8">'
|
|
26
|
+
"<title>InvarLock Safety Certificate</title>"
|
|
27
|
+
"<style>body{font-family:ui-monospace,Menlo,monospace;white-space:pre-wrap}</style>"
|
|
28
|
+
"</head><body>" + body + "</body></html>"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
__all__ = ["render_certificate_html"]
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Any, cast
|
|
6
|
+
|
|
7
|
+
from .report_types import (
|
|
8
|
+
Artifacts,
|
|
9
|
+
DataConfig,
|
|
10
|
+
EditDeltas,
|
|
11
|
+
EditInfo,
|
|
12
|
+
EvalMetrics,
|
|
13
|
+
Flags,
|
|
14
|
+
GuardReport,
|
|
15
|
+
MetaData,
|
|
16
|
+
RunReport,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _str(x: Any, default: str = "") -> str:
|
|
21
|
+
try:
|
|
22
|
+
s = str(x)
|
|
23
|
+
return s if s is not None else default
|
|
24
|
+
except Exception:
|
|
25
|
+
return default
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _as_mapping(x: Any) -> Mapping[str, Any]:
|
|
29
|
+
return x if isinstance(x, Mapping) else {}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def normalize_run_report(report: Mapping[str, Any] | RunReport) -> RunReport:
|
|
33
|
+
"""Coerce an arbitrary report-like mapping into a canonical RunReport.
|
|
34
|
+
|
|
35
|
+
This is the single entry point for converting pre-canonical or loosely-typed
|
|
36
|
+
data into the strict PM-only RunReport shape used by certificate/report.
|
|
37
|
+
"""
|
|
38
|
+
src = _as_mapping(report)
|
|
39
|
+
|
|
40
|
+
# ---- meta ----
|
|
41
|
+
meta_in = _as_mapping(src.get("meta"))
|
|
42
|
+
ts = _str(meta_in.get("ts") or datetime.now().isoformat())
|
|
43
|
+
meta_dict: dict[str, Any] = {
|
|
44
|
+
"model_id": _str(meta_in.get("model_id")),
|
|
45
|
+
"adapter": _str(meta_in.get("adapter")),
|
|
46
|
+
"commit": _str(meta_in.get("commit")),
|
|
47
|
+
"seed": int(meta_in.get("seed", 42) or 42),
|
|
48
|
+
"device": _str(meta_in.get("device", "cpu")),
|
|
49
|
+
"ts": ts,
|
|
50
|
+
"auto": meta_in.get("auto") if isinstance(meta_in.get("auto"), dict) else None,
|
|
51
|
+
}
|
|
52
|
+
meta = cast(MetaData, meta_dict)
|
|
53
|
+
|
|
54
|
+
# ---- data ----
|
|
55
|
+
data_in = _as_mapping(src.get("data"))
|
|
56
|
+
data_dict: dict[str, Any] = {
|
|
57
|
+
"dataset": _str(data_in.get("dataset")),
|
|
58
|
+
"split": _str(data_in.get("split", "validation")),
|
|
59
|
+
"seq_len": int(data_in.get("seq_len", 0) or 0),
|
|
60
|
+
"stride": int(data_in.get("stride", 0) or 0),
|
|
61
|
+
"preview_n": int(data_in.get("preview_n", 0) or 0),
|
|
62
|
+
"final_n": int(data_in.get("final_n", 0) or 0),
|
|
63
|
+
}
|
|
64
|
+
for k in (
|
|
65
|
+
"tokenizer_name",
|
|
66
|
+
"tokenizer_hash",
|
|
67
|
+
"vocab_size",
|
|
68
|
+
"bos_token",
|
|
69
|
+
"eos_token",
|
|
70
|
+
"pad_token",
|
|
71
|
+
"add_prefix_space",
|
|
72
|
+
"dataset_hash",
|
|
73
|
+
"preview_hash",
|
|
74
|
+
"final_hash",
|
|
75
|
+
"preview_total_tokens",
|
|
76
|
+
"final_total_tokens",
|
|
77
|
+
"masked_tokens_total",
|
|
78
|
+
"masked_tokens_preview",
|
|
79
|
+
"masked_tokens_final",
|
|
80
|
+
"loss_type",
|
|
81
|
+
):
|
|
82
|
+
if k in data_in:
|
|
83
|
+
data_dict[k] = data_in.get(k)
|
|
84
|
+
data = cast(DataConfig, data_dict)
|
|
85
|
+
|
|
86
|
+
# ---- edit ----
|
|
87
|
+
edit_in = _as_mapping(src.get("edit"))
|
|
88
|
+
deltas_in = _as_mapping(edit_in.get("deltas"))
|
|
89
|
+
spars_val = deltas_in.get("sparsity")
|
|
90
|
+
deltas = EditDeltas(
|
|
91
|
+
params_changed=int(deltas_in.get("params_changed", 0) or 0),
|
|
92
|
+
sparsity=(float(spars_val) if isinstance(spars_val, int | float) else None),
|
|
93
|
+
bitwidth_map=(
|
|
94
|
+
deltas_in.get("bitwidth_map")
|
|
95
|
+
if isinstance(deltas_in.get("bitwidth_map"), dict)
|
|
96
|
+
else None
|
|
97
|
+
),
|
|
98
|
+
layers_modified=int(deltas_in.get("layers_modified", 0) or 0),
|
|
99
|
+
)
|
|
100
|
+
edit = EditInfo(
|
|
101
|
+
name=_str(edit_in.get("name")),
|
|
102
|
+
plan_digest=_str(edit_in.get("plan_digest")),
|
|
103
|
+
deltas=deltas,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# ---- guards ----
|
|
107
|
+
guards_in = src.get("guards")
|
|
108
|
+
guards: list[dict[str, Any]] = []
|
|
109
|
+
if isinstance(guards_in, list):
|
|
110
|
+
guards = [g for g in guards_in if isinstance(g, dict)]
|
|
111
|
+
|
|
112
|
+
# ---- metrics ----
|
|
113
|
+
m_in = _as_mapping(src.get("metrics"))
|
|
114
|
+
pm_in = _as_mapping(m_in.get("primary_metric"))
|
|
115
|
+
metrics_out: dict[str, Any] = {"primary_metric": dict(pm_in)}
|
|
116
|
+
|
|
117
|
+
# accuracy-style fallback (from classification aggregates)
|
|
118
|
+
if not metrics_out["primary_metric"]:
|
|
119
|
+
cls = (
|
|
120
|
+
m_in.get("classification")
|
|
121
|
+
if isinstance(m_in.get("classification"), dict)
|
|
122
|
+
else None
|
|
123
|
+
)
|
|
124
|
+
if isinstance(cls, dict):
|
|
125
|
+
point = None
|
|
126
|
+
fin = cls.get("final")
|
|
127
|
+
if isinstance(fin, int | float):
|
|
128
|
+
point = float(fin)
|
|
129
|
+
elif isinstance(fin, dict):
|
|
130
|
+
num = fin.get("correct_total")
|
|
131
|
+
den = fin.get("total")
|
|
132
|
+
if (
|
|
133
|
+
isinstance(num, int | float)
|
|
134
|
+
and isinstance(den, int | float)
|
|
135
|
+
and float(den) > 0
|
|
136
|
+
):
|
|
137
|
+
point = float(num) / float(den)
|
|
138
|
+
if isinstance(point, float):
|
|
139
|
+
# infer kind from model_id hint when available
|
|
140
|
+
model_id = _str(meta.get("model_id", "")).lower()
|
|
141
|
+
kind = "vqa_accuracy" if "vqa" in model_id else "accuracy"
|
|
142
|
+
pm_acc: dict[str, Any] = {
|
|
143
|
+
"kind": kind,
|
|
144
|
+
"unit": "accuracy",
|
|
145
|
+
"direction": "higher",
|
|
146
|
+
"aggregation_scope": "example",
|
|
147
|
+
"paired": True,
|
|
148
|
+
"gating_basis": "point",
|
|
149
|
+
"final": point,
|
|
150
|
+
}
|
|
151
|
+
# include n_final when available
|
|
152
|
+
if isinstance(fin, dict) and isinstance(fin.get("total"), int | float):
|
|
153
|
+
# safe: pm_acc is a plain dict
|
|
154
|
+
pm_acc["n_final"] = int(fin["total"])
|
|
155
|
+
metrics_out["primary_metric"] = pm_acc
|
|
156
|
+
|
|
157
|
+
# carry through selected non-PM fields when present
|
|
158
|
+
for k in (
|
|
159
|
+
"latency_ms_per_tok",
|
|
160
|
+
"latency_ms_p50",
|
|
161
|
+
"latency_ms_p95",
|
|
162
|
+
"memory_mb_peak",
|
|
163
|
+
"throughput_sps",
|
|
164
|
+
"spectral",
|
|
165
|
+
"rmt",
|
|
166
|
+
"invariants",
|
|
167
|
+
"bootstrap",
|
|
168
|
+
"reduction",
|
|
169
|
+
"moe",
|
|
170
|
+
"window_overlap_fraction",
|
|
171
|
+
"window_match_fraction",
|
|
172
|
+
"paired_windows",
|
|
173
|
+
"paired_delta_summary",
|
|
174
|
+
"window_pairing_reason",
|
|
175
|
+
"window_pairing_preview",
|
|
176
|
+
"window_pairing_final",
|
|
177
|
+
"total_tokens",
|
|
178
|
+
"preview_total_tokens",
|
|
179
|
+
"final_total_tokens",
|
|
180
|
+
):
|
|
181
|
+
if k in m_in:
|
|
182
|
+
metrics_out[k] = m_in.get(k)
|
|
183
|
+
metrics = cast(EvalMetrics, metrics_out)
|
|
184
|
+
|
|
185
|
+
# ---- artifacts ----
|
|
186
|
+
a_in = _as_mapping(src.get("artifacts"))
|
|
187
|
+
artifacts_dict: dict[str, Any] = {
|
|
188
|
+
"events_path": _str(a_in.get("events_path")),
|
|
189
|
+
"logs_path": _str(a_in.get("logs_path")),
|
|
190
|
+
"checkpoint_path": a_in.get("checkpoint_path")
|
|
191
|
+
if a_in.get("checkpoint_path") is None
|
|
192
|
+
or isinstance(a_in.get("checkpoint_path"), str)
|
|
193
|
+
else None,
|
|
194
|
+
}
|
|
195
|
+
artifacts = cast(Artifacts, artifacts_dict)
|
|
196
|
+
|
|
197
|
+
# ---- flags ----
|
|
198
|
+
f_in = _as_mapping(src.get("flags"))
|
|
199
|
+
flags = cast(
|
|
200
|
+
Flags,
|
|
201
|
+
{
|
|
202
|
+
"guard_recovered": bool(f_in.get("guard_recovered", False)),
|
|
203
|
+
"rollback_reason": f_in.get("rollback_reason"),
|
|
204
|
+
},
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
out: RunReport = RunReport(
|
|
208
|
+
meta=meta,
|
|
209
|
+
data=data,
|
|
210
|
+
edit=edit,
|
|
211
|
+
guards=cast(list[GuardReport], guards),
|
|
212
|
+
metrics=metrics,
|
|
213
|
+
artifacts=artifacts,
|
|
214
|
+
flags=flags,
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
# keep evaluation_windows if provided (for deeper pairing-based features)
|
|
218
|
+
ew = src.get("evaluation_windows")
|
|
219
|
+
if isinstance(ew, dict):
|
|
220
|
+
out["evaluation_windows"] = ew
|
|
221
|
+
|
|
222
|
+
# keep guard_overhead if provided (for quality_overhead derivation downstream)
|
|
223
|
+
go = src.get("guard_overhead")
|
|
224
|
+
if isinstance(go, Mapping):
|
|
225
|
+
out["guard_overhead"] = dict(go)
|
|
226
|
+
|
|
227
|
+
# keep provenance when present (dataset_split, provider_digest, etc.)
|
|
228
|
+
prov = src.get("provenance")
|
|
229
|
+
if isinstance(prov, Mapping):
|
|
230
|
+
out["provenance"] = dict(prov)
|
|
231
|
+
|
|
232
|
+
return out
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
__all__ = ["normalize_run_report"]
|