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
TermDatabin contract. C1–C8 hold exactly. - Approximate mode (any LightGBM booster): per-feature TreeSHAP
attributions (
pred_contrib, noshappackage) 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_gam → TriadExplainer) 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).