credonlabs 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.
Files changed (48) hide show
  1. credonlabs-0.1.0/LICENSE +23 -0
  2. credonlabs-0.1.0/PKG-INFO +435 -0
  3. credonlabs-0.1.0/README.md +392 -0
  4. credonlabs-0.1.0/pyproject.toml +72 -0
  5. credonlabs-0.1.0/setup.cfg +4 -0
  6. credonlabs-0.1.0/src/credonlabs/__init__.py +253 -0
  7. credonlabs-0.1.0/src/credonlabs/accumulators.py +1376 -0
  8. credonlabs-0.1.0/src/credonlabs/adapters.py +517 -0
  9. credonlabs-0.1.0/src/credonlabs/business_logic.py +495 -0
  10. credonlabs-0.1.0/src/credonlabs/cli.py +561 -0
  11. credonlabs-0.1.0/src/credonlabs/client.py +470 -0
  12. credonlabs-0.1.0/src/credonlabs/counterfactual.py +273 -0
  13. credonlabs-0.1.0/src/credonlabs/demo.py +351 -0
  14. credonlabs-0.1.0/src/credonlabs/drift.py +613 -0
  15. credonlabs-0.1.0/src/credonlabs/engine.py +745 -0
  16. credonlabs-0.1.0/src/credonlabs/exceptions.py +157 -0
  17. credonlabs-0.1.0/src/credonlabs/explain.py +682 -0
  18. credonlabs-0.1.0/src/credonlabs/fairness.py +538 -0
  19. credonlabs-0.1.0/src/credonlabs/freeai.py +395 -0
  20. credonlabs-0.1.0/src/credonlabs/groups.py +336 -0
  21. credonlabs-0.1.0/src/credonlabs/inspector.py +1080 -0
  22. credonlabs-0.1.0/src/credonlabs/model_card.py +770 -0
  23. credonlabs-0.1.0/src/credonlabs/pii.py +341 -0
  24. credonlabs-0.1.0/src/credonlabs/publish.py +698 -0
  25. credonlabs-0.1.0/src/credonlabs/readers.py +425 -0
  26. credonlabs-0.1.0/src/credonlabs/reasons.py +414 -0
  27. credonlabs-0.1.0/src/credonlabs/registry.py +808 -0
  28. credonlabs-0.1.0/src/credonlabs/runner.py +1450 -0
  29. credonlabs-0.1.0/src/credonlabs/scan.py +1079 -0
  30. credonlabs-0.1.0/src/credonlabs/stability.py +423 -0
  31. credonlabs-0.1.0/src/credonlabs/statistical.py +735 -0
  32. credonlabs-0.1.0/src/credonlabs/suite.py +976 -0
  33. credonlabs-0.1.0/src/credonlabs/tasks.py +590 -0
  34. credonlabs-0.1.0/src/credonlabs.egg-info/PKG-INFO +435 -0
  35. credonlabs-0.1.0/src/credonlabs.egg-info/SOURCES.txt +46 -0
  36. credonlabs-0.1.0/src/credonlabs.egg-info/dependency_links.txt +1 -0
  37. credonlabs-0.1.0/src/credonlabs.egg-info/entry_points.txt +2 -0
  38. credonlabs-0.1.0/src/credonlabs.egg-info/requires.txt +28 -0
  39. credonlabs-0.1.0/src/credonlabs.egg-info/top_level.txt +1 -0
  40. credonlabs-0.1.0/tests/test_drift_and_suite.py +390 -0
  41. credonlabs-0.1.0/tests/test_fairness_and_explain.py +513 -0
  42. credonlabs-0.1.0/tests/test_inspector_and_run.py +627 -0
  43. credonlabs-0.1.0/tests/test_pii.py +186 -0
  44. credonlabs-0.1.0/tests/test_publish.py +677 -0
  45. credonlabs-0.1.0/tests/test_registry.py +372 -0
  46. credonlabs-0.1.0/tests/test_statistical.py +210 -0
  47. credonlabs-0.1.0/tests/test_streaming.py +904 -0
  48. credonlabs-0.1.0/tests/test_validation_tests.py +312 -0
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2026 Credon Labs. All rights reserved.
2
+
3
+ This software and its source code are proprietary and confidential.
4
+
5
+ Use is permitted only by parties holding a valid written licence
6
+ agreement with Credon Labs, and only within the scope of that
7
+ agreement. No right is granted to copy, modify, distribute,
8
+ sublicense, reverse engineer, or create derivative works, except
9
+ where such a right cannot lawfully be excluded.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
12
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
13
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
14
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
15
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
16
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
18
+ OTHER DEALINGS IN THE SOFTWARE.
19
+
20
+ Model Risk Management outputs produced by this software are
21
+ decision-support material. They do not constitute regulatory
22
+ approval, and responsibility for any lending decision remains
23
+ with the licensee.
@@ -0,0 +1,435 @@
1
+ Metadata-Version: 2.4
2
+ Name: credonlabs
3
+ Version: 0.1.0
4
+ Summary: Credon Labs Model Risk Management SDK — validation, drift, explainability, fairness and RBI FREE-AI reporting for credit models.
5
+ Author: Credon Labs Engineering
6
+ License-Expression: LicenseRef-Proprietary
7
+ Project-URL: Homepage, https://credonlabs.com
8
+ Project-URL: Documentation, https://credonlabs.com
9
+ Project-URL: Issues, https://credonlabs.com
10
+ Keywords: model-risk-management,mrm,credit-risk,free-ai,rbi,explainability,drift,fairness
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Financial and Insurance Industry
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: numpy>=1.24
21
+ Requires-Dist: pandas>=2.0
22
+ Requires-Dist: scikit-learn>=1.3
23
+ Requires-Dist: scipy>=1.10
24
+ Provides-Extra: shap
25
+ Requires-Dist: shap>=0.44; extra == "shap"
26
+ Provides-Extra: http
27
+ Requires-Dist: requests>=2.31; extra == "http"
28
+ Provides-Extra: parquet
29
+ Requires-Dist: pyarrow>=14.0; extra == "parquet"
30
+ Provides-Extra: onnx
31
+ Requires-Dist: onnxruntime>=1.16; extra == "onnx"
32
+ Provides-Extra: all
33
+ Requires-Dist: shap>=0.44; extra == "all"
34
+ Requires-Dist: requests>=2.31; extra == "all"
35
+ Requires-Dist: pyarrow>=14.0; extra == "all"
36
+ Provides-Extra: dev
37
+ Requires-Dist: shap>=0.44; extra == "dev"
38
+ Requires-Dist: requests>=2.31; extra == "dev"
39
+ Requires-Dist: pyarrow>=14.0; extra == "dev"
40
+ Requires-Dist: pytest>=7.4; extra == "dev"
41
+ Requires-Dist: build>=1.0; extra == "dev"
42
+ Dynamic: license-file
43
+
44
+ # credonlabs
45
+
46
+ Model Risk Management SDK for Indian lenders — validation, drift monitoring, explainability, fairness testing and RBI FREE-AI reporting for credit models.
47
+
48
+
49
+ ```bash
50
+ pip install credonlabs
51
+ ```
52
+
53
+ Everything runs locally. The HTTP client is optional and is only needed to push results to the hosted platform.
54
+
55
+ **Handles any model type and any dataset size.** Binary, multiclass and regression; scikit-learn, XGBoost, LightGBM, CatBoost, ONNX, PyTorch, or any callable. Datasets stream in constant memory — measured at **11.2 MB peak whether the input is 100 thousand rows or 10 million**.
56
+
57
+ ---
58
+
59
+ ## Two entry points
60
+
61
+ | | `run()` | `scan()` |
62
+ |---|---|---|
63
+ | Data | fits in memory | any size, streamed |
64
+ | Passes | one, in memory | one, batched |
65
+ | Model | required | optional |
66
+ | Stages | all 12 | metrics, drift, fairness exact; explainability on a sample |
67
+
68
+ ```python
69
+ credonlabs.run(model="model.joblib", data="validation.csv", target="default_flag")
70
+
71
+ credonlabs.scan(data="scores/*.parquet", target="default_flag", scores="score")
72
+ ```
73
+
74
+ `scan()` with `scores=` loads **no model at all** — metrics, drift, calibration and fairness need only what the model produced, not the model itself. That is what makes a 100GB model workable: your scoring layer already wrote the scores, so the SDK reads them.
75
+
76
+ ---
77
+
78
+ ## Quick start
79
+
80
+ ```python
81
+ import credonlabs
82
+
83
+ report = credonlabs.validate(
84
+ model=model, # any fitted sklearn-compatible estimator
85
+ X=X_val, # validation features (DataFrame)
86
+ y=y_val, # observed outcomes
87
+ model_name="personal_loan_pd",
88
+ version="1.0.0",
89
+ owner="Risk Team",
90
+ business_purpose="Unsecured personal loan underwriting",
91
+ criticality="tier_1",
92
+ )
93
+
94
+ print(credonlabs.summarise(report))
95
+ print(report["verdict"]) # approved | approved_with_conditions | not_approved
96
+ print(report["model_card"]) # RBI-inspection-ready Markdown
97
+ ```
98
+
99
+ One call runs every stage. Each is independent: a stage whose inputs are missing reports itself as unavailable rather than aborting the run, so a partial validation still produces usable evidence.
100
+
101
+ ### See it work on generated data
102
+
103
+ ```bash
104
+ credonlabs demo
105
+ ```
106
+
107
+ Generates a labelled dataset with real signal, trains a model, and runs the whole suite. Writes only inside `./credonlabs_demo`.
108
+
109
+ ---
110
+
111
+ ## What it does
112
+
113
+ | Stage | Requirement | Output |
114
+ |---|---|---|
115
+ | **PII boundary** | NFR-013 | Rejects PAN, Aadhaar, phone, email, IFSC, voter ID |
116
+ | **Registry** | FR-MRM-001…004 | Immutable versioning, criticality tiers, approval workflow |
117
+ | **Statistical battery** | FR-MRM-010 | AUC, KS, Gini, Brier, PSI + bootstrap CIs + calibration |
118
+ | **Business-logic tests** | FR-MRM-011 | Monotonicity, sign and bound constraints |
119
+ | **Stability** | FR-MRM-012 | Perturbation, feature dropout, adversarial noise |
120
+ | **Validation report** | FR-MRM-013 | Signed, inspection-format Markdown |
121
+ | **Data drift** | FR-MRM-020 | Per-feature PSI, alerts at 0.10 / 0.25 |
122
+ | **Concept drift** | FR-MRM-021 | AUC/KS decay, 5-point revalidation trigger |
123
+ | **Alerting** | FR-MRM-022 | Per-model thresholds and routing |
124
+ | **Explainability** | FR-MRM-030/031 | TreeSHAP / KernelSHAP, seven feature groups |
125
+ | **Counterfactuals** | FR-MRM-032 | "If X were Y, the score would change by Z" |
126
+ | **Bias & fairness** | FR-MRM-040/041 | Demographic parity, equal opportunity, average odds, incidents |
127
+ | **Model card** | FR-MRM-050 | Purpose, performance, bias, limitations, history |
128
+ | **FREE-AI mapping** | FR-MRM-051 | 7 Sutras × 6 Pillars, with honest coverage gaps |
129
+ | **Plain-language reasons** | FR-MRM-060 | Jargon-free borrower explanations |
130
+
131
+ ---
132
+
133
+ ## Big data and big models
134
+
135
+ ### Stream a sharded dataset
136
+
137
+ ```python
138
+ report = credonlabs.scan(
139
+ data="s3_export/scores/", # CSV, Parquet, directory, or glob
140
+ target="default_flag",
141
+ scores="score", # no model loaded
142
+ baseline="baseline.json", # enables drift
143
+ protected=["age_band"],
144
+ batch_rows=100_000,
145
+ )
146
+ ```
147
+
148
+ Only the columns a stage needs are read. On a wide Parquet table that alone removes most of the bytes on disk.
149
+
150
+ ### Reference profiles
151
+
152
+ Do not re-read the training set every day. Summarise it once:
153
+
154
+ ```python
155
+ credonlabs.profile(data="train/", target="default_flag", out="baseline.json")
156
+ ```
157
+
158
+ 30,000 rows becomes a **4.8 KB** file of bin edges and counts. Daily monitoring compares against that:
159
+
160
+ ```python
161
+ credonlabs.compare(data="today/", baseline="baseline.json")
162
+ ```
163
+
164
+ ### How the streaming metrics stay exact
165
+
166
+ Every metric decomposes into a single pass:
167
+
168
+ | Metric | Accumulated state | Memory |
169
+ |---|---|---|
170
+ | AUC, KS, Gini | score histogram × {pos, neg} | O(bins) |
171
+ | Brier | running Σ(p−y)² | O(1) |
172
+ | Calibration | per-bin Σp, Σy, n | O(bins) |
173
+ | PSI | bin counts vs stored edges | O(features × bins) |
174
+ | Bias | counters per (group, decision, outcome) | O(groups) |
175
+ | Regression | running sums of error and y² | O(1) |
176
+
177
+ Brier and the regression metrics are **exact**. AUC from a 10,000-bin histogram matches `sklearn.roc_auc_score` to **six decimal places** — verified in `tests/test_streaming.py` against the same data. The bin count is recorded in every report so a reviewer can see the resolution.
178
+
179
+ Feeding data in different batch sizes produces bit-identical results, and partial histograms `merge()`, so parallel readers are safe.
180
+
181
+ ---
182
+
183
+ ## Model types
184
+
185
+ | Task | Metrics | Fairness |
186
+ |---|---|---|
187
+ | **Binary** | AUC, KS, Gini, Brier, calibration | selection-rate parity, equal opportunity, average odds |
188
+ | **Multiclass** | macro AUC (OvR), accuracy, log loss, confusion | selection-rate parity |
189
+ | **Regression** | RMSE, MAE, R², MAPE, residuals | prediction parity, group error gaps |
190
+
191
+ The task is detected from the model and the outcome column; the outcome wins, because a classifier scored against a continuous target is a mistake to catch, not a configuration to honour. Override with `task="regression"`.
192
+
193
+ Fairness changes shape per task deliberately. Selection-rate parity is meaningless for a regression — there the question is whether groups receive systematically different predictions and whether the model is systematically less accurate for one of them.
194
+
195
+ ## Model adapters
196
+
197
+ ```python
198
+ from credonlabs import SklearnAdapter, CallableAdapter, ScoreColumnAdapter, OnnxAdapter, TorchAdapter
199
+ ```
200
+
201
+ | Adapter | For |
202
+ |---|---|
203
+ | `SklearnAdapter` | sklearn, XGBoost, LightGBM, CatBoost wrappers |
204
+ | `ScoreColumnAdapter` | no model — scores already in the data |
205
+ | `CallableAdapter` | any function, a queue, a remote endpoint |
206
+ | `OnnxAdapter` | ONNX Runtime |
207
+ | `TorchAdapter` | PyTorch, eval mode, batched, device-aware |
208
+
209
+ Chosen automatically; pass one explicitly to override. A score column always wins over a model, because re-running a large model to get numbers you already have is the expensive mistake.
210
+
211
+ ---
212
+
213
+ ## The pieces individually
214
+
215
+ ### Statistical battery
216
+
217
+ ```python
218
+ from credonlabs import statistical
219
+
220
+ result = statistical.run_battery(
221
+ y_true=y_val,
222
+ y_score=scores,
223
+ baseline_scores=training_scores, # enables PSI
224
+ )
225
+
226
+ result["auc"] # 0.9810
227
+ result["confidence_intervals"]["auc"] # {'lower': 0.97, 'upper': 0.99, ...}
228
+ result["calibration"]["mean_absolute_calibration_error"]
229
+ ```
230
+
231
+ ### Business-logic constraints
232
+
233
+ Catches the defect a purely statistical battery cannot see: a model can hold an AUC of 0.85 while still *lowering* creditworthiness as income rises.
234
+
235
+ ```python
236
+ from credonlabs import MonotonicConstraint, SignConstraint, BoundConstraint
237
+
238
+ constraints = [
239
+ MonotonicConstraint(feature="verified_monthly_income", direction="decreasing"),
240
+ SignConstraint(feature="emi_bounces_12m", expected_sign="positive"),
241
+ BoundConstraint(feature="credit_score", minimum=300, maximum=900),
242
+ ]
243
+
244
+ report = credonlabs.validate(..., constraints=constraints)
245
+ ```
246
+
247
+ `direction="decreasing"` means higher income must not increase the probability of default. Violations come back with severity and the exact inputs that triggered them.
248
+
249
+ ### Bias audit
250
+
251
+ ```python
252
+ report = credonlabs.validate(
253
+ ...,
254
+ protected_attributes={"age_band": validation["age_band"]},
255
+ )
256
+
257
+ report["fairness"]["attributes"]["age_band"]["disparate_impact_ratio"] # 0.254
258
+ report["fairness"]["incidents"] # incident records
259
+ ```
260
+
261
+ Ratios outside **0.80–1.25** (the four-fifths rule) raise an incident with affected groups, sample sizes, and the FR-MRM-041 SLA.
262
+
263
+ Protected attributes must arrive already banded — `age_band`, not a date of birth.
264
+
265
+ ### Explainability and borrower reasons
266
+
267
+ ```python
268
+ local = credonlabs.explain_local(model, X_val, row=0)
269
+
270
+ reason = credonlabs.generate_reason(
271
+ group_attribution=local["group_attribution"],
272
+ decision="declined",
273
+ )
274
+
275
+ print(reason["text"])
276
+ print(reason["jargon_check"]) # {'clean': True, 'banned_terms_found': []}
277
+ ```
278
+
279
+ > We were not able to approve this application. The main reasons were that there were missed or late repayments in your recent credit history and you are already repaying a large amount each month relative to what you earn. In your favour, your income was steady and at a comfortable level. You can ask us to look at this decision again if you think something has been recorded incorrectly.
280
+
281
+ Every generated sentence is checked against a banned-terms list — no "SHAP", "percentile", "model", "probability". Templates are data, not code: register a translated set with `reasons.register_locale()` so the lender's legal team owns the wording.
282
+
283
+ ### Counterfactuals
284
+
285
+ ```python
286
+ result = credonlabs.generate_counterfactuals(model, row=0, X=X_val, top_n=3)
287
+
288
+ for entry in result["counterfactuals"]:
289
+ print(entry["statement"])
290
+ ```
291
+
292
+ Searches single-feature, policy-compliant changes only. Age band, pincode tier, gender and employment category are **never** suggested, whatever the caller passes.
293
+
294
+ ### Monitoring
295
+
296
+ ```python
297
+ report = credonlabs.run_monitoring(
298
+ baseline_features=X_train,
299
+ current_features=X_production,
300
+ baseline_scores=scores_train,
301
+ current_scores=scores_production,
302
+ current_outcomes=y_production, # once outcomes arrive
303
+ baseline_metrics={"auc": 0.98, "ks": 0.89},
304
+ )
305
+
306
+ report["alert_level"] # ok | warning | critical
307
+ report["data_drift"]["drifted_features"]
308
+ report["concept_drift"]["revalidation_required"]
309
+ ```
310
+
311
+ The three signals become available at different times — features first, scores next, outcomes last — so each section runs only when its inputs are present.
312
+
313
+ ### Registry
314
+
315
+ ```python
316
+ store = credonlabs.ModelRegistry("registry.json")
317
+
318
+ store.register(
319
+ model_name="personal_loan_pd",
320
+ version="1.0.0",
321
+ owner="Risk Team",
322
+ criticality="tier_1",
323
+ business_purpose="Underwriting",
324
+ artifact_path="model.joblib", # records SHA-256 + size
325
+ )
326
+
327
+ store.approve("personal_loan_pd", "1.0.0", "priya")
328
+ store.approve("personal_loan_pd", "1.0.0", "ravi") # tier_1 needs two distinct approvers
329
+
330
+ store.diff("personal_loan_pd", "1.0.0", "1.1.0") # what changed between versions
331
+ ```
332
+
333
+ Versions are immutable — re-registering the same version is refused. Tiers can be escalated but never silently downgraded. Deprecation never deletes.
334
+
335
+ ---
336
+
337
+ ## Command line
338
+
339
+ ```bash
340
+ credonlabs validate --model model.joblib --data validation.csv \
341
+ --target default_flag --model-name personal_loan_pd --version 1.0.0 \
342
+ --owner "Risk Team" --purpose "Underwriting" \
343
+ --protected age_band --card model_card.md --out report.json
344
+ ```
345
+
346
+ Exits **non-zero** when the verdict is `not_approved`, so it gates a CI pipeline directly.
347
+
348
+ ```bash
349
+ credonlabs monitor --model model.joblib --baseline train.csv \
350
+ --current production.csv --target default_flag
351
+
352
+ credonlabs registry --registry registry.json --csv inventory.csv
353
+
354
+ credonlabs demo
355
+ ```
356
+
357
+ ---
358
+
359
+ ## Platform client (optional)
360
+
361
+ ```bash
362
+ pip install credonlabs[http]
363
+ ```
364
+
365
+ ```python
366
+ from credonlabs import CredonClient, ClientConfig
367
+
368
+ client = CredonClient(ClientConfig(
369
+ api_key="...",
370
+ lender_tenant_id="nbfc_alpha",
371
+ ))
372
+
373
+ client.register_model(record.to_dict())
374
+ client.submit_validation(model_id, report)
375
+ client.score(features={...}, product_code="personal_loan_unsecured")
376
+ ```
377
+
378
+ `client.score()` runs the PII scrubber **before** the payload leaves the process. Platform errors come back as the same exception classes the SDK raises locally, so you handle one taxonomy:
379
+
380
+ | Exception | Code | HTTP |
381
+ |---|---|---|
382
+ | `SchemaValidationError` | `SCHEMA_VALIDATION_ERROR` | 400 |
383
+ | `PIIDetectedError` | `PII_DETECTED` | 400 |
384
+ | `UnauthorizedError` | `UNAUTHORIZED` | 401 |
385
+ | `TenantAccessDeniedError` | `TENANT_ACCESS_DENIED` | 403 |
386
+ | `IdempotencyConflictError` | `IDEMPOTENCY_CONFLICT` | 409 |
387
+ | `CoverageTooLowError` | `COVERAGE_TOO_LOW` | 422 |
388
+ | `RateLimitedError` | `RATE_LIMITED` | 429 |
389
+ | `ModelUnavailableError` | `MODEL_UNAVAILABLE` | 503 |
390
+
391
+ ---
392
+
393
+ ## Design notes
394
+
395
+ **No PII, ever.** `pii.assert_clean()` rejects a feature vector before it leaves your process. Errors name the *field*, never the value — an error payload can't itself become a leak. Measured floats are exempt from the numeric patterns: the digits of `-0.1321048632913019` contain a ten-digit run that looks like a mobile number, and flagging it would make the scanner useless.
396
+
397
+ **Explainability-first.** The SDK never returns a score with no attribution. Without `shap` it falls back to native importances or standardised coefficients and marks the result `degraded` with the reason — it doesn't silently return nothing.
398
+
399
+ **Honest reporting.** `freeai.coverage_for_report()` marks an obligation as evidenced only if the stage that evidences it actually ran. A validation that skipped the bias audit reports S4 as *not evidenced*, so a lender never claims coverage it hasn't demonstrated. The model card's Limitations section is populated from real findings, not boilerplate.
400
+
401
+ **Verdicts are blocking.** PII in the data, a high-severity business-logic violation, a high-severity bias incident, or no attribution at all all produce `not_approved` for a tier-1 model — not a warning.
402
+
403
+ ---
404
+
405
+ ## Publishing reports to Credon
406
+
407
+ ```python
408
+ credonlabs.run(..., api_key="mrm_...") # or set CREDONLABS_API_KEY
409
+ ```
410
+
411
+ Reports post to `https://api.credonlabs.com` — the endpoint ships with the package, so no integrator's code names a URL. Override with `base_url=` or `CREDONLABS_BASE_URL` for staging or a self-hosted engine.
412
+
413
+ The key is an **MRM key**, created from the dashboard's API keys page or `POST /mrm/keys`. It is separate from the credit-model scoring key: leaking the scoring key must not expose validation reports.
414
+
415
+ Nothing is sent unless a key is supplied.
416
+
417
+ ## Install options
418
+
419
+ ```bash
420
+ pip install credonlabs # core: numpy, pandas, scikit-learn, scipy
421
+ pip install credonlabs[shap] # + SHAP attributions
422
+ pip install credonlabs[parquet] # + Parquet streaming (pyarrow)
423
+ pip install credonlabs[onnx] # + ONNX Runtime scoring
424
+ pip install credonlabs[http] # + platform client
425
+ pip install credonlabs[all]
426
+ pip install credonlabs[dev] # + pytest, build
427
+ ```
428
+
429
+ Requires Python 3.10+.
430
+
431
+ ## Tests
432
+
433
+ ```bash
434
+ pytest tests/ -q
435
+ ```