margin 0.9.7__tar.gz → 0.9.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of margin might be problematic. Click here for more details.
- {margin-0.9.7/margin.egg-info → margin-0.9.8}/PKG-INFO +1 -1
- {margin-0.9.7 → margin-0.9.8}/margin/policy/validate.py +26 -0
- {margin-0.9.7 → margin-0.9.8}/margin/streaming.py +15 -0
- {margin-0.9.7 → margin-0.9.8/margin.egg-info}/PKG-INFO +1 -1
- {margin-0.9.7 → margin-0.9.8}/pyproject.toml +1 -1
- {margin-0.9.7 → margin-0.9.8}/tests/test_policy_validate.py +38 -0
- {margin-0.9.7 → margin-0.9.8}/LICENSE +0 -0
- {margin-0.9.7 → margin-0.9.8}/NOTICE +0 -0
- {margin-0.9.7 → margin-0.9.8}/README.md +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/__init__.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/__main__.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/algebra.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/anomaly.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/bridge.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/calibrate.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/causal.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/composite.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/confidence.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/config.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/contract.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/correlate.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/diff.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/drift.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/events.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/forecast.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/health.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/intent.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/ledger.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/loop.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/observation.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/persist.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/policy/__init__.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/policy/compose.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/policy/core.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/policy/temporal.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/policy/trace.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/policy/tuning.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/predicates.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/provenance.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/transitions.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/uncertain.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin/validity.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin.egg-info/SOURCES.txt +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin.egg-info/dependency_links.txt +0 -0
- {margin-0.9.7 → margin-0.9.8}/margin.egg-info/top_level.txt +0 -0
- {margin-0.9.7 → margin-0.9.8}/setup.cfg +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_algebra.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_anomaly.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_bridge.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_calibrate.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_causal.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_composite.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_confidence.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_config.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_contract.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_correlate.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_diff.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_drift.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_events.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_forecast.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_health.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_healthcare.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_intent.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_ledger.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_loop.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_neuro.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_observation.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_persist.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_policy.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_policy_compose.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_policy_temporal.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_policy_trace.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_policy_tuning.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_predicates.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_printer3d.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_provenance.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_reverse_bridge.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_ros2.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_staleness.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_streaming.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_transformer.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_transitions.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_uncertain.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_validity.py +0 -0
- {margin-0.9.7 → margin-0.9.8}/tests/test_windowing.py +0 -0
|
@@ -82,6 +82,10 @@ def validate(
|
|
|
82
82
|
5. Missing health coverage (no rule handles ABLATED, DEGRADED, etc.)
|
|
83
83
|
6. Contract coverage (if a contract is provided, check that the
|
|
84
84
|
policy has rules for every component the contract mentions)
|
|
85
|
+
7. Component coverage (if components list provided)
|
|
86
|
+
8. alpha_from_sigma without a constraint floor
|
|
87
|
+
9. min_confidence too high (Parser.parse() defaults to MODERATE, so
|
|
88
|
+
rules with min_confidence >= HIGH may silently never fire)
|
|
85
89
|
|
|
86
90
|
Args:
|
|
87
91
|
policy: the policy to validate
|
|
@@ -146,6 +150,9 @@ def validate(
|
|
|
146
150
|
# 8. alpha_from_sigma without a constraint floor
|
|
147
151
|
_check_alpha_from_sigma(policy, issues)
|
|
148
152
|
|
|
153
|
+
# 9. min_confidence gate too high for default parse behaviour
|
|
154
|
+
_check_min_confidence(policy, issues)
|
|
155
|
+
|
|
149
156
|
return ValidationResult(issues=issues)
|
|
150
157
|
|
|
151
158
|
|
|
@@ -256,3 +263,22 @@ def _check_component_coverage(
|
|
|
256
263
|
issues.append(ValidationIssue(
|
|
257
264
|
"info", "policy",
|
|
258
265
|
f"component '{comp}' has no dedicated rule (no wildcard rules either)"))
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _check_min_confidence(policy: Policy, issues: list[ValidationIssue]) -> None:
|
|
269
|
+
"""
|
|
270
|
+
Warn when a rule's min_confidence gate is above MODERATE.
|
|
271
|
+
|
|
272
|
+
Parser.parse() assigns MODERATE confidence to every observation by
|
|
273
|
+
default (when no per-component confidences dict is passed). A rule
|
|
274
|
+
with min_confidence >= HIGH will therefore silently never fire unless
|
|
275
|
+
the caller explicitly passes HIGH or CERTAIN confidences on every step.
|
|
276
|
+
"""
|
|
277
|
+
for rule in policy.rules:
|
|
278
|
+
if rule.min_confidence >= Confidence.HIGH:
|
|
279
|
+
issues.append(ValidationIssue(
|
|
280
|
+
"warning", rule.name,
|
|
281
|
+
f"min_confidence={rule.min_confidence.value} — Parser.parse() defaults "
|
|
282
|
+
"to MODERATE; this rule will never fire unless the caller explicitly "
|
|
283
|
+
"passes per-component confidences of HIGH or CERTAIN",
|
|
284
|
+
))
|
|
@@ -392,6 +392,21 @@ class Monitor:
|
|
|
392
392
|
anomaly_min_reference: int = 10,
|
|
393
393
|
features: Optional[set] = None,
|
|
394
394
|
):
|
|
395
|
+
"""
|
|
396
|
+
Args:
|
|
397
|
+
parser: Parser configured with baselines and thresholds
|
|
398
|
+
window: base window size for all trackers (overridden per-tracker)
|
|
399
|
+
drift_window: DriftTracker window (overrides ``window``)
|
|
400
|
+
anomaly_window: AnomalyTracker window (overrides ``window``)
|
|
401
|
+
correlation_window: CorrelationTracker window (overrides ``window``)
|
|
402
|
+
window_config: WindowConfig dataclass; overrides named window params
|
|
403
|
+
min_correlation: minimum |r| to include a pair in correlations
|
|
404
|
+
anomaly_min_reference: minimum steps before AnomalyTracker classifies
|
|
405
|
+
features: set of tracker names to enable — ``{"drift"``,
|
|
406
|
+
``"anomaly"``, ``"correlation"}``; ``None`` (default)
|
|
407
|
+
enables all three; ``set()`` disables all.
|
|
408
|
+
``"health"`` is always implied and need not be listed.
|
|
409
|
+
"""
|
|
395
410
|
self.parser = parser
|
|
396
411
|
self.window = window
|
|
397
412
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "margin"
|
|
7
|
-
version = "0.9.
|
|
7
|
+
version = "0.9.8"
|
|
8
8
|
description = "Typed health classification, uncertainty algebra, and correction auditing for any system that measures things and needs to explain what happened."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -151,6 +151,44 @@ class TestComponentCoverage:
|
|
|
151
151
|
assert len(comp_issues) == 0
|
|
152
152
|
|
|
153
153
|
|
|
154
|
+
class TestMinConfidenceCheck:
|
|
155
|
+
def test_high_confidence_gate_warns(self):
|
|
156
|
+
rule = PolicyRule(
|
|
157
|
+
"r", any_degraded(),
|
|
158
|
+
Action(target="*", op=Op.RESTORE, alpha=0.5),
|
|
159
|
+
min_confidence=Confidence.HIGH,
|
|
160
|
+
)
|
|
161
|
+
result = validate(Policy(name="p", rules=[rule]))
|
|
162
|
+
assert any("min_confidence" in i.message or "MODERATE" in i.message
|
|
163
|
+
for i in result.warnings)
|
|
164
|
+
|
|
165
|
+
def test_certain_confidence_gate_warns(self):
|
|
166
|
+
rule = PolicyRule(
|
|
167
|
+
"r", any_degraded(),
|
|
168
|
+
Action(target="*", op=Op.RESTORE, alpha=0.5),
|
|
169
|
+
min_confidence=Confidence.CERTAIN,
|
|
170
|
+
)
|
|
171
|
+
result = validate(Policy(name="p", rules=[rule]))
|
|
172
|
+
assert any("min_confidence" in i.message or "MODERATE" in i.message
|
|
173
|
+
for i in result.warnings)
|
|
174
|
+
|
|
175
|
+
def test_moderate_confidence_gate_no_warn(self):
|
|
176
|
+
rule = PolicyRule(
|
|
177
|
+
"r", any_degraded(),
|
|
178
|
+
Action(target="*", op=Op.RESTORE, alpha=0.5),
|
|
179
|
+
min_confidence=Confidence.MODERATE,
|
|
180
|
+
)
|
|
181
|
+
result = validate(Policy(name="p", rules=[rule]))
|
|
182
|
+
# No warning about min_confidence for MODERATE (default parse behaviour)
|
|
183
|
+
assert not any("MODERATE" in i.message and "min_confidence" in i.message
|
|
184
|
+
for i in result.warnings)
|
|
185
|
+
|
|
186
|
+
def test_low_confidence_gate_no_warn(self):
|
|
187
|
+
rule = _make_rule("r", any_degraded()) # default min_confidence=LOW
|
|
188
|
+
result = validate(Policy(name="p", rules=[rule]))
|
|
189
|
+
assert not any("min_confidence" in i.message for i in result.warnings)
|
|
190
|
+
|
|
191
|
+
|
|
154
192
|
class TestValidationResult:
|
|
155
193
|
def test_valid_when_no_errors(self):
|
|
156
194
|
r = ValidationResult(issues=[])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|