margin 0.9.17__tar.gz → 0.9.18__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.17/margin.egg-info → margin-0.9.18}/PKG-INFO +1 -1
- {margin-0.9.17 → margin-0.9.18}/margin/fingerprint.py +16 -8
- {margin-0.9.17 → margin-0.9.18/margin.egg-info}/PKG-INFO +1 -1
- {margin-0.9.17 → margin-0.9.18}/pyproject.toml +1 -1
- {margin-0.9.17 → margin-0.9.18}/tests/test_controller.py +16 -2
- {margin-0.9.17 → margin-0.9.18}/LICENSE +0 -0
- {margin-0.9.17 → margin-0.9.18}/NOTICE +0 -0
- {margin-0.9.17 → margin-0.9.18}/README.md +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/__init__.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/__main__.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/algebra.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/anomaly.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/bridge.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/calibrate.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/causal.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/composite.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/confidence.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/config.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/contract.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/controller.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/correlate.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/diff.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/drift.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/events.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/forecast.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/health.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/intent.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/ledger.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/loop.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/observation.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/persist.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/policy/__init__.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/policy/compose.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/policy/core.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/policy/temporal.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/policy/trace.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/policy/tuning.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/policy/validate.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/predicates.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/provenance.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/streaming.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/transitions.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/uncertain.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin/validity.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin.egg-info/SOURCES.txt +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin.egg-info/dependency_links.txt +0 -0
- {margin-0.9.17 → margin-0.9.18}/margin.egg-info/top_level.txt +0 -0
- {margin-0.9.17 → margin-0.9.18}/setup.cfg +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_algebra.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_anomaly.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_bridge.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_calibrate.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_causal.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_composite.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_confidence.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_config.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_contract.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_correlate.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_diff.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_drift.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_events.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_forecast.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_health.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_healthcare.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_intent.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_ledger.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_loop.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_neuro.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_observation.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_persist.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_policy.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_policy_compose.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_policy_temporal.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_policy_trace.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_policy_tuning.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_policy_validate.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_predicates.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_printer3d.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_provenance.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_reverse_bridge.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_ros2.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_staleness.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_streaming.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_transformer.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_transitions.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_uncertain.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_validity.py +0 -0
- {margin-0.9.17 → margin-0.9.18}/tests/test_windowing.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: margin
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.18
|
|
4
4
|
Summary: Typed health classification, uncertainty algebra, and correction auditing for any system that measures things and needs to explain what happened.
|
|
5
5
|
Author: Cope Labs LLC
|
|
6
6
|
License: MIT
|
|
@@ -126,23 +126,31 @@ class Fingerprint(dict):
|
|
|
126
126
|
|
|
127
127
|
def sigma(self, component: str, value: float) -> float:
|
|
128
128
|
"""
|
|
129
|
-
|
|
129
|
+
Z-score of ``value`` against the fingerprint's empirical distribution.
|
|
130
130
|
|
|
131
|
-
Returns ``(value − mean) /
|
|
131
|
+
Returns ``(value − mean) / std`` (standard z-score).
|
|
132
132
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
Using ``std`` as denominator is correct for cross-session normalization.
|
|
134
|
+
``|mean|`` would only be appropriate when the coefficient of variation
|
|
135
|
+
(std/|mean|) is small; for high-CV components (e.g. ``std=0.498``,
|
|
136
|
+
``mean=0.070``, CV=7.1) it amplifies by 7×, turning a normal ±0.07
|
|
137
|
+
swing into ±1.0 and saturating the controller.
|
|
136
138
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
+
Falls back to ``(value − mean) / |mean|`` when ``std`` is zero (constant
|
|
140
|
+
window or not yet stored), and returns ``value`` unchanged when both
|
|
141
|
+
``mean`` and ``std`` are zero.
|
|
139
142
|
|
|
140
143
|
Example::
|
|
141
144
|
|
|
142
145
|
metric = fp.sigma("recovery_ratio", cq.recovery_ratio)
|
|
143
146
|
alpha, reason = ctrl.step(alpha, metric)
|
|
144
147
|
"""
|
|
145
|
-
|
|
148
|
+
stats = self.get(component, {})
|
|
149
|
+
mean = stats.get("mean", 0.0)
|
|
150
|
+
std = stats.get("std", 0.0)
|
|
151
|
+
if std != 0.0:
|
|
152
|
+
return (value - mean) / std
|
|
153
|
+
# std=0: constant distribution — fall back to relative deviation
|
|
146
154
|
if mean == 0.0:
|
|
147
155
|
return value
|
|
148
156
|
return (value - mean) / abs(mean)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: margin
|
|
3
|
-
Version: 0.9.
|
|
3
|
+
Version: 0.9.18
|
|
4
4
|
Summary: Typed health classification, uncertainty algebra, and correction auditing for any system that measures things and needs to explain what happened.
|
|
5
5
|
Author: Cope Labs LLC
|
|
6
6
|
License: MIT
|
|
@@ -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.18"
|
|
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"}
|
|
@@ -552,14 +552,28 @@ class TestFingerprintSigma:
|
|
|
552
552
|
|
|
553
553
|
def test_negative_mean(self):
|
|
554
554
|
fp = Fingerprint(stats={"rr": {"mean": -2.0, "std": 0.5, "n": 10, "trend": "STABLE"}})
|
|
555
|
-
# (value - mean) /
|
|
556
|
-
assert fp.sigma("rr", -1.0) == pytest.approx(0
|
|
555
|
+
# z-score: (value - mean) / std = (-1.0 - (-2.0)) / 0.5 = 2.0
|
|
556
|
+
assert fp.sigma("rr", -1.0) == pytest.approx(2.0)
|
|
557
557
|
|
|
558
558
|
def test_missing_component_returns_value(self):
|
|
559
559
|
fp = _make_fp([1.0] * 10)
|
|
560
560
|
# missing → mean=0.0 → returns value unchanged
|
|
561
561
|
assert fp.sigma("missing", 0.7) == pytest.approx(0.7)
|
|
562
562
|
|
|
563
|
+
def test_uses_std_not_mean_as_denominator(self):
|
|
564
|
+
# Regression: Build #29 failure — high-CV component (std=0.498, mean=0.070)
|
|
565
|
+
# Old formula: (value - mean) / |mean| = 0.07 / 0.07 = 1.0 (7× amplification)
|
|
566
|
+
# New formula: (value - mean) / std = 0.07 / 0.498 ≈ 0.141 (sensible z-score)
|
|
567
|
+
fp = Fingerprint(stats={"rr": {"mean": 0.070, "std": 0.498, "n": 98}})
|
|
568
|
+
result = fp.sigma("rr", 0.14)
|
|
569
|
+
assert result == pytest.approx((0.14 - 0.070) / 0.498, rel=1e-4) # z-score
|
|
570
|
+
assert abs(result) < 0.2 # not ±1.0 (the bang-bang range)
|
|
571
|
+
|
|
572
|
+
def test_std_zero_falls_back_to_mean_relative(self):
|
|
573
|
+
# Constant distribution: std=0 → fall back to (value-mean)/|mean|
|
|
574
|
+
fp = Fingerprint(stats={"rr": {"mean": 1.0, "std": 0.0, "n": 5}})
|
|
575
|
+
assert fp.sigma("rr", 1.5) == pytest.approx(0.5) # (1.5-1.0)/1.0
|
|
576
|
+
|
|
563
577
|
|
|
564
578
|
class TestFingerprintPrecomputedPercentiles:
|
|
565
579
|
"""Fingerprints from Monitor.fingerprint() now include median/q25/q75.
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|