dqal 0.1.0__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.
@@ -0,0 +1,21 @@
1
+ # Changelog
2
+
3
+ All notable changes to DQAL will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] — 2026-09-09
9
+
10
+ ### Added
11
+
12
+ - **Quality Scorer** with three sub-signals: Missingness, Drift (PSI/JS divergence), and Outlier (Isolation Forest / Mahalanobis).
13
+ - **3-tier gating state machine** (`SERVE` / `FLAG` / `ABSTAIN`) with hysteresis dead-band and consecutive confirmation to prevent flapping.
14
+ - **Model-agnostic adapter** wrapping scikit-learn estimators, PyTorch `nn.Module`, and custom callables via `DQAL.predict()`.
15
+ - **Privacy-preserving SQLite telemetry logger** — logs statistical metrics only; raw feature logging disabled by default.
16
+ - **Retraining orchestrator** with minimum data volume, label verification, and validation-gated model promotion with rollback.
17
+ - **Learned Quality Scorer** for training a meta-model on historical quality signals.
18
+ - **Terminal telemetry reporting & SQLite logger** for real-time batch metrics, gating decisions, and selective retraining history.
19
+ - **60-batch degradation benchmark** (`benchmarks/run_benchmark.py`) validating correlation, latency, early warning, and label safety.
20
+ - **CI pipeline** via GitHub Actions across Python 3.10 / 3.11 / 3.12.
21
+ - **YAML-based configuration** (`configs/default_config.yaml`) for weights, thresholds, hysteresis, logging, and retrain policy.
dqal-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DQAL Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
dqal-0.1.0/MANIFEST.in ADDED
@@ -0,0 +1,5 @@
1
+ include LICENSE
2
+ include README.md
3
+ include CHANGELOG.md
4
+ recursive-include configs *.yaml
5
+ recursive-include dqal *.py
dqal-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,269 @@
1
+ Metadata-Version: 2.4
2
+ Name: dqal
3
+ Version: 0.1.0
4
+ Summary: DQAL — Data-Quality-Aware Learning: A real-time, model-agnostic quality assurance and selective retraining framework for ML pipelines.
5
+ Author-email: Pratham Khatri <prathamdkhatri@gmail.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/Pratham1227-beep/dqal
8
+ Project-URL: Repository, https://github.com/Pratham1227-beep/dqal
9
+ Project-URL: Bug Tracker, https://github.com/Pratham1227-beep/dqal/issues
10
+ Project-URL: Changelog, https://github.com/Pratham1227-beep/dqal/blob/main/CHANGELOG.md
11
+ Keywords: machine-learning,data-quality,mlops,drift-detection,model-monitoring
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Classifier: Topic :: Software Development :: Quality Assurance
22
+ Requires-Python: >=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: numpy>=1.23.0
26
+ Requires-Dist: pandas>=1.5.0
27
+ Requires-Dist: scipy>=1.9.0
28
+ Requires-Dist: scikit-learn>=1.1.0
29
+ Requires-Dist: pyyaml>=6.0
30
+ Provides-Extra: torch
31
+ Requires-Dist: torch>=2.0.0; extra == "torch"
32
+ Provides-Extra: viz
33
+ Requires-Dist: matplotlib>=3.6.0; extra == "viz"
34
+ Requires-Dist: seaborn>=0.12.0; extra == "viz"
35
+ Provides-Extra: dev
36
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
37
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
38
+ Provides-Extra: all
39
+ Requires-Dist: torch>=2.0.0; extra == "all"
40
+ Requires-Dist: matplotlib>=3.6.0; extra == "all"
41
+ Requires-Dist: seaborn>=0.12.0; extra == "all"
42
+ Requires-Dist: pytest>=7.0.0; extra == "all"
43
+ Dynamic: license-file
44
+
45
+ # 🛡️ DQAL — Data-Quality-Aware Learning
46
+
47
+ [![DQAL CI](https://github.com/Pratham1227-beep/dqal/actions/workflows/ci.yml/badge.svg)](https://github.com/Pratham1227-beep/dqal)
48
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
49
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
50
+
51
+ > **Real-time, model-agnostic inference quality scoring, 3-tier gating (`SERVE` / `FLAG` / `ABSTAIN`), and selective retraining orchestration.**
52
+
53
+ ---
54
+
55
+ ## 1. Problem Statement
56
+
57
+ Deployed machine learning models fail silently. A model trained on clean, stationary data continues generating overconfident predictions when:
58
+ - **Upstream features drop out** (missing fields, API breaking changes, sensor timeouts)
59
+ - **Input distributions drift** (seasonal shifts, demographic changes, covariate shifts)
60
+ - **Extreme noise/outliers slip through** (hardware faults, corrupted data joins)
61
+
62
+ Traditional monitoring detects these weeks after downstream accuracy degrades. **DQAL** provides a lightweight, inline guardrail layer that inspects each prediction batch in real time, computes an interpretable Quality Score $Q \in [0, 1]$, gates execution, and safely triggers retraining.
63
+
64
+ ---
65
+
66
+ ## 2. System Architecture
67
+
68
+ ```
69
+ ┌─────────────────────────────────────────┐
70
+ Incoming batch → │ 1. QUALITY SCORER │
71
+ of data │ • Missingness (Feature null rates) │
72
+ │ • Drift (Continuous PSI / Cat JS) │
73
+ │ • Outlier (Isolation Forest / Mahala) │
74
+ └────────────────────┬────────────────────┘
75
+ │ Q ∈ [0, 1], Sub-signals
76
+
77
+ ┌─────────────────────────────────────────┐
78
+ │ 2. TRIGGER LOGIC │
79
+ │ • Q > 0.80 → SERVE │
80
+ │ • 0.50 < Q ≤ 0.80 → FLAG │
81
+ │ • Q ≤ 0.50 → ABSTAIN │
82
+ │ • Hysteresis dead-band & confirmation │
83
+ └────────────────────┬────────────────────┘
84
+ │ Decision
85
+ ┌────────────────────┴────────────────────┐
86
+ ▼ ▼
87
+ ┌───────────────────┐ ┌───────────────────┐
88
+ │ 3. WRAPPED MODEL │ │ 4. SQLITE LOGGER │
89
+ │ (Sklearn/PyTorch) │ │ (Privacy-safe: no │
90
+ │ Serve/Abstain │ │ raw PII by def) │
91
+ └───────────────────┘ └─────────┬─────────┘
92
+
93
+
94
+ ┌───────────────────┐
95
+ │ 5. ORCHESTRATOR │
96
+ │ • Volume checks │
97
+ │ • Label gating │
98
+ │ • Val. promotion │
99
+ └─────────┬─────────┘
100
+
101
+
102
+ ┌───────────────────┐
103
+ │ 6. TERMINAL LOGS │
104
+ │ (Real-time stdout │
105
+ │ telemetry & Q) │
106
+ └───────────────────┘
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 3. Key Highlights & Features
112
+
113
+ - **⚡ Model-Agnostic Adapter**: Wraps any `scikit-learn` estimator, `PyTorch nn.Module`, or custom callable without modifying underlying model code.
114
+ - **📊 Interpretable Quality Score $Q$**: Combines Missingness, Population Stability Index (PSI), and Isolation Forest anomaly scores into a single metric $Q \in [0, 1]$.
115
+ - **🚦 3-Tier State Machine with Hysteresis**: Prevents state flapping near threshold boundaries with dead-bands and consecutive confirmation counts.
116
+ - **🔒 Privacy-Preserving Telemetry**: Logs statistical metrics to SQLite; disables raw feature logging by default to prevent PII exposure.
117
+ - **🔄 Validated Retraining & Rollback**: Enforces minimum data volume and verified label availability before retraining. Only promotes candidate models if validation accuracy beats active models.
118
+ - **💻 Terminal-First Telemetry & Inspection**: Real-time command-line logging of $Q$, gating decisions (`SERVE`/`FLAG`/`ABSTAIN`), sub-signal diagnostics, and model transition events directly in terminal output.
119
+
120
+ ---
121
+
122
+ ## 4. Installation & Setup
123
+
124
+ ```bash
125
+ # Clone repository
126
+ git clone https://github.com/Pratham1227-beep/dqal.git
127
+ cd dqal
128
+
129
+ # Install in editable mode with all optional dependencies (visualization, PyTorch, dev)
130
+ pip install -e ".[all]"
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 5. Quickstart Example
136
+
137
+ ### Wrapping a Scikit-Learn Model
138
+
139
+ ```python
140
+ from sklearn.ensemble import RandomForestClassifier
141
+ from sklearn.datasets import load_breast_cancer
142
+ from sklearn.model_selection import train_test_split
143
+ from dqal import DQAL, DQALConfig
144
+
145
+ # 1. Train your baseline model
146
+ data = load_breast_cancer(as_frame=True)
147
+ X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.3, random_state=42)
148
+
149
+ model = RandomForestClassifier(n_estimators=100, random_state=42).fit(X_train, y_train)
150
+
151
+ # 2. Wrap with DQAL and fit baseline distributions
152
+ # CRITICAL: Baseline distributions must be captured from clean training data!
153
+ dqal = DQAL(model=model, model_version="v1.0.0")
154
+ dqal.fit_baseline(X_train)
155
+
156
+ # 3. Predict on incoming batches
157
+ result = dqal.predict(X_test.iloc[:50])
158
+
159
+ print(f"Quality Score Q: {result.Q:.3f}")
160
+ print(f"Gating Decision: {result.decision}") # SERVE, FLAG, or ABSTAIN
161
+ print(f"Sub-signals: {result.signals}")
162
+ print(f"Predictions: {result.predictions[:5]}")
163
+ ```
164
+
165
+ ### Wrapping a PyTorch Model
166
+
167
+ ```python
168
+ import torch
169
+ import torch.nn as nn
170
+ from dqal import DQAL
171
+
172
+ torch_model = nn.Sequential(
173
+ nn.Linear(30, 16),
174
+ nn.ReLU(),
175
+ nn.Linear(16, 2)
176
+ )
177
+
178
+ dqal = DQAL(model=torch_model, model_version="v1.0.0-torch")
179
+ dqal.fit_baseline(X_train)
180
+
181
+ result = dqal.predict(X_test.iloc[:20])
182
+ ```
183
+
184
+ ---
185
+
186
+ ## 6. Configuration (`configs/default_config.yaml`)
187
+
188
+ ```yaml
189
+ weights:
190
+ missingness: 0.30
191
+ drift: 0.40
192
+ outlier: 0.30
193
+
194
+ thresholds:
195
+ abstain_below: 0.50
196
+ flag_below: 0.80
197
+
198
+ hysteresis:
199
+ deadband: 0.03
200
+ consecutive_batches: 2
201
+
202
+ logging:
203
+ db_path: "dqal_telemetry.db"
204
+ log_raw_features: false # Opt-in only
205
+
206
+ retrain:
207
+ min_flagged_batches: 5
208
+ min_samples: 100
209
+ require_labels: true
210
+ min_improvement_delta: 0.01
211
+ ```
212
+
213
+ ---
214
+
215
+ ## 7. Empirical Validation & Benchmarks
216
+
217
+ We evaluated DQAL across a progressive 60-batch degradation simulation (`benchmarks/run_benchmark.py`):
218
+ 1. **Pristine Baseline** (Batches 0–11)
219
+ 2. **Mild Covariate Shift** (Batches 12–23)
220
+ 3. **Missing Fields Spike** (Batches 24–35)
221
+ 4. **Severe Noise & Outliers** (Batches 36–47)
222
+ 5. **Catastrophic Drift** (Batches 48–59)
223
+
224
+ ### Benchmark Results
225
+
226
+ | Metric | Target | DQAL Result | Status |
227
+ | :--- | :--- | :--- | :--- |
228
+ | **Pearson Correlation ($r$)** | $r < -0.70$ or $> 0.70$ | **$r = 0.8502$** ($p = 8.45 \times 10^{-18}$) | Passed |
229
+ | **Inference Overhead** | $< 50$ ms / batch | **$49.79$ ms / batch** | Passed |
230
+ | **Early Warning Lead Time** | $> 0$ batches | **$9$ batches lead time** | Passed |
231
+ | **Label Safety Enforced** | $100\%$ | **Blocked unlabelled retraining** | Passed |
232
+
233
+ ![DQAL Benchmark Results](benchmark_results.png)
234
+
235
+ ---
236
+
237
+ ## 8. Inspecting Telemetry in Terminal
238
+
239
+ DQAL logs structured, privacy-safe metrics per batch to SQLite (`dqal_telemetry.db`) and displays real-time gating decisions and sub-signals in your terminal:
240
+
241
+ ```python
242
+ from dqal.logger import TelemetryLogger
243
+
244
+ # Inspect logged telemetry in terminal
245
+ logger = TelemetryLogger("dqal_telemetry.db")
246
+ df = logger.get_telemetry_df()
247
+ print(df[["batch_id", "Q", "decision", "missing_signal", "drift_signal", "outlier_signal"]].tail(10))
248
+ ```
249
+
250
+ Or query directly using the SQLite CLI:
251
+
252
+ ```bash
253
+ sqlite3 dqal_telemetry.db "SELECT batch_id, Q, decision, model_version FROM predictions_telemetry ORDER BY id DESC LIMIT 10;"
254
+ ```
255
+
256
+ ---
257
+
258
+ ## 9. Running Tests
259
+
260
+ ```bash
261
+ pytest -v
262
+ ```
263
+
264
+ ---
265
+
266
+ ## 10. Known Limitations
267
+
268
+ - **Row vs. Batch Granularity**: Scoring single isolated rows has higher variance due to sample statistics. Batch mode ($\ge 30$ rows) provides robust distribution estimation.
269
+ - **Concept Drift vs. Anomaly**: DQAL detects statistical covariate and quality shift. Distinguishing permanent regime shift from temporary noise is surfaced to operators via the `FLAG` state rather than automated blind retraining.
dqal-0.1.0/README.md ADDED
@@ -0,0 +1,225 @@
1
+ # 🛡️ DQAL — Data-Quality-Aware Learning
2
+
3
+ [![DQAL CI](https://github.com/Pratham1227-beep/dqal/actions/workflows/ci.yml/badge.svg)](https://github.com/Pratham1227-beep/dqal)
4
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ > **Real-time, model-agnostic inference quality scoring, 3-tier gating (`SERVE` / `FLAG` / `ABSTAIN`), and selective retraining orchestration.**
8
+
9
+ ---
10
+
11
+ ## 1. Problem Statement
12
+
13
+ Deployed machine learning models fail silently. A model trained on clean, stationary data continues generating overconfident predictions when:
14
+ - **Upstream features drop out** (missing fields, API breaking changes, sensor timeouts)
15
+ - **Input distributions drift** (seasonal shifts, demographic changes, covariate shifts)
16
+ - **Extreme noise/outliers slip through** (hardware faults, corrupted data joins)
17
+
18
+ Traditional monitoring detects these weeks after downstream accuracy degrades. **DQAL** provides a lightweight, inline guardrail layer that inspects each prediction batch in real time, computes an interpretable Quality Score $Q \in [0, 1]$, gates execution, and safely triggers retraining.
19
+
20
+ ---
21
+
22
+ ## 2. System Architecture
23
+
24
+ ```
25
+ ┌─────────────────────────────────────────┐
26
+ Incoming batch → │ 1. QUALITY SCORER │
27
+ of data │ • Missingness (Feature null rates) │
28
+ │ • Drift (Continuous PSI / Cat JS) │
29
+ │ • Outlier (Isolation Forest / Mahala) │
30
+ └────────────────────┬────────────────────┘
31
+ │ Q ∈ [0, 1], Sub-signals
32
+
33
+ ┌─────────────────────────────────────────┐
34
+ │ 2. TRIGGER LOGIC │
35
+ │ • Q > 0.80 → SERVE │
36
+ │ • 0.50 < Q ≤ 0.80 → FLAG │
37
+ │ • Q ≤ 0.50 → ABSTAIN │
38
+ │ • Hysteresis dead-band & confirmation │
39
+ └────────────────────┬────────────────────┘
40
+ │ Decision
41
+ ┌────────────────────┴────────────────────┐
42
+ ▼ ▼
43
+ ┌───────────────────┐ ┌───────────────────┐
44
+ │ 3. WRAPPED MODEL │ │ 4. SQLITE LOGGER │
45
+ │ (Sklearn/PyTorch) │ │ (Privacy-safe: no │
46
+ │ Serve/Abstain │ │ raw PII by def) │
47
+ └───────────────────┘ └─────────┬─────────┘
48
+
49
+
50
+ ┌───────────────────┐
51
+ │ 5. ORCHESTRATOR │
52
+ │ • Volume checks │
53
+ │ • Label gating │
54
+ │ • Val. promotion │
55
+ └─────────┬─────────┘
56
+
57
+
58
+ ┌───────────────────┐
59
+ │ 6. TERMINAL LOGS │
60
+ │ (Real-time stdout │
61
+ │ telemetry & Q) │
62
+ └───────────────────┘
63
+ ```
64
+
65
+ ---
66
+
67
+ ## 3. Key Highlights & Features
68
+
69
+ - **⚡ Model-Agnostic Adapter**: Wraps any `scikit-learn` estimator, `PyTorch nn.Module`, or custom callable without modifying underlying model code.
70
+ - **📊 Interpretable Quality Score $Q$**: Combines Missingness, Population Stability Index (PSI), and Isolation Forest anomaly scores into a single metric $Q \in [0, 1]$.
71
+ - **🚦 3-Tier State Machine with Hysteresis**: Prevents state flapping near threshold boundaries with dead-bands and consecutive confirmation counts.
72
+ - **🔒 Privacy-Preserving Telemetry**: Logs statistical metrics to SQLite; disables raw feature logging by default to prevent PII exposure.
73
+ - **🔄 Validated Retraining & Rollback**: Enforces minimum data volume and verified label availability before retraining. Only promotes candidate models if validation accuracy beats active models.
74
+ - **💻 Terminal-First Telemetry & Inspection**: Real-time command-line logging of $Q$, gating decisions (`SERVE`/`FLAG`/`ABSTAIN`), sub-signal diagnostics, and model transition events directly in terminal output.
75
+
76
+ ---
77
+
78
+ ## 4. Installation & Setup
79
+
80
+ ```bash
81
+ # Clone repository
82
+ git clone https://github.com/Pratham1227-beep/dqal.git
83
+ cd dqal
84
+
85
+ # Install in editable mode with all optional dependencies (visualization, PyTorch, dev)
86
+ pip install -e ".[all]"
87
+ ```
88
+
89
+ ---
90
+
91
+ ## 5. Quickstart Example
92
+
93
+ ### Wrapping a Scikit-Learn Model
94
+
95
+ ```python
96
+ from sklearn.ensemble import RandomForestClassifier
97
+ from sklearn.datasets import load_breast_cancer
98
+ from sklearn.model_selection import train_test_split
99
+ from dqal import DQAL, DQALConfig
100
+
101
+ # 1. Train your baseline model
102
+ data = load_breast_cancer(as_frame=True)
103
+ X_train, X_test, y_train, y_test = train_test_split(data.data, data.target, test_size=0.3, random_state=42)
104
+
105
+ model = RandomForestClassifier(n_estimators=100, random_state=42).fit(X_train, y_train)
106
+
107
+ # 2. Wrap with DQAL and fit baseline distributions
108
+ # CRITICAL: Baseline distributions must be captured from clean training data!
109
+ dqal = DQAL(model=model, model_version="v1.0.0")
110
+ dqal.fit_baseline(X_train)
111
+
112
+ # 3. Predict on incoming batches
113
+ result = dqal.predict(X_test.iloc[:50])
114
+
115
+ print(f"Quality Score Q: {result.Q:.3f}")
116
+ print(f"Gating Decision: {result.decision}") # SERVE, FLAG, or ABSTAIN
117
+ print(f"Sub-signals: {result.signals}")
118
+ print(f"Predictions: {result.predictions[:5]}")
119
+ ```
120
+
121
+ ### Wrapping a PyTorch Model
122
+
123
+ ```python
124
+ import torch
125
+ import torch.nn as nn
126
+ from dqal import DQAL
127
+
128
+ torch_model = nn.Sequential(
129
+ nn.Linear(30, 16),
130
+ nn.ReLU(),
131
+ nn.Linear(16, 2)
132
+ )
133
+
134
+ dqal = DQAL(model=torch_model, model_version="v1.0.0-torch")
135
+ dqal.fit_baseline(X_train)
136
+
137
+ result = dqal.predict(X_test.iloc[:20])
138
+ ```
139
+
140
+ ---
141
+
142
+ ## 6. Configuration (`configs/default_config.yaml`)
143
+
144
+ ```yaml
145
+ weights:
146
+ missingness: 0.30
147
+ drift: 0.40
148
+ outlier: 0.30
149
+
150
+ thresholds:
151
+ abstain_below: 0.50
152
+ flag_below: 0.80
153
+
154
+ hysteresis:
155
+ deadband: 0.03
156
+ consecutive_batches: 2
157
+
158
+ logging:
159
+ db_path: "dqal_telemetry.db"
160
+ log_raw_features: false # Opt-in only
161
+
162
+ retrain:
163
+ min_flagged_batches: 5
164
+ min_samples: 100
165
+ require_labels: true
166
+ min_improvement_delta: 0.01
167
+ ```
168
+
169
+ ---
170
+
171
+ ## 7. Empirical Validation & Benchmarks
172
+
173
+ We evaluated DQAL across a progressive 60-batch degradation simulation (`benchmarks/run_benchmark.py`):
174
+ 1. **Pristine Baseline** (Batches 0–11)
175
+ 2. **Mild Covariate Shift** (Batches 12–23)
176
+ 3. **Missing Fields Spike** (Batches 24–35)
177
+ 4. **Severe Noise & Outliers** (Batches 36–47)
178
+ 5. **Catastrophic Drift** (Batches 48–59)
179
+
180
+ ### Benchmark Results
181
+
182
+ | Metric | Target | DQAL Result | Status |
183
+ | :--- | :--- | :--- | :--- |
184
+ | **Pearson Correlation ($r$)** | $r < -0.70$ or $> 0.70$ | **$r = 0.8502$** ($p = 8.45 \times 10^{-18}$) | Passed |
185
+ | **Inference Overhead** | $< 50$ ms / batch | **$49.79$ ms / batch** | Passed |
186
+ | **Early Warning Lead Time** | $> 0$ batches | **$9$ batches lead time** | Passed |
187
+ | **Label Safety Enforced** | $100\%$ | **Blocked unlabelled retraining** | Passed |
188
+
189
+ ![DQAL Benchmark Results](benchmark_results.png)
190
+
191
+ ---
192
+
193
+ ## 8. Inspecting Telemetry in Terminal
194
+
195
+ DQAL logs structured, privacy-safe metrics per batch to SQLite (`dqal_telemetry.db`) and displays real-time gating decisions and sub-signals in your terminal:
196
+
197
+ ```python
198
+ from dqal.logger import TelemetryLogger
199
+
200
+ # Inspect logged telemetry in terminal
201
+ logger = TelemetryLogger("dqal_telemetry.db")
202
+ df = logger.get_telemetry_df()
203
+ print(df[["batch_id", "Q", "decision", "missing_signal", "drift_signal", "outlier_signal"]].tail(10))
204
+ ```
205
+
206
+ Or query directly using the SQLite CLI:
207
+
208
+ ```bash
209
+ sqlite3 dqal_telemetry.db "SELECT batch_id, Q, decision, model_version FROM predictions_telemetry ORDER BY id DESC LIMIT 10;"
210
+ ```
211
+
212
+ ---
213
+
214
+ ## 9. Running Tests
215
+
216
+ ```bash
217
+ pytest -v
218
+ ```
219
+
220
+ ---
221
+
222
+ ## 10. Known Limitations
223
+
224
+ - **Row vs. Batch Granularity**: Scoring single isolated rows has higher variance due to sample statistics. Batch mode ($\ge 30$ rows) provides robust distribution estimation.
225
+ - **Concept Drift vs. Anomaly**: DQAL detects statistical covariate and quality shift. Distinguishing permanent regime shift from temporary noise is surfaced to operators via the `FLAG` state rather than automated blind retraining.
@@ -0,0 +1,7 @@
1
+ """
2
+ Benchmark module for DQAL.
3
+ """
4
+ from benchmarks.simulator import DegradationSimulator, DegradationPhase
5
+ from benchmarks.run_benchmark import run_full_benchmark
6
+
7
+ __all__ = ["DegradationSimulator", "DegradationPhase", "run_full_benchmark"]