Skip to content

Design Decisions

Where the spec (spec.md, TRIAD v0.1) was silent, wrong, or overridden, the resolution is recorded here and in the relevant docstring.

1. Two-mode architecture

The package is model-agnostic with two modes sharing one API:

  • Exact mode (additive models): the decomposition is a reallocation of exact term contributions via the TermData bin contract. C1–C8 hold exactly.
  • Approximate mode (any LightGBM booster): per-feature TreeSHAP attributions (pred_contrib, no shap package) are reallocated into the same channels — the spec's §12 "approximate TRIAD", pulled into v0.1.

Mode is inferred at TriadExplainer construction (additive-constrained model → exact; else → shap) with an explicit mode= override. mode="exact" on a non-additive booster raises. mode="shap" on an additive booster is allowed (the two modes coincide there; see decision 12).

2. Native epistemic variance in GBM packages (research verdict)

Package Native epistemic variance Verdict for TRIAD
CatBoost Yes — SGLB virtual ensembles (posterior_sampling=True + virtual_ensembles_predict) Per-instance η-variance only; not per-feature/per-bin. Roadmap fast-path: K truncated copies via model.copy().shrink(...) → SHAP per copy → per-instance per-feature φ-variance from one training run (members are correlated prefixes; SGLB justifies a posterior reading).
XGBoost No (quantile objectives are aleatoric) Generic bagging.
LightGBM No Generic bagging (triadxai.bagging, default K=8).
AdaBoost (sklearn) No (stages measure convergence, not epistemic spread) Generic bagging.
EBM (interpret) Yes — outer-bag SDs (standard_deviations_) Used directly as per-bin v.

3. Bag disagreement covers density; no OOR decay in approximate mode

In sparse regions each bootstrap replica sees a different handful of points, so split thresholds and leaf values there are pinned by few observations and the replicas' attributions diverge; where thousands of points constrain the fit, replicas agree. Var_k φ_j^{(k)}(x) is therefore a per-instance, score-scale density/extrapolation signal produced by the data itself — it subsumes what exact mode approximates with the heuristic out-of-range decay. Approximate mode therefore applies no OOR decay (the oov flag is still emitted). Exact mode keeps the spec §3.4 decay exp(-λ·dist/IQR).

4. Φ / V provenance

Attributions Φ come from the single deployed model; variance V from bag replicas. C1/C2 therefore hold exactly on the deployed model's attributions; V enters only through the support weight w.

5. C-property status in approximate mode

C1 ✓ (D is the residual of φ), C2 ✓ (TreeSHAP local accuracy; verified ≤ 9e-15), C3 ✓ (v→0 ⇒ D→0), C4 ✓, C5 ✓, C6 ✓, C7 ✓, C8 ✓ with a caveat: a feature absent from all trees gets φ ≡ 0 ⇒ all channels 0; a noise feature that does get trees is handled by τ̂² = 0 ⇒ all-D instead.

Lost vs exact mode (why it must be labelled approximate): φ_j is not a function of x_j alone (interaction effects leak into per-feature attributions via TreeSHAP's path-dependent allocation); no per-bin audit tables (the §4.4 payload becomes per-instance v/w plus per-feature τ̂²); the decomposition depends on the reference population (base value and τ̂²).

6. lightgbm in core dependencies

The default documented workflow (fit_lgbm_gamTriadExplainer) must work after a bare pip install triadxai. Counter-argument recorded: the core contract path (contracts/shrinkage/decompose/reasons) is importable without any booster, so a purist layout would put lightgbm behind a [lgbm] extra like [ebm]. Decision: core dependency; the LightGBM adapter is the flagship. The native lgb.train API is used (not the sklearn wrapper) to avoid a scikit-learn dependency.

7. Bagging K=8 variance noise

Per-instance variance from K=8 replicas is a χ²₇-noisy estimate. τ̂², which averages v over the reference population, stays stable. n_bags is configurable in fit_lgbm_gam and fit_bagged.

8. Flat module layout

Spec §11 proposes sub-packages (core/, adapters/, ...). v0.1 ships nine flat modules (200–400 lines each, mirroring flag-gam); the sub-packages exist to host deferred v0.2+ adapters and can be introduced later without breaking the top-level API.

9. Package name triadxai

The spec's triad-xai / import triad placeholder collides with the PyPI triad package (Fugue project). Distribution and import name are both triadxai.

10. interpret attribute corrections (verified on 0.6.16)

The per-bin SD attribute is standard_deviations_, not term_standard_deviations_ as spec §2.2 states. intercept_ is an ndarray of shape (1,) for binary classifiers, not a float. Out-of-range continuous values clamp to the terminal value bin, not the unknown bin. standard_deviations_ becomes None after monotonize() (adapter raises) and is all-zeros with outer_bags=1 (adapter warns).

11. D computed as residual

D = f − w·f (never (1−w)·f) so C1 holds to float roundoff; tests assert term-level completeness at atol 1e-12.

12. Cross-mode coincidence as an invariant

On an additive-constrained booster, LightGBM's pred_contrib φ_j equals the centered shape value f̃_j(x) to ~1e-14 (verified). The test suite uses this to tie the two pipelines together (test_cross_mode_coincidence, test_shap_mode_on_additive_matches_exact_totals).

13. LightGBM adapter caveats

init_score is rejected (breaks score reconciliation). zero_as_missing models are rejected (unsupported missing_type). Exact mode is main-effects by construction (single-feature trees); interacting LightGBM models go through approximate mode. Unseen categorical levels are routed to the unknown slot whose value equals the missing-path value, mirroring what the pandas prediction pipeline does (unseen level → NaN code). Numeric binning uses searchsorted(thresholds, x, side="left") (LightGBM's x <= thr → left); note EBM's convention differs (side="right" + 1).

14. Pair half-split weakens feature-level C4 (EBM extra)

Under pair_split="half", half of a missing-partner pair's M lands on the observed feature, so "observed ⇒ M=0" holds at term level, not feature level. C1/C4/C5 are asserted at term level for pair-bearing models. LightGBM exact mode has no pairs, so its feature-level C4 is exact.

15. Deferred to v0.2+

Scorecard and pyGAM adapters, pair_split="pooled", portfolio-level global report (§7.2), shape-function profile plots, multiclass models, k_method="cv", threshold-relative baselines (§9.1), CatBoost SGLB fast-path (decision 2), conformal D-channel wrapper (§12).