invarlock 0.3.4__py3-none-any.whl → 0.3.6__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.
Files changed (48) hide show
  1. invarlock/__init__.py +1 -1
  2. invarlock/_data/runtime/tiers.yaml +57 -30
  3. invarlock/adapters/__init__.py +1 -1
  4. invarlock/calibration/spectral_null.py +15 -10
  5. invarlock/calibration/variance_ve.py +0 -2
  6. invarlock/cli/commands/calibrate.py +6 -2
  7. invarlock/cli/commands/certify.py +58 -39
  8. invarlock/cli/commands/doctor.py +3 -1
  9. invarlock/cli/commands/explain_gates.py +57 -8
  10. invarlock/cli/commands/report.py +1 -1
  11. invarlock/cli/commands/run.py +159 -61
  12. invarlock/cli/commands/verify.py +78 -4
  13. invarlock/cli/config.py +21 -5
  14. invarlock/core/api.py +45 -5
  15. invarlock/core/auto_tuning.py +65 -20
  16. invarlock/core/contracts.py +7 -1
  17. invarlock/core/registry.py +2 -2
  18. invarlock/core/runner.py +314 -50
  19. invarlock/eval/bench.py +0 -13
  20. invarlock/eval/data.py +73 -283
  21. invarlock/eval/metrics.py +134 -4
  22. invarlock/eval/primary_metric.py +23 -0
  23. invarlock/eval/tail_stats.py +230 -0
  24. invarlock/guards/_estimators.py +154 -0
  25. invarlock/guards/policies.py +16 -6
  26. invarlock/guards/rmt.py +625 -544
  27. invarlock/guards/spectral.py +348 -110
  28. invarlock/guards/tier_config.py +32 -30
  29. invarlock/guards/variance.py +5 -29
  30. invarlock/guards_ref/rmt_ref.py +23 -23
  31. invarlock/model_profile.py +42 -15
  32. invarlock/reporting/certificate.py +225 -46
  33. invarlock/reporting/certificate_schema.py +2 -1
  34. invarlock/reporting/dataset_hashing.py +15 -2
  35. invarlock/reporting/guards_analysis.py +197 -274
  36. invarlock/reporting/normalizer.py +6 -0
  37. invarlock/reporting/policy_utils.py +38 -36
  38. invarlock/reporting/primary_metric_utils.py +71 -17
  39. invarlock/reporting/render.py +61 -0
  40. invarlock/reporting/report.py +1 -1
  41. invarlock/reporting/report_types.py +5 -2
  42. invarlock/reporting/validate.py +1 -18
  43. {invarlock-0.3.4.dist-info → invarlock-0.3.6.dist-info}/METADATA +6 -6
  44. {invarlock-0.3.4.dist-info → invarlock-0.3.6.dist-info}/RECORD +48 -46
  45. {invarlock-0.3.4.dist-info → invarlock-0.3.6.dist-info}/WHEEL +0 -0
  46. {invarlock-0.3.4.dist-info → invarlock-0.3.6.dist-info}/entry_points.txt +0 -0
  47. {invarlock-0.3.4.dist-info → invarlock-0.3.6.dist-info}/licenses/LICENSE +0 -0
  48. {invarlock-0.3.4.dist-info → invarlock-0.3.6.dist-info}/top_level.txt +0 -0
@@ -48,6 +48,10 @@ def _compute_thresholds_payload(
48
48
  if not isinstance(pm_policy, dict):
49
49
  pm_policy = {}
50
50
 
51
+ pm_tail_policy = metrics_policy.get("pm_tail", {})
52
+ if not isinstance(pm_tail_policy, dict):
53
+ pm_tail_policy = {}
54
+
51
55
  acc_policy = metrics_policy.get("accuracy", {})
52
56
  if not isinstance(acc_policy, dict):
53
57
  acc_policy = {}
@@ -76,6 +80,12 @@ def _compute_thresholds_payload(
76
80
  resolved_policy.get("variance", {}) if isinstance(resolved_policy, dict) else {}
77
81
  )
78
82
 
83
+ def _safe_float_any(value: Any, default: float) -> float:
84
+ try:
85
+ return float(value)
86
+ except Exception:
87
+ return float(default)
88
+
79
89
  payload = {
80
90
  "tier": tier_lc,
81
91
  "pm_ratio": {
@@ -86,6 +96,22 @@ def _compute_thresholds_payload(
86
96
  ),
87
97
  "hysteresis_ratio": float(pm_policy.get("hysteresis_ratio", 0.0) or 0.0),
88
98
  },
99
+ "pm_tail": {
100
+ "mode": str(pm_tail_policy.get("mode", "warn") or "warn").strip().lower(),
101
+ "min_windows": int(pm_tail_policy.get("min_windows", 0) or 0),
102
+ "quantile": _safe_float_any(pm_tail_policy.get("quantile", 0.95), 0.95),
103
+ "quantile_max": (
104
+ float(pm_tail_policy.get("quantile_max"))
105
+ if isinstance(pm_tail_policy.get("quantile_max"), int | float)
106
+ else None
107
+ ),
108
+ "epsilon": _safe_float_any(pm_tail_policy.get("epsilon", 0.0), 0.0),
109
+ "mass_max": (
110
+ float(pm_tail_policy.get("mass_max"))
111
+ if isinstance(pm_tail_policy.get("mass_max"), int | float)
112
+ else None
113
+ ),
114
+ },
89
115
  "accuracy": {
90
116
  "delta_min_pp": float(acc_policy.get("delta_min_pp", -1.0) or -1.0),
91
117
  "min_examples": int(acc_policy.get("min_examples", 200) or 200),
@@ -110,16 +136,6 @@ def _compute_thresholds_hash(payload: dict[str, Any]) -> str:
110
136
  return hashlib.sha256(canonical.encode("utf-8")).hexdigest()[:16]
111
137
 
112
138
 
113
- def _promote_legacy_multiple_testing_key(payload: dict[str, Any]) -> None:
114
- """Promote legacy 'multipletesting' to 'multiple_testing' in-place if present."""
115
- try:
116
- legacy_mt = payload.pop("multipletesting", None)
117
- if legacy_mt is not None and "multiple_testing" not in payload:
118
- payload["multiple_testing"] = legacy_mt
119
- except Exception:
120
- pass
121
-
122
-
123
139
  def _resolve_policy_tier(report: RunReport) -> str:
124
140
  """Resolve the policy tier from report metadata or context."""
125
141
  tier: Any = None
@@ -218,15 +234,9 @@ def _build_resolved_policies(
218
234
  from .policy_utils import _format_family_caps as _ffc # self import safe
219
235
 
220
236
  spectral_resolved["family_caps"] = _ffc(spectral_caps)
221
- # Prefer observed policy sigma_quantile (accepting legacy aliases), then fallback
222
237
  pol_sq = None
223
238
  try:
224
239
  pol_sq = (spectral.get("policy", {}) or {}).get("sigma_quantile")
225
- if pol_sq is None:
226
- # Legacy aliases
227
- pol_sq = (spectral.get("policy", {}) or {}).get("contraction") or (
228
- spectral.get("policy", {}) or {}
229
- ).get("kappa")
230
240
  except Exception:
231
241
  pol_sq = None
232
242
  spectral_resolved["sigma_quantile"] = _safe_float(
@@ -276,6 +286,9 @@ def _build_resolved_policies(
276
286
  spectral_resolved["max_spectral_norm"] = spectral.get("policy", {}).get(
277
287
  "max_spectral_norm", spectral_resolved.get("max_spectral_norm")
278
288
  )
289
+ mc = spectral.get("measurement_contract")
290
+ if isinstance(mc, dict) and mc:
291
+ spectral_resolved["measurement_contract"] = copy.deepcopy(mc)
279
292
  resolved["spectral"] = spectral_resolved
280
293
 
281
294
  # RMT guard
@@ -295,15 +308,16 @@ def _build_resolved_policies(
295
308
  rmt_resolved["epsilon_default"] = _safe_float(epsilon_default_val, 0.1)
296
309
  from .policy_utils import _format_epsilon_map as _fem
297
310
 
298
- epsilon_map = _fem(rmt.get("epsilon_by_family") or rmt_resolved.pop("epsilon", {}))
311
+ epsilon_map = _fem(
312
+ rmt.get("epsilon_by_family") or rmt_resolved.get("epsilon_by_family") or {}
313
+ )
299
314
  if epsilon_map:
300
315
  rmt_resolved["epsilon_by_family"] = epsilon_map
301
- else:
302
- rmt_resolved.pop("epsilon", None)
303
- if "epsilon" in rmt_resolved:
304
- rmt_resolved.pop("epsilon", None)
305
316
  if "correct" in rmt_resolved:
306
317
  rmt_resolved["correct"] = bool(rmt_resolved["correct"])
318
+ mc = rmt.get("measurement_contract")
319
+ if isinstance(mc, dict) and mc:
320
+ rmt_resolved["measurement_contract"] = copy.deepcopy(mc)
307
321
  resolved["rmt"] = rmt_resolved
308
322
 
309
323
  # Variance guard
@@ -441,13 +455,9 @@ def _extract_effective_policies(report: RunReport) -> dict[str, Any]:
441
455
  elif guard_name == "spectral":
442
456
  sigma_quantile = guard_metrics.get(
443
457
  "sigma_quantile",
444
- guard_metrics.get("contraction", guard_metrics.get("kappa", 0.95)),
445
- )
446
- multiple_testing = guard_metrics.get("multiple_testing") or (
447
- guard_metrics.get("multipletesting")
448
- if isinstance(guard_metrics.get("multipletesting"), dict)
449
- else None
458
+ 0.95,
450
459
  )
460
+ multiple_testing = guard_metrics.get("multiple_testing")
451
461
  guard_policy = {
452
462
  "max_spectral_norm": guard_metrics.get("max_spectral_norm"),
453
463
  "stability_score": guard_metrics.get("stability_score", 0.95),
@@ -473,20 +483,13 @@ def _extract_effective_policies(report: RunReport) -> dict[str, Any]:
473
483
 
474
484
  if guard_policy:
475
485
  if guard_name == "spectral":
476
- sigma_quantile = guard_policy.get("sigma_quantile")
477
- if sigma_quantile is None:
478
- sigma_quantile = guard_policy.get("contraction")
479
- if sigma_quantile is None and "kappa" in guard_policy:
480
- sigma_quantile = guard_policy["kappa"]
481
486
  sanitized_policy = dict(guard_policy)
487
+ sigma_quantile = sanitized_policy.get("sigma_quantile")
482
488
  if sigma_quantile is not None:
483
489
  try:
484
490
  sanitized_policy["sigma_quantile"] = float(sigma_quantile)
485
491
  except (TypeError, ValueError):
486
492
  pass
487
- _promote_legacy_multiple_testing_key(sanitized_policy)
488
- sanitized_policy.pop("contraction", None)
489
- sanitized_policy.pop("kappa", None)
490
493
  if sanitized_policy.get("max_spectral_norm") in (None, 0):
491
494
  sanitized_policy["max_spectral_norm"] = None
492
495
  guard_policy = sanitized_policy
@@ -587,7 +590,6 @@ __all__ = [
587
590
  "_compute_variance_policy_digest",
588
591
  "_compute_thresholds_payload",
589
592
  "_compute_thresholds_hash",
590
- "_promote_legacy_multiple_testing_key",
591
593
  "_resolve_policy_tier",
592
594
  "_build_resolved_policies",
593
595
  "_extract_effective_policies",
@@ -30,6 +30,38 @@ def attach_primary_metric(
30
30
  pm = m.get("primary_metric") if isinstance(m, dict) else None
31
31
  if isinstance(pm, dict) and pm:
32
32
  pm_copy = copy.deepcopy(pm)
33
+ pm_copy.setdefault("invalid", bool(pm_copy.get("invalid", False)))
34
+ degraded_reason = pm_copy.get("degraded_reason")
35
+ preview_val = pm_copy.get("preview")
36
+ final_val = pm_copy.get("final")
37
+ ratio_val = pm_copy.get("ratio_vs_baseline")
38
+ baseline_final = (
39
+ baseline_ref.get("primary_metric", {}).get("final")
40
+ if isinstance(baseline_ref, dict)
41
+ else None
42
+ )
43
+
44
+ def _is_finite(value: Any) -> bool:
45
+ return isinstance(value, (int, float)) and math.isfinite(float(value))
46
+
47
+ baseline_has_reference = _is_finite(baseline_final)
48
+ needs_pm_fallback = not (_is_finite(preview_val) and _is_finite(final_val))
49
+ needs_ratio_fallback = baseline_has_reference and not _is_finite(ratio_val)
50
+
51
+ if degraded_reason is None:
52
+ if needs_pm_fallback:
53
+ degraded_reason = "non_finite_pm"
54
+ elif needs_ratio_fallback:
55
+ degraded_reason = "non_finite_delta"
56
+ elif pm_copy.get("invalid"):
57
+ degraded_reason = "primary_metric_invalid"
58
+
59
+ pm_copy["degraded"] = bool(
60
+ pm_copy.get("degraded") or pm_copy.get("invalid") or degraded_reason
61
+ )
62
+ if pm_copy["degraded"] and degraded_reason:
63
+ pm_copy.setdefault("degraded_reason", degraded_reason)
64
+
33
65
  # Propagate instability hint from ppl_analysis
34
66
  try:
35
67
  if isinstance(ppl_analysis, dict) and bool(
@@ -75,33 +107,52 @@ def attach_primary_metric(
75
107
  pm_copy["analysis_point_final"] = float(mean_fin)
76
108
  # Attach analysis-basis CIs for preview/final in log space from report metrics
77
109
  try:
78
- dlci = (
79
- _coerce_interval(m.get("logloss_delta_ci"))
80
- if isinstance(m, dict)
81
- else (math.nan, math.nan)
82
- )
83
- if isinstance(dlci, tuple | list) and len(dlci) == 2:
84
- lo, hi = float(dlci[0]), float(dlci[1])
85
- if math.isfinite(lo) and math.isfinite(hi):
86
- pm_copy.setdefault("ci", (lo, hi))
110
+ dlci_source: tuple[float, float] | list[float] | None = None
111
+ pairing_source = None
112
+ if isinstance(ppl_analysis, dict):
113
+ stats = ppl_analysis.get("stats") or {}
114
+ if isinstance(stats, dict):
115
+ pairing_source = stats.get("pairing")
116
+ if pairing_source == "paired_baseline":
117
+ dlci_source = _coerce_interval(
118
+ ppl_analysis.get("logloss_delta_ci")
119
+ )
120
+ if dlci_source is None:
121
+ dlci_source = (
122
+ _coerce_interval(m.get("logloss_delta_ci"))
123
+ if isinstance(m, dict)
124
+ else (math.nan, math.nan)
125
+ )
126
+ if (
127
+ isinstance(dlci_source, tuple | list)
128
+ and len(dlci_source) == 2
129
+ ):
130
+ lo_raw, hi_raw = dlci_source[0], dlci_source[1]
131
+ if isinstance(lo_raw, (int, float)) and isinstance(
132
+ hi_raw, (int, float)
133
+ ):
134
+ lo, hi = float(lo_raw), float(hi_raw)
135
+ if math.isfinite(lo) and math.isfinite(hi):
136
+ pm_copy.setdefault("ci", (lo, hi))
87
137
  except Exception:
88
138
  pass
89
139
  except Exception:
90
140
  pass
91
141
  # Ensure ratio_vs_baseline present and consistent
92
142
  try:
93
- base_final = (
94
- baseline_ref.get("primary_metric", {}).get("final")
95
- if isinstance(baseline_ref, dict)
143
+ fin = pm_copy.get("final")
144
+ baseline_final_val = (
145
+ float(baseline_final)
146
+ if isinstance(baseline_final, (int, float))
147
+ and _is_finite(baseline_final)
96
148
  else None
97
149
  )
98
- fin = pm_copy.get("final")
99
150
  if (
100
- isinstance(fin, int | float)
101
- and isinstance(base_final, int | float)
102
- and float(base_final) > 0
151
+ isinstance(fin, (int, float))
152
+ and baseline_final_val is not None
153
+ and baseline_final_val > 0
103
154
  ):
104
- pm_copy["ratio_vs_baseline"] = float(fin) / float(base_final)
155
+ pm_copy["ratio_vs_baseline"] = float(fin) / baseline_final_val
105
156
  # Ensure display_ci aligns with log-space CI for ppl-like metrics
106
157
  try:
107
158
  kind = str(pm_copy.get("kind", "")).lower()
@@ -277,6 +328,9 @@ def attach_primary_metric(
277
328
  if isinstance(point, float):
278
329
  pm["display_ci"] = [point, point]
279
330
  else:
331
+ # As last resort, emit a degenerate [1.0, 1.0] to satisfy schema invariants
280
332
  pm["display_ci"] = [1.0, 1.0]
333
+ pm.setdefault("estimated", True)
334
+
281
335
  except Exception:
282
336
  pass
@@ -468,9 +468,70 @@ def render_certificate_markdown(certificate: dict[str, Any]) -> str:
468
468
  f"| Guard Overhead Acceptable | {status} | {measured} | ≤ +{threshold_pct:.1f}% | point | Guarded vs bare PM overhead |"
469
469
  )
470
470
 
471
+ def _emit_pm_tail_gate_row() -> None:
472
+ pm_tail = certificate.get("primary_metric_tail", {}) or {}
473
+ if not isinstance(pm_tail, dict) or not pm_tail:
474
+ return
475
+
476
+ evaluated = bool(pm_tail.get("evaluated", False))
477
+ mode = str(pm_tail.get("mode", "warn") or "warn").strip().lower()
478
+ passed = bool(pm_tail.get("passed", True))
479
+ warned = bool(pm_tail.get("warned", False))
480
+
481
+ if not evaluated:
482
+ status = "🛈 INFO"
483
+ elif passed:
484
+ status = "✅ PASS"
485
+ elif mode == "fail":
486
+ status = "❌ FAIL"
487
+ else:
488
+ status = "⚠️ WARN" if warned else "⚠️ WARN"
489
+
490
+ policy = (
491
+ pm_tail.get("policy", {}) if isinstance(pm_tail.get("policy"), dict) else {}
492
+ )
493
+ stats = (
494
+ pm_tail.get("stats", {}) if isinstance(pm_tail.get("stats"), dict) else {}
495
+ )
496
+
497
+ q = policy.get("quantile", 0.95)
498
+ try:
499
+ qf = float(q)
500
+ except Exception:
501
+ qf = 0.95
502
+ qf = max(0.0, min(1.0, qf))
503
+ q_key = f"q{int(round(100.0 * qf))}"
504
+ q_name = f"P{int(round(100.0 * qf))}"
505
+ q_val = stats.get(q_key)
506
+ mass_val = stats.get("tail_mass")
507
+ eps = policy.get("epsilon", stats.get("epsilon"))
508
+
509
+ measured_parts: list[str] = []
510
+ if isinstance(q_val, int | float) and math.isfinite(float(q_val)):
511
+ measured_parts.append(f"{q_name}={float(q_val):.3f}")
512
+ if isinstance(mass_val, int | float) and math.isfinite(float(mass_val)):
513
+ measured_parts.append(f"mass={float(mass_val):.3f}")
514
+ measured = ", ".join(measured_parts) if measured_parts else "N/A"
515
+
516
+ thr_parts: list[str] = []
517
+ qmax = policy.get("quantile_max")
518
+ if isinstance(qmax, int | float) and math.isfinite(float(qmax)):
519
+ thr_parts.append(f"{q_name}≤{float(qmax):.3f}")
520
+ mmax = policy.get("mass_max")
521
+ if isinstance(mmax, int | float) and math.isfinite(float(mmax)):
522
+ thr_parts.append(f"mass≤{float(mmax):.3f}")
523
+ if isinstance(eps, int | float) and math.isfinite(float(eps)):
524
+ thr_parts.append(f"ε={float(eps):.1e}")
525
+ threshold = "; ".join(thr_parts) if thr_parts else "policy"
526
+
527
+ lines.append(
528
+ f"| Primary Metric Tail | {status} | {measured} | {threshold} | {q_name.lower()} | Tail regression vs baseline (ΔlogNLL) |"
529
+ )
530
+
471
531
  # Emit canonical gate rows
472
532
  if has_pm:
473
533
  _emit_pm_gate_row()
534
+ _emit_pm_tail_gate_row()
474
535
  _emit_drift_gate_row()
475
536
  _emit_overhead_gate_row()
476
537
 
@@ -401,7 +401,7 @@ def _generate_single_markdown(report: RunReport) -> list[str]:
401
401
  parts.append(f"ratio_vs_baseline={ratio:.3f}")
402
402
  lines.append(" — ".join(parts) if len(parts) > 1 else parts[0])
403
403
  else:
404
- # When primary_metric is absent, do not attempt legacy fallbacks
404
+ # When primary_metric is absent, do not attempt fallbacks
405
405
  lines.append("- **Primary Metric**: unavailable")
406
406
  lines.append(
407
407
  f"- **Parameters Changed**: {report['edit']['deltas']['params_changed']:,}"
@@ -101,8 +101,10 @@ class EvalMetrics(TypedDict, total=False):
101
101
 
102
102
  # Canonical primary metric snapshot
103
103
  primary_metric: dict[str, Any]
104
+ # Always-computed tail evidence/gate for ppl-like primary metrics
105
+ primary_metric_tail: dict[str, Any]
104
106
 
105
- # Optional legacy/aux fields retained for guard telemetry and debug
107
+ # Optional aux fields retained for guard telemetry and debug
106
108
  latency_ms_per_tok: float # Average latency per token in milliseconds
107
109
  memory_mb_peak: float # Peak memory usage in MB
108
110
  spectral: dict[str, Any] # Spectral norm summaries
@@ -164,6 +166,7 @@ class RunReport(TypedDict):
164
166
  # Optional extras kept for richer downstream processing
165
167
  guard_overhead: NotRequired[dict[str, Any]]
166
168
  provenance: NotRequired[dict[str, Any]]
169
+ context: NotRequired[dict[str, Any]]
167
170
 
168
171
 
169
172
  # Utility functions for creating reports
@@ -247,7 +250,7 @@ def validate_report(report: RunReport) -> bool:
247
250
  if pm_final is not None and not isinstance(pm_final, int | float):
248
251
  return False
249
252
  else:
250
- # PM-only: legacy ppl_* acceptance removed
253
+ # PM-only: ppl_* acceptance removed
251
254
  return False
252
255
 
253
256
  meta = report.get("meta", {})
@@ -9,10 +9,9 @@ Supports both automated CI testing and flexible user validation.
9
9
  from __future__ import annotations
10
10
 
11
11
  import json
12
- import os
13
12
  import warnings
14
13
  from pathlib import Path
15
- from typing import Any, cast
14
+ from typing import Any
16
15
 
17
16
  __all__ = [
18
17
  "validate_against_baseline",
@@ -99,23 +98,7 @@ def validate_against_baseline(
99
98
  ratio_bounds: tuple[float, float] = (1.25, 1.32),
100
99
  delta_bounds_pp: tuple[float, float] | None = None,
101
100
  structural_exact: bool = True,
102
- **kwargs,
103
101
  ) -> ValidationResult:
104
- # Backward-compatible kwargs (deprecated): enable via INVARLOCK_VALIDATE_LEGACY=1
105
- legacy = str(os.environ.get("INVARLOCK_VALIDATE_LEGACY", "")).strip().lower() in {
106
- "1",
107
- "true",
108
- "yes",
109
- "on",
110
- }
111
- if legacy:
112
- if "tol_ppl_ratio" in kwargs and isinstance(
113
- kwargs["tol_ppl_ratio"], int | float
114
- ):
115
- tol_ratio = float(kwargs["tol_ppl_ratio"])
116
- if "ppl_bounds" in kwargs and isinstance(kwargs["ppl_bounds"], tuple):
117
- # Coerce after runtime guard
118
- ratio_bounds = cast(tuple[float, float], kwargs["ppl_bounds"])
119
102
  """
120
103
  Validate pruning results against baseline metrics (PM-only API).
121
104
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: invarlock
3
- Version: 0.3.4
3
+ Version: 0.3.6
4
4
  Summary: Edit‑agnostic robustness certificates for weight edits (InvarLock framework)
5
5
  Author-email: InvarLock Team <oss@invarlock.dev>
6
6
  Maintainer-email: InvarLock Maintainers <support@invarlock.dev>
@@ -112,7 +112,7 @@ they don’t, roll back safely.
112
112
  Technical: edit‑agnostic guard pipeline (invariants → spectral → RMT →
113
113
  variance) producing a machine‑readable Safety Certificate.
114
114
 
115
- > **Status:** 0.3.4 (pre‑1.0). Until 1.0, **minor** releases may be
115
+ > **Status:** 0.3.6 (pre‑1.0). Until 1.0, **minor** releases may be
116
116
  > breaking. See CLI help and the CHANGELOG for updates.
117
117
 
118
118
  [![CI](https://img.shields.io/github/actions/workflow/status/invarlock/invarlock/ci.yml?branch=main&logo=github&label=CI)](https://github.com/invarlock/invarlock/actions/workflows/ci.yml)
@@ -170,7 +170,7 @@ Quick examples (repo presets, CPU; repo clone required for preset paths):
170
170
  pip install "invarlock[hf]"
171
171
 
172
172
  # Preflight a config (JSON diagnostics)
173
- invarlock doctor --config configs/tasks/causal_lm/ci_cpu.yaml --json
173
+ invarlock doctor --config configs/presets/causal_lm/wikitext2_512.yaml --json
174
174
 
175
175
  # Calibrated GPT‑2 small (recommended starting point; repo preset)
176
176
  INVARLOCK_ALLOW_NETWORK=1 INVARLOCK_DEDUP_TEXTS=1 \
@@ -179,7 +179,7 @@ invarlock certify \
179
179
  --subject gpt2 \
180
180
  --adapter auto \
181
181
  --profile release \
182
- --preset configs/tasks/causal_lm/release_auto.yaml
182
+ --preset configs/presets/causal_lm/wikitext2_512.yaml
183
183
 
184
184
  # Tiny causal LM smoke (out‑of‑calibration, dev‑only)
185
185
  INVARLOCK_ALLOW_NETWORK=1 \
@@ -249,7 +249,7 @@ INVARLOCK_ALLOW_NETWORK=1 invarlock certify \
249
249
  --subject gpt2 \
250
250
  --adapter auto \
251
251
  --profile ci \
252
- --preset configs/tasks/causal_lm/ci_cpu.yaml
252
+ --preset configs/presets/causal_lm/wikitext2_512.yaml
253
253
  ```
254
254
 
255
255
  - Offline/air‑gapped usage: pre‑download to a cache, then run with network
@@ -488,7 +488,7 @@ output:
488
488
  Run preflight checks before a run to catch misconfigurations early:
489
489
 
490
490
  ```bash
491
- invarlock doctor --config configs/tasks/causal_lm/ci_cpu.yaml --json
491
+ invarlock doctor --config configs/presets/causal_lm/wikitext2_512.yaml --json
492
492
  ```
493
493
 
494
494
  Text mode emits lines prefixed with `ERROR:`, `WARNING:`, or `NOTE:` and stable
@@ -1,15 +1,15 @@
1
- invarlock/__init__.py,sha256=pTrxNy6MaRsu31Wvc1_V2TIENrSBVyVlk3AFDqggHxg,1268
1
+ invarlock/__init__.py,sha256=_KZRr1cTUSCHY7ZiPIk71h06tEznF_LOZQbyXcQfBMk,1268
2
2
  invarlock/__main__.py,sha256=ffhoKctw89j-henmQXThbHDIdlvK9fBfsy8LpjhOEXc,146
3
3
  invarlock/config.py,sha256=7BUOl7EW258YnsgRipjOx6lmWou5jNDzimREd35ewsQ,1725
4
- invarlock/model_profile.py,sha256=sFHpK-1Q-1DjiZTWMolQBG4Dw9feLJgk3GnaD3ixgd8,12809
4
+ invarlock/model_profile.py,sha256=K-RSLbQRv9uM4RMfLvApLf3p2wp8iKrfy3BZ4p1h3m4,13756
5
5
  invarlock/model_utils.py,sha256=mEl9KOF2yOJgx-6r38PbD9SNFeAScamy9K-csxtl40Q,6395
6
6
  invarlock/py.typed,sha256=LCPmZeE_vANVVJDNvuq9A07i7jg9Nxrq6f10UeuNfZc,37
7
7
  invarlock/security.py,sha256=xUjbHu-bHKUfFqDyN_21Hj00NBmAcGgnAg4JCjb0JOE,4861
8
8
  invarlock/sparsity_utils.py,sha256=30SC3osptca2GmzxezbfX31EE6sRUhmEz8u3jn4vB2c,8281
9
- invarlock/_data/runtime/tiers.yaml,sha256=xVHPi-Nopxc-Ye-5lGIer9k-lxiiZZ2cmSnzZE-EHIA,2989
9
+ invarlock/_data/runtime/tiers.yaml,sha256=9EbVnNw6MX18NKMI9xjKzJt-BsaB-JhUtC13c3Skmls,3619
10
10
  invarlock/_data/runtime/profiles/ci_cpu.yaml,sha256=FE5vxeemAFWW7oRxPvp_8hIcCO8qrJilvQpXuS3f6u0,389
11
11
  invarlock/_data/runtime/profiles/release.yaml,sha256=xF0Qb0OTm904U6L3wK674JMTcDPegYvpKgwUB9pfq_w,482
12
- invarlock/adapters/__init__.py,sha256=Bwj8aKjhFxCzvcdxTIl-nG7IXyIE4L3Nd_fsIghbZxA,3418
12
+ invarlock/adapters/__init__.py,sha256=MxWJGRxVrV2TL5c7MA4FqmWyu1e_Kwpk7Ol4IFUJcNM,3411
13
13
  invarlock/adapters/_capabilities.py,sha256=FmzUR5BHsxWe92Z9W1As-G5_5wG1PvqF2sUpjZ2_CdY,1483
14
14
  invarlock/adapters/auto.py,sha256=4F3I63PRW604v_NtaTY7aGvUJVjGSjejVKFff-X_1t4,7693
15
15
  invarlock/adapters/base.py,sha256=szSh1bECeDSDGQSr5oIWhs5RlI587gE4gzdt5cnOJ1s,16100
@@ -25,15 +25,15 @@ invarlock/adapters/hf_t5.py,sha256=sqHmi8io7oKlr7GrAk8tGo72zb-hmHGmXplCQSZgrA8,4
25
25
  invarlock/adapters/py.typed,sha256=LCPmZeE_vANVVJDNvuq9A07i7jg9Nxrq6f10UeuNfZc,37
26
26
  invarlock/assurance/__init__.py,sha256=SFDT2klaUaKZejulL5cfBTW29ehJxyW5srE-LuqP7z0,1388
27
27
  invarlock/calibration/__init__.py,sha256=M5lbkNQtLBuQjQJGeRzHovkpYI87fEWIm7a0b23jSp4,110
28
- invarlock/calibration/spectral_null.py,sha256=968168sQDgtZ2tATx7JkEtwtWw0Y7RFSk7OyQxwXBsE,9419
29
- invarlock/calibration/variance_ve.py,sha256=sdO-a9FUSDSvOI9T8qXAanw4GWOV7RZ_vv53N5ilEg4,4549
28
+ invarlock/calibration/spectral_null.py,sha256=2WQU7YgnnJ2i3OF60Zj4miaWBvWBXQmztukQtIWhvro,9601
29
+ invarlock/calibration/variance_ve.py,sha256=QkHO2vxht-n56LNqWbHYYY106Ge5PbxzHfGV1QktnN8,4487
30
30
  invarlock/cli/__init__.py,sha256=mRjYDVmNykhxJxfQBxJMzhFfmNhmvP6OWI-vJL-ehUA,196
31
31
  invarlock/cli/__main__.py,sha256=spgMrx0eJQSEf4rcd0_mB2B8rHOc3iWlTFO3P_qEvoM,175
32
32
  invarlock/cli/_evidence.py,sha256=38QMfFlPUT_qIRAZmpDROkwSIpHGiNKRWDyXfZ9xI_U,769
33
33
  invarlock/cli/_json.py,sha256=AKrRNFza76tH3GBVHO8gSA3klUVQ9XpDo_aYh8l-7j8,2367
34
34
  invarlock/cli/adapter_auto.py,sha256=Qwh4hJXm_vGexCXPt3iP70rQPC7ozwlEzSTYay0svQ8,5284
35
35
  invarlock/cli/app.py,sha256=iWO4tTwglZTH2CGEW_SXIQ95MyFTw6NYxlBujhpZQRg,9179
36
- invarlock/cli/config.py,sha256=d9uar3l9VuqeF_AMtan85V71Vc2L6HVjwLwE6SM2e0M,13464
36
+ invarlock/cli/config.py,sha256=vyLxR9WKW2vnIFACmS6k79yHEaO1zKuZ9q5bufaoB18,14203
37
37
  invarlock/cli/constants.py,sha256=RuXxG82pukfBnEuJB2CVF5dyu4lEi-l8eAxkR314yuk,2107
38
38
  invarlock/cli/determinism.py,sha256=ux3AODjZbSdYE29uSrHXvY2qrEPxeAJd04QLT52lnec,8346
39
39
  invarlock/cli/device.py,sha256=5X0j2yiZbSKX9-SlDaAbSeHCoWhfEQ74YWPTb8WRk8k,3165
@@ -43,28 +43,28 @@ invarlock/cli/overhead_utils.py,sha256=Ygvl192UDTroAbVAd7v35jgigmmfVxNkCIGYlWfh6
43
43
  invarlock/cli/provenance.py,sha256=2E_8MxpSVEcxe5UewTb5Hlz6x4jXFwGd1567F4nIbEc,1939
44
44
  invarlock/cli/utils.py,sha256=R6IN21lGfko2lGUgspmkZyjA6Nl_dVRaP8F8nRtN5yw,1393
45
45
  invarlock/cli/commands/__init__.py,sha256=afpKpU8hJI41Ol46oXxVwQgPwFBy4OmLaa_v4AAOdts,712
46
- invarlock/cli/commands/calibrate.py,sha256=b_75wIuHuhQ-frVcKkSuA8W5AMN3acc63k6q9tZvNEE,20780
47
- invarlock/cli/commands/certify.py,sha256=2dYMrZYX1fACOIHbHshPoM7leCizQDRTPZ3Gc8s7FNo,14903
48
- invarlock/cli/commands/doctor.py,sha256=cz4uH8v77M74YhwlWEMgnmEpmqbsV5CN5-zkuDIBLS8,56897
49
- invarlock/cli/commands/explain_gates.py,sha256=CajKcu6rNi57yBsM_EUhi8rlmTl-ymT1kUaznXzALSE,7624
46
+ invarlock/cli/commands/calibrate.py,sha256=TnoYKjvmz2pSj3Wak8HluSV27hN2D8O1dGAQWCcHeeE,20830
47
+ invarlock/cli/commands/certify.py,sha256=n62diGs7eFymuJNz-EJmWldYVO5KehHWeYtwtL1UWRY,15861
48
+ invarlock/cli/commands/doctor.py,sha256=IQciP1Xs-_W4R5lhZv1ZbYwvIjy9VY_WMBypvbok1FI,56944
49
+ invarlock/cli/commands/explain_gates.py,sha256=7cnc_FBxvSkjmM12JOA2yfhY4JH1puDDaIHo3r6IC9M,9444
50
50
  invarlock/cli/commands/export_html.py,sha256=oUGtt6EpKhjlywdtz_0FqYqcmA219H4eSjPuSMDShgY,3095
51
51
  invarlock/cli/commands/plugins.py,sha256=u5E6ThcWE5RUs2YKH-m6x7n-5K1jt2IudkF9kl9T5xg,53486
52
- invarlock/cli/commands/report.py,sha256=I-B11k6cLLNUIaNiKlsWrGgZ2cTQQJsarN3oNf9Dt84,12988
53
- invarlock/cli/commands/run.py,sha256=nf9Y_BcgxQyaCjwQmGUt8ZojDXBDPSeEk4Ut4_uRggM,200772
54
- invarlock/cli/commands/verify.py,sha256=WAgIzV_CAZSkzRJIxVFV5llZAL3n3-biTMXLm6YL_qs,46408
52
+ invarlock/cli/commands/report.py,sha256=AaGq4J1qm8ERMZmbAkAHtc8kZ0CvMp14wili1K2tX8g,12987
53
+ invarlock/cli/commands/run.py,sha256=S25dVLxQe1RVxLQ6cD8CSlpqGxp1Eggvbk4WzsHSwW4,204782
54
+ invarlock/cli/commands/verify.py,sha256=zKoSTPLrMgCw6LseCNn5RkPDEZTuRZ8j14tWHbvcZxM,49234
55
55
  invarlock/core/__init__.py,sha256=4wb83Xv7NE5M1FgvaFUviiNtVSTVATiPH3gqavNmp2w,1490
56
56
  invarlock/core/abi.py,sha256=gmU1F7LDd2HTcF4kcznn8vgG4zj9UCHSqhBk9jyu05k,484
57
- invarlock/core/api.py,sha256=dg76wZaULo-T-_nZtq6rmDtWwSNLCSYXiQKVYySV6Fg,7545
58
- invarlock/core/auto_tuning.py,sha256=ulk_bLAokQJFHgttj5x9QmkwSx7IPVhX2J1GBPWS6PA,17383
57
+ invarlock/core/api.py,sha256=RTFswFBuUH38gary5X7qmccOD7vAYLtSN0ie8Y6p1ck,8480
58
+ invarlock/core/auto_tuning.py,sha256=Gj0AhpThoDYnzr9DyuXM9iCuieMKR4xv43tC7ZcjHzs,18543
59
59
  invarlock/core/bootstrap.py,sha256=0mA_x1Ipz4eTwJqoz4-F4H0O2AqvlmQGA9BVJpTNqXs,10655
60
60
  invarlock/core/checkpoint.py,sha256=a78L-mZd3j2kC1az2eTScRxTHjrULuYs-UPfWUcDgqM,6933
61
- invarlock/core/contracts.py,sha256=9j55WVwMrEsUqxWlzAdMsHtkzgfkSftdizhcLiJBauw,2165
61
+ invarlock/core/contracts.py,sha256=ESK3-ErieGEf8e84wiphlCjahdr87zoKyTSskq6o23E,2468
62
62
  invarlock/core/error_utils.py,sha256=T23-p5ONQ-SeVuMR4Ts0cWyupsSa-0DAgsejRTfxeCg,1782
63
63
  invarlock/core/events.py,sha256=8XBAi-9A7ys7QJQwqlz8PVlfxF0TM_TvLqjcPtDwZm4,9428
64
64
  invarlock/core/exceptions.py,sha256=b4OszJ0Fd0Ezy8s99AzprS7lAkqdZYGXaSj9fYaln4E,2077
65
- invarlock/core/registry.py,sha256=a5hYHXl74MLnaPFbmpwJ-1OsJgY3SSe2Jisbzfr2rLM,19137
65
+ invarlock/core/registry.py,sha256=ZRW7JY-XgWrQMtN451n_Uk4it3CMLCsZUPHqic2G1x4,19109
66
66
  invarlock/core/retry.py,sha256=KTVkrTnWs60jwATOZDHinERH56GnOGjsKR0lmohagEo,4503
67
- invarlock/core/runner.py,sha256=Tep0CDT75PbE8bpGapR8J00-MXZ-T0JB4C6tsqOMs68,93567
67
+ invarlock/core/runner.py,sha256=BYvJlWhsrSRyudXNdY-vuZVt5NypYqMTS5yK28jhIVI,104105
68
68
  invarlock/core/types.py,sha256=nVLMP4yqlxwhE1moQU7FWVeGJqTuud-cvTZiutdBGKk,3585
69
69
  invarlock/edits/__init__.py,sha256=5CJTX6oJTLj79Vmks2_8mXRGFQH0oyKaZOrBLTlRtV0,277
70
70
  invarlock/edits/_edit_utils.py,sha256=VGl32JAt7XsovxJbX1YvW9DJvtG-K2EKu-TjBFTQmDY,6329
@@ -74,13 +74,14 @@ invarlock/edits/py.typed,sha256=LCPmZeE_vANVVJDNvuq9A07i7jg9Nxrq6f10UeuNfZc,37
74
74
  invarlock/edits/quant_rtn.py,sha256=8rseGbF_-EFuL8MWCuzgGXYfzp9LsONhV72-OK56mlk,30684
75
75
  invarlock/edits/registry.py,sha256=MmUfJhhvc3WxB03wQkPxFMS6nkT7YcXFPQqhbksfOUc,4523
76
76
  invarlock/eval/__init__.py,sha256=GsKoszCysh3TT_UHiuJcqeoiXT7AUNZoqMuBmefnWtY,755
77
- invarlock/eval/bench.py,sha256=85tGywzAeJSVlZ1Qsebk8FwIGUYhq9g6TxOW5XnL5X8,56335
77
+ invarlock/eval/bench.py,sha256=pG1OSO5-Ela46ReImhQJAuLTxE6oSfTFjHSTSL_09-8,55925
78
78
  invarlock/eval/bench_regression.py,sha256=GDphmdcH7NI8P_afSkQAPMChEgW15J0gqTZ4Kj3kxgw,456
79
79
  invarlock/eval/bootstrap.py,sha256=CNn7W_MY716Wa_wn6cYRmbTYB9lT2X0yLOAIHCRw29k,1766
80
- invarlock/eval/data.py,sha256=QVGOIiakm89jEy9-rVMlFJ6WYHq_keSrSNUOjRsVwCA,75736
81
- invarlock/eval/metrics.py,sha256=3ay3mqsFTa0V5a66gKdk7BOOJjKWXlub5lrTpcex9DQ,73946
82
- invarlock/eval/primary_metric.py,sha256=ay8gB7xGjWahXpJP-o4OcZFNRNZKcUIHjKmSeOUWJNk,28701
80
+ invarlock/eval/data.py,sha256=YUOvgM3h_KSIZ0FQw5yhrsU_YonIb5Ml950t8hg3qn8,66652
81
+ invarlock/eval/metrics.py,sha256=Ff72jgeLAWCn1WgpDE2lX0RzdJMrb39fgjKCF2rwkpk,78972
82
+ invarlock/eval/primary_metric.py,sha256=lGDWiXM1cyXqGH6XprLrxBl1hTwjrlSYbQCzF687zsA,29545
83
83
  invarlock/eval/py.typed,sha256=LCPmZeE_vANVVJDNvuq9A07i7jg9Nxrq6f10UeuNfZc,37
84
+ invarlock/eval/tail_stats.py,sha256=ueScFzPvBnBC4jVW5EElnB0c3LPK3cAITcOUdyPCsEk,7114
84
85
  invarlock/eval/probes/__init__.py,sha256=KocOJmEWrD90c2HbDW3wDsdsibRyidskpI4rNNfLbZ0,593
85
86
  invarlock/eval/probes/fft.py,sha256=iuZauzOaNPbXN4t74vMiNQAjg6ZmwPNPUuUBj4L1ick,4106
86
87
  invarlock/eval/probes/mi.py,sha256=ew33dkc1tymDVek718m7ZU--BAFa1L35PZA2POwKx0g,7258
@@ -91,15 +92,16 @@ invarlock/eval/providers/text_lm.py,sha256=EpQWjQEkxSMhTiABsJzZqfYsgSYeMmUW-ZgeP
91
92
  invarlock/eval/providers/vision_text.py,sha256=pqhPHwvYEnyKupchIy-g-jM_oWeYNXRHb23_Qm4v2hU,3180
92
93
  invarlock/guards/__init__.py,sha256=Kj7Jwb4qLyaY0ATRku34T628vom3QMjTiVrlpfJAWw8,443
93
94
  invarlock/guards/_contracts.py,sha256=WPhg3iWpHGkKfPvlPPQ-umzOakpy3s289DKkYQ0e64I,263
95
+ invarlock/guards/_estimators.py,sha256=84nT5eF7uN-zr-RfYF2uOvdHlmE5c8_yvor4IqxvwWk,4642
94
96
  invarlock/guards/invariants.py,sha256=2mD5WSJMCksjO-DodAac5pvZN0nl29NKHhqwqH_gyCQ,22379
95
- invarlock/guards/policies.py,sha256=sbZkddUSnkx3ZsFm4vV4DfSU81QUh9R8S4vuAtPF11I,25466
97
+ invarlock/guards/policies.py,sha256=ggY0zZ3i39OAeFZJSG1FjwnR3-wjWntKLLvumBvG8pc,25933
96
98
  invarlock/guards/py.typed,sha256=LCPmZeE_vANVVJDNvuq9A07i7jg9Nxrq6f10UeuNfZc,37
97
- invarlock/guards/rmt.py,sha256=U3_JTZKsOIgnH-TdZxKMLL9p_3EbfYJKlIqB1gtvQLw,97928
98
- invarlock/guards/spectral.py,sha256=lmnq4x1-MwoXAK6awaUeb_6xvCya-Tg_zqECDdYvMOA,58618
99
- invarlock/guards/tier_config.py,sha256=_WJIQ4qvIOc8EI1ygBhpBqbZPt072RT6H6Oh9-LqNWY,10706
100
- invarlock/guards/variance.py,sha256=lcTNb_uSufB7D8cLkoY1S_IQWHUjIfCucsu5y8MpfPs,136794
99
+ invarlock/guards/rmt.py,sha256=eKWbF4htt_0-Cuby5T9Q6Di6QmQPsCBUWh-dCXlrxic,99864
100
+ invarlock/guards/spectral.py,sha256=TP_xmzL0iP3CSQjnkulNbuJegxCrp68MuMPWdLeE0Gg,69597
101
+ invarlock/guards/tier_config.py,sha256=6JzS1TOlhUVX2NdUodWhb4VOA_AnAFVOXvwY9aiopbA,10796
102
+ invarlock/guards/variance.py,sha256=8WauGx34ORBMrArYTDRtyEZuTcZSeBIqJHqG067wugc,136371
101
103
  invarlock/guards_ref/__init__.py,sha256=jLnyFqdqQaheG1qQMlU4Gx7R118rkkQHPqFVF3_1ih0,366
102
- invarlock/guards_ref/rmt_ref.py,sha256=md-aSzLCxPL3OXmrA5NtI9wK7cVSyd2xw8WtSodcGQY,1246
104
+ invarlock/guards_ref/rmt_ref.py,sha256=IfwN-l9cLExUQJhZmr-1uJv7qRSoYrGg2w2caCG53hs,1399
103
105
  invarlock/guards_ref/spectral_ref.py,sha256=FdwFfrs5hxEEUIfBV3CvAJvTX78gAM00mKLEXyZ0zJo,4386
104
106
  invarlock/guards_ref/variance_ref.py,sha256=BmTQL5nfxReJK5SqnuUi1SOcQftK7IUNwlcxqdtGPEU,2264
105
107
  invarlock/observability/__init__.py,sha256=_fCH1H51M0PYOvpuNq9sVQLTiDAtdQMvtnhVt-z-VPk,345
@@ -117,24 +119,24 @@ invarlock/plugins/hf_bnb_adapter.py,sha256=g0ysWEi8dQzLtJy8iCszfTsYCOACuZMFYnTLM
117
119
  invarlock/plugins/hf_gptq_adapter.py,sha256=ysugAcnjLqF5sqpijSNiim1xUpRmoIgBrG053X3S2hE,3743
118
120
  invarlock/plugins/py.typed,sha256=LCPmZeE_vANVVJDNvuq9A07i7jg9Nxrq6f10UeuNfZc,37
119
121
  invarlock/reporting/__init__.py,sha256=A0541EqxcdTpslNbZEWIO4q-LCqzCQcadev2IBKEBbM,232
120
- invarlock/reporting/certificate.py,sha256=yoMfALyXYGK6BBHJfsrCFDxb07o-9J0KQqui35RHkhM,146382
121
- invarlock/reporting/certificate_schema.py,sha256=ft58LrF4lfdXT08P0jjtiNvRPVs6TdgPU_cp9K4TMPw,8939
122
- invarlock/reporting/dataset_hashing.py,sha256=b9LM2rtOtD0-1gQq_oJ0yI6oLleempwKinQtLupajwI,8680
123
- invarlock/reporting/guards_analysis.py,sha256=7TTlF-OwgT7wGQ8zZ8oHHPuMdUMvKw7836WvO0J1GUc,42465
122
+ invarlock/reporting/certificate.py,sha256=UyUhhrgWsdNG2xPtOVvRjaiWaOhHP-Aw6PuzOD8UBHQ,154177
123
+ invarlock/reporting/certificate_schema.py,sha256=aZPDvJcFOIcwNJ06iTHJtXAHTmb5BPvv_T7qaSTjW8o,8978
124
+ invarlock/reporting/dataset_hashing.py,sha256=igDq9iMB8sqed5CEWT2fXtx9z5QAxIZ9bbs5RndDDC4,9228
125
+ invarlock/reporting/guards_analysis.py,sha256=JYZ-_Aoc1XI7BrYYm1Pit4n5vTewnt8wqhzMDrWYpO8,38014
124
126
  invarlock/reporting/html.py,sha256=d3LQ_brDGYW7GLR_Kj4rimIfGZsAgVE9XQtIjqsJ1rw,1029
125
- invarlock/reporting/normalizer.py,sha256=hSfNMyUusWZ1OIJ5lVxzKrk8Le1rRqbwOkPY83gCcHM,8078
126
- invarlock/reporting/policy_utils.py,sha256=Yu0zAtjnf0-w9t03NvH7LJ0lxe98o-E1tD8TpXtzsfo,23080
127
- invarlock/reporting/primary_metric_utils.py,sha256=F9H8xpEIgbYfj6VS5-QA5aNLL5OwPegdQVKwvdoVVMM,12150
128
- invarlock/reporting/render.py,sha256=zukCOm6Qm81nDkpOur50TKrlgRpnt7Q53TEU7eYFivg,59976
129
- invarlock/reporting/report.py,sha256=kyoqTiqtYUQfgpwm6RApV-LbHHIyryfiIPIRhy-z47Q,32293
130
- invarlock/reporting/report_types.py,sha256=IoCLoPdoB71hW6-UatZXSjG7itTn4dKp7jPRndXxugA,8736
127
+ invarlock/reporting/normalizer.py,sha256=7zUyx9pUPuV6IrEi7PRBFIAid_14ABuU4xhHLjkONCI,8271
128
+ invarlock/reporting/policy_utils.py,sha256=540fw6cFvyvYL7avlvId9GUvY9-g6MkeDlcPt18uuE0,22934
129
+ invarlock/reporting/primary_metric_utils.py,sha256=7h6CzMQzu0A8xN10vbRgSNcQ0YTMxsT2JiNEgCVaXyM,14849
130
+ invarlock/reporting/render.py,sha256=nujyDXgh11dWUtYPru41mx8FnWer7-5wbCiqqK2ae7A,62450
131
+ invarlock/reporting/report.py,sha256=oqNjusy2wseURakW3Icn0MPSDNMm6bpcvKREFTzbd3o,32286
132
+ invarlock/reporting/report_types.py,sha256=cw6UxHS67W0Y8uLEFoplGFrdrr9ktZDyzkvjuQkSERU,8873
131
133
  invarlock/reporting/utils.py,sha256=1aLYgSUR4XvgmhDvU9YK9ICd7W5sjft1qdsZC9JJSRY,5540
132
- invarlock/reporting/validate.py,sha256=oh7w8VrLM2EYZSJ2ySDNi7WKKmF1SgS81VkOrcHMzaE,22427
134
+ invarlock/reporting/validate.py,sha256=aFcac5iaaNOLMYEf6g5xoF4-a-J5E430utFLnfu6fKc,21782
133
135
  invarlock/utils/__init__.py,sha256=DR2pBrgddLH2PW-6ninOE8CM7DNvlvgyYsCkckozbPU,4276
134
136
  invarlock/utils/digest.py,sha256=sfnqGFRiRf7l950MjSIrWO1XbUfXlcEfNLeWFbBUr8I,1290
135
- invarlock-0.3.4.dist-info/licenses/LICENSE,sha256=uFddaXYY02nEFdPpS7bam_bnm0st41BibzD0jHULPXw,10413
136
- invarlock-0.3.4.dist-info/METADATA,sha256=RycW7PQJeWJgfX-e3KbqUi_zjXxDPzLkchaTVoS_SCA,21845
137
- invarlock-0.3.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
138
- invarlock-0.3.4.dist-info/entry_points.txt,sha256=i0e4ZzmJNMBGG-69lbgP-muEcn1je2TUIWwl9SJERm0,670
139
- invarlock-0.3.4.dist-info/top_level.txt,sha256=GXfftc_YDHHcQC2vQgYbZ5cTO82YuWY3HusHMT3DuKs,10
140
- invarlock-0.3.4.dist-info/RECORD,,
137
+ invarlock-0.3.6.dist-info/licenses/LICENSE,sha256=uFddaXYY02nEFdPpS7bam_bnm0st41BibzD0jHULPXw,10413
138
+ invarlock-0.3.6.dist-info/METADATA,sha256=PYnrgExSymgE3QAyfJbHect9jVt6cJatWY3zVp7npNo,21875
139
+ invarlock-0.3.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
140
+ invarlock-0.3.6.dist-info/entry_points.txt,sha256=i0e4ZzmJNMBGG-69lbgP-muEcn1je2TUIWwl9SJERm0,670
141
+ invarlock-0.3.6.dist-info/top_level.txt,sha256=GXfftc_YDHHcQC2vQgYbZ5cTO82YuWY3HusHMT3DuKs,10
142
+ invarlock-0.3.6.dist-info/RECORD,,