invarlock 0.3.5__py3-none-any.whl → 0.3.7__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 (74) hide show
  1. invarlock/__init__.py +2 -2
  2. invarlock/_data/runtime/tiers.yaml +57 -30
  3. invarlock/adapters/__init__.py +11 -15
  4. invarlock/adapters/auto.py +35 -40
  5. invarlock/adapters/capabilities.py +2 -2
  6. invarlock/adapters/hf_causal.py +418 -0
  7. invarlock/adapters/{hf_onnx.py → hf_causal_onnx.py} +3 -3
  8. invarlock/adapters/hf_mixin.py +25 -4
  9. invarlock/adapters/{hf_bert.py → hf_mlm.py} +4 -11
  10. invarlock/adapters/{hf_t5.py → hf_seq2seq.py} +9 -9
  11. invarlock/calibration/spectral_null.py +15 -10
  12. invarlock/calibration/variance_ve.py +0 -2
  13. invarlock/cli/adapter_auto.py +31 -21
  14. invarlock/cli/app.py +73 -2
  15. invarlock/cli/commands/calibrate.py +6 -2
  16. invarlock/cli/commands/certify.py +651 -91
  17. invarlock/cli/commands/doctor.py +11 -11
  18. invarlock/cli/commands/explain_gates.py +57 -8
  19. invarlock/cli/commands/plugins.py +13 -9
  20. invarlock/cli/commands/report.py +233 -69
  21. invarlock/cli/commands/run.py +1066 -244
  22. invarlock/cli/commands/verify.py +154 -15
  23. invarlock/cli/config.py +22 -6
  24. invarlock/cli/doctor_helpers.py +4 -5
  25. invarlock/cli/output.py +193 -0
  26. invarlock/cli/provenance.py +1 -1
  27. invarlock/core/api.py +45 -5
  28. invarlock/core/auto_tuning.py +65 -20
  29. invarlock/core/bootstrap.py +1 -1
  30. invarlock/core/contracts.py +7 -1
  31. invarlock/core/registry.py +11 -13
  32. invarlock/core/runner.py +425 -75
  33. invarlock/edits/quant_rtn.py +65 -37
  34. invarlock/eval/bench.py +3 -16
  35. invarlock/eval/data.py +82 -51
  36. invarlock/eval/metrics.py +63 -2
  37. invarlock/eval/primary_metric.py +23 -0
  38. invarlock/eval/tail_stats.py +230 -0
  39. invarlock/eval/tasks/__init__.py +12 -0
  40. invarlock/eval/tasks/classification.py +48 -0
  41. invarlock/eval/tasks/qa.py +36 -0
  42. invarlock/eval/tasks/text_generation.py +102 -0
  43. invarlock/guards/_estimators.py +154 -0
  44. invarlock/guards/invariants.py +19 -10
  45. invarlock/guards/policies.py +16 -6
  46. invarlock/guards/rmt.py +627 -546
  47. invarlock/guards/spectral.py +348 -110
  48. invarlock/guards/tier_config.py +32 -30
  49. invarlock/guards/variance.py +7 -31
  50. invarlock/guards_ref/rmt_ref.py +23 -23
  51. invarlock/model_profile.py +90 -42
  52. invarlock/observability/health.py +6 -6
  53. invarlock/observability/metrics.py +108 -0
  54. invarlock/reporting/certificate.py +384 -55
  55. invarlock/reporting/certificate_schema.py +3 -2
  56. invarlock/reporting/dataset_hashing.py +15 -2
  57. invarlock/reporting/guards_analysis.py +350 -277
  58. invarlock/reporting/html.py +55 -5
  59. invarlock/reporting/normalizer.py +13 -0
  60. invarlock/reporting/policy_utils.py +38 -36
  61. invarlock/reporting/primary_metric_utils.py +71 -17
  62. invarlock/reporting/render.py +852 -431
  63. invarlock/reporting/report.py +40 -4
  64. invarlock/reporting/report_types.py +11 -3
  65. invarlock/reporting/telemetry.py +86 -0
  66. invarlock/reporting/validate.py +1 -18
  67. {invarlock-0.3.5.dist-info → invarlock-0.3.7.dist-info}/METADATA +27 -13
  68. {invarlock-0.3.5.dist-info → invarlock-0.3.7.dist-info}/RECORD +72 -65
  69. {invarlock-0.3.5.dist-info → invarlock-0.3.7.dist-info}/WHEEL +1 -1
  70. {invarlock-0.3.5.dist-info → invarlock-0.3.7.dist-info}/entry_points.txt +5 -3
  71. invarlock/adapters/hf_gpt2.py +0 -404
  72. invarlock/adapters/hf_llama.py +0 -487
  73. {invarlock-0.3.5.dist-info → invarlock-0.3.7.dist-info}/licenses/LICENSE +0 -0
  74. {invarlock-0.3.5.dist-info → invarlock-0.3.7.dist-info}/top_level.txt +0 -0
invarlock/__init__.py CHANGED
@@ -6,13 +6,13 @@ Core runtime package — torch-independent utilities, configuration, and interfa
6
6
 
7
7
  This package provides the foundation for the InvarLock GuardChain without heavy dependencies.
8
8
  For torch-dependent functionality, see subpackages under `invarlock.*`:
9
- - `invarlock.adapters`: Model adapters (HF GPT-2/BERT/LLaMA, auto)
9
+ - `invarlock.adapters`: Model adapters (HF causal/MLM/seq2seq + auto)
10
10
  - `invarlock.guards`: Safety mechanisms (invariants, spectral, RMT, variance)
11
11
  - `invarlock.edits`: Built-in quantization and edit interfaces
12
12
  - `invarlock.eval`: Metrics, guard-overhead checks, and certification
13
13
  """
14
14
 
15
- __version__ = "0.3.5"
15
+ __version__ = "0.3.7"
16
16
 
17
17
  # Core exports - torch-independent
18
18
  from .config import CFG, Defaults, get_default_config
@@ -1,8 +1,12 @@
1
- # Tier guard policy knobs for variance correction (balanced vs conservative)
1
+ # Tier policy defaults (metrics gates + guard knobs) used at runtime.
2
2
  #
3
- # These values mirror the settings validated during the December 2025
4
- # calibration runs. They should be kept in sync with the policy digest
5
- # embedded in certificates and referenced by automation documentation.
3
+ # Balanced and Conservative values are calibrated/validated against pilot/null
4
+ # runs (Nov/Dec 2025) where applicable; Aggressive is research-oriented (not in
5
+ # the safety case).
6
+ #
7
+ # Rationale by key: docs/reference/tier-policy-catalog.md
8
+ # Calibration method: docs/assurance/09-tier-v1-calibration.md
9
+ # Provenance/digest: docs/assurance/11-policy-provenance.md
6
10
 
7
11
  balanced:
8
12
  metrics:
@@ -11,6 +15,13 @@ balanced:
11
15
  min_tokens: 50000
12
16
  hysteresis_ratio: 0.002
13
17
  min_token_fraction: 0.01
18
+ pm_tail:
19
+ mode: warn
20
+ min_windows: 50
21
+ quantile: 0.95
22
+ quantile_max: 0.20
23
+ epsilon: 0.0001
24
+ mass_max: 1.0
14
25
  accuracy:
15
26
  delta_min_pp: -1.0
16
27
  min_examples: 200
@@ -20,7 +31,7 @@ balanced:
20
31
  deadband: 0.02
21
32
  min_abs_adjust: 0.012
22
33
  max_scale_step: 0.03
23
- min_effect_lognll: 0.0009
34
+ min_effect_lognll: 0.0
24
35
  predictive_one_sided: true
25
36
  topk_backstop: 1
26
37
  max_adjusted_modules: 1
@@ -33,10 +44,10 @@ balanced:
33
44
  max_caps: 5
34
45
  max_spectral_norm: null
35
46
  family_caps:
36
- ffn: 3.834
37
- attn: 3.423
38
- embed: 3.1
39
- other: 3.1
47
+ ffn: 3.849
48
+ attn: 3.018
49
+ embed: 1.05
50
+ other: 0.0
40
51
  multiple_testing:
41
52
  method: bh
42
53
  alpha: 0.05
@@ -44,12 +55,12 @@ balanced:
44
55
  rmt_guard:
45
56
  deadband: 0.10
46
57
  margin: 1.5
47
- epsilon_default: 0.10
58
+ epsilon_default: 0.01
48
59
  epsilon_by_family:
49
- ffn: 0.10
50
- attn: 0.08
51
- embed: 0.12
52
- other: 0.12
60
+ ffn: 0.01
61
+ attn: 0.01
62
+ embed: 0.01
63
+ other: 0.01
53
64
 
54
65
  conservative:
55
66
  metrics:
@@ -58,6 +69,13 @@ conservative:
58
69
  min_tokens: 20000
59
70
  hysteresis_ratio: 0.002
60
71
  min_token_fraction: 0.01
72
+ pm_tail:
73
+ mode: warn
74
+ min_windows: 50
75
+ quantile: 0.95
76
+ quantile_max: 0.12
77
+ epsilon: 0.0001
78
+ mass_max: 1.0
61
79
  accuracy:
62
80
  delta_min_pp: -0.5
63
81
  min_examples: 200
@@ -67,7 +85,7 @@ conservative:
67
85
  deadband: 0.03
68
86
  min_abs_adjust: 0.02
69
87
  max_scale_step: 0.015
70
- min_effect_lognll: 0.0018
88
+ min_effect_lognll: 0.016
71
89
  predictive_one_sided: false
72
90
  topk_backstop: 0
73
91
  max_adjusted_modules: 0
@@ -78,24 +96,25 @@ conservative:
78
96
  deadband: 0.05
79
97
  scope: ffn
80
98
  max_caps: 3
99
+ max_spectral_norm: null
81
100
  family_caps:
82
- ffn: 2.3
101
+ ffn: 3.849
83
102
  attn: 2.6
84
103
  embed: 2.8
85
104
  other: 2.8
86
105
  multiple_testing:
87
106
  method: bonferroni
88
- alpha: 0.02
107
+ alpha: 0.000625
89
108
  m: 4
90
109
  rmt_guard:
91
110
  deadband: 0.05
92
111
  margin: 1.3
93
- epsilon_default: 0.06
112
+ epsilon_default: 0.01
94
113
  epsilon_by_family:
95
- ffn: 0.06
96
- attn: 0.05
97
- embed: 0.07
98
- other: 0.07
114
+ ffn: 0.01
115
+ attn: 0.01
116
+ embed: 0.01
117
+ other: 0.01
99
118
 
100
119
  aggressive:
101
120
  metrics:
@@ -104,6 +123,13 @@ aggressive:
104
123
  min_tokens: 50000
105
124
  hysteresis_ratio: 0.002
106
125
  min_token_fraction: 0.01
126
+ pm_tail:
127
+ mode: warn
128
+ min_windows: 50
129
+ quantile: 0.95
130
+ quantile_max: 0.30
131
+ epsilon: 0.0001
132
+ mass_max: 1.0
107
133
  accuracy:
108
134
  delta_min_pp: -2.0
109
135
  min_examples: 200
@@ -111,27 +137,28 @@ aggressive:
111
137
  min_examples_fraction: 0.01
112
138
  variance_guard:
113
139
  deadband: 0.12
114
- min_effect_lognll: 0.0005
140
+ min_effect_lognll: 0.033
115
141
  spectral_guard:
116
142
  sigma_quantile: 0.98
117
143
  deadband: 0.15
118
144
  scope: ffn
119
145
  max_caps: 8
146
+ max_spectral_norm: null
120
147
  family_caps:
121
- ffn: 3.0
148
+ ffn: 3.849
122
149
  attn: 3.5
123
150
  embed: 2.5
124
151
  other: 3.5
125
152
  multiple_testing:
126
153
  method: bh
127
- alpha: 0.1
154
+ alpha: 0.00078125
128
155
  m: 4
129
156
  rmt_guard:
130
157
  deadband: 0.15
131
158
  margin: 1.8
132
- epsilon_default: 0.15
159
+ epsilon_default: 0.01
133
160
  epsilon_by_family:
134
- ffn: 0.15
135
- attn: 0.15
136
- embed: 0.15
137
- other: 0.15
161
+ ffn: 0.01
162
+ attn: 0.01
163
+ embed: 0.01
164
+ other: 0.01
@@ -29,13 +29,11 @@ from .capabilities import (
29
29
  )
30
30
 
31
31
  _LAZY_MAP = {
32
- "HF_BERT_Adapter": ".hf_bert",
33
- "HF_GPT2_Adapter": ".hf_gpt2",
34
- "HF_LLaMA_Adapter": ".hf_llama",
35
- "HF_T5_Adapter": ".hf_t5",
36
- "HF_ORT_CausalLM_Adapter": ".hf_onnx",
37
- "HF_Causal_Auto_Adapter": ".auto",
38
- "HF_MLM_Auto_Adapter": ".auto",
32
+ "HF_Causal_Adapter": ".hf_causal",
33
+ "HF_MLM_Adapter": ".hf_mlm",
34
+ "HF_Seq2Seq_Adapter": ".hf_seq2seq",
35
+ "HF_Causal_ONNX_Adapter": ".hf_causal_onnx",
36
+ "HF_Auto_Adapter": ".auto",
39
37
  }
40
38
 
41
39
 
@@ -76,7 +74,7 @@ class _RemovedComponent:
76
74
  return _RemovedComponent(self._name, self._replacement)
77
75
 
78
76
 
79
- # Placeholders for removed/legacy utilities referenced in tests
77
+ # Placeholders for removed utilities referenced in tests
80
78
  HF_Pythia_Adapter = _RemovedComponent("HF_Pythia_Adapter")
81
79
  auto_tune_pruning_budget = _RemovedComponent("auto_tune_pruning_budget")
82
80
  run_auto_invarlock = _RemovedComponent("run_auto_invarlock")
@@ -91,13 +89,11 @@ run_invarlock = _RemovedComponent("run_invarlock", "invarlock.cli.run")
91
89
  quick_prune_gpt2 = _RemovedComponent("quick_prune_gpt2")
92
90
 
93
91
  __all__ = [
94
- "HF_GPT2_Adapter",
95
- "HF_BERT_Adapter",
96
- "HF_LLaMA_Adapter",
97
- "HF_T5_Adapter",
98
- "HF_ORT_CausalLM_Adapter",
99
- "HF_Causal_Auto_Adapter",
100
- "HF_MLM_Auto_Adapter",
92
+ "HF_Causal_Adapter",
93
+ "HF_MLM_Adapter",
94
+ "HF_Seq2Seq_Adapter",
95
+ "HF_Causal_ONNX_Adapter",
96
+ "HF_Auto_Adapter",
101
97
  "BaseAdapter",
102
98
  "AdapterConfig",
103
99
  "AdapterInterface",
@@ -110,21 +110,26 @@ class _DelegatingAdapter(ModelAdapter):
110
110
 
111
111
  def _load_adapter(self, adapter_name: str) -> ModelAdapter:
112
112
  """Load an adapter by name."""
113
- if adapter_name == "hf_llama":
114
- HF_LLaMA_Adapter = _importlib.import_module(
115
- ".hf_llama", __package__
116
- ).HF_LLaMA_Adapter
117
- return HF_LLaMA_Adapter()
118
- elif adapter_name == "hf_bert":
119
- HF_BERT_Adapter = _importlib.import_module(
120
- ".hf_bert", __package__
121
- ).HF_BERT_Adapter
122
- return HF_BERT_Adapter()
123
- elif adapter_name == "hf_gpt2":
124
- HF_GPT2_Adapter = _importlib.import_module(
125
- ".hf_gpt2", __package__
126
- ).HF_GPT2_Adapter
127
- return HF_GPT2_Adapter()
113
+ if adapter_name == "hf_causal":
114
+ HF_Causal_Adapter = _importlib.import_module(
115
+ ".hf_causal", __package__
116
+ ).HF_Causal_Adapter
117
+ return HF_Causal_Adapter()
118
+ if adapter_name == "hf_mlm":
119
+ HF_MLM_Adapter = _importlib.import_module(
120
+ ".hf_mlm", __package__
121
+ ).HF_MLM_Adapter
122
+ return HF_MLM_Adapter()
123
+ if adapter_name == "hf_seq2seq":
124
+ HF_Seq2Seq_Adapter = _importlib.import_module(
125
+ ".hf_seq2seq", __package__
126
+ ).HF_Seq2Seq_Adapter
127
+ return HF_Seq2Seq_Adapter()
128
+ if adapter_name == "hf_causal_onnx":
129
+ HF_Causal_ONNX_Adapter = _importlib.import_module(
130
+ ".hf_causal_onnx", __package__
131
+ ).HF_Causal_ONNX_Adapter
132
+ return HF_Causal_ONNX_Adapter()
128
133
  elif adapter_name == "hf_bnb":
129
134
  HF_BNB_Adapter = _importlib.import_module(
130
135
  "invarlock.plugins.hf_bnb_adapter"
@@ -141,11 +146,11 @@ class _DelegatingAdapter(ModelAdapter):
141
146
  ).HF_GPTQ_Adapter
142
147
  return HF_GPTQ_Adapter()
143
148
  else:
144
- # Default to GPT2 adapter
145
- HF_GPT2_Adapter = _importlib.import_module(
146
- ".hf_gpt2", __package__
147
- ).HF_GPT2_Adapter
148
- return HF_GPT2_Adapter()
149
+ # Default to causal adapter
150
+ HF_Causal_Adapter = _importlib.import_module(
151
+ ".hf_causal", __package__
152
+ ).HF_Causal_Adapter
153
+ return HF_Causal_Adapter()
149
154
 
150
155
  def _ensure_delegate_from_id(self, model_id: str) -> ModelAdapter:
151
156
  if self._delegate is not None:
@@ -172,14 +177,16 @@ class _DelegatingAdapter(ModelAdapter):
172
177
  self._delegate = self._load_adapter(quant_adapter)
173
178
  return self._delegate
174
179
 
175
- # Fall back to class name inspection
180
+ # Fall back to lightweight class-name inspection (no transformers import).
176
181
  cls_name = getattr(model, "__class__", type(model)).__name__.lower()
177
- if any(k in cls_name for k in ["llama", "mistral", "qwen", "yi"]):
178
- self._delegate = self._load_adapter("hf_llama")
179
- elif any(k in cls_name for k in ["bert", "roberta", "albert", "deberta"]):
180
- self._delegate = self._load_adapter("hf_bert")
182
+ if any(k in cls_name for k in ["bert", "roberta", "albert", "deberta"]):
183
+ self._delegate = self._load_adapter("hf_mlm")
181
184
  else:
182
- self._delegate = self._load_adapter("hf_gpt2")
185
+ cfg = getattr(model, "config", None)
186
+ if getattr(cfg, "is_encoder_decoder", False):
187
+ self._delegate = self._load_adapter("hf_seq2seq")
188
+ else:
189
+ self._delegate = self._load_adapter("hf_causal")
183
190
  return self._delegate
184
191
 
185
192
  def can_handle(self, model: Any) -> bool: # pragma: no cover - trivial
@@ -206,21 +213,9 @@ class _DelegatingAdapter(ModelAdapter):
206
213
  raise AttributeError(item)
207
214
 
208
215
 
209
- class HF_Causal_Auto_Adapter(_DelegatingAdapter):
210
- name = "hf_causal_auto"
216
+ class HF_Auto_Adapter(_DelegatingAdapter):
217
+ name = "hf_auto"
211
218
 
212
219
  def load_model(self, model_id: str, device: str = "auto", **kwargs: Any) -> Any:
213
220
  delegate = self._ensure_delegate_from_id(model_id)
214
221
  return delegate.load_model(model_id, device=device, **kwargs)
215
-
216
-
217
- class HF_MLM_Auto_Adapter(_DelegatingAdapter):
218
- name = "hf_mlm_auto"
219
-
220
- def load_model(self, model_id: str, device: str = "auto", **kwargs: Any) -> Any:
221
- # Force BERT-like adapter for MLM families
222
- HF_BERT_Adapter = _importlib.import_module(
223
- ".hf_bert", __package__
224
- ).HF_BERT_Adapter
225
- self._delegate = HF_BERT_Adapter()
226
- return self._delegate.load_model(model_id, device=device, **kwargs)
@@ -359,7 +359,7 @@ def _detect_weight_tying(model: Any) -> dict[str, str]:
359
359
  tying: dict[str, str] = {}
360
360
 
361
361
  # Common weight tying patterns
362
- # LLaMA/Mistral: lm_head.weight ↔ model.embed_tokens.weight
362
+ # Decoder embed_tokens style: lm_head.weight ↔ model.embed_tokens.weight
363
363
  if hasattr(model, "lm_head") and hasattr(model, "model"):
364
364
  inner = model.model
365
365
  if hasattr(inner, "embed_tokens"):
@@ -408,7 +408,7 @@ def _detect_primary_metric(model: Any) -> str:
408
408
  return "rouge"
409
409
  return "ppl_seq2seq"
410
410
 
411
- # Decoder-only models (GPT-like, LLaMA-like)
411
+ # Decoder-only models (GPT-like, RoPE-style)
412
412
  return "ppl_causal"
413
413
 
414
414