Skip to content

Tuning sweeps, band efficiency, exact scorecards, tuning guide + FAQ - #6

Merged
orgoca merged 2 commits into
mainfrom
feat/tuning-scorecard
Aug 16, 2026
Merged

Tuning sweeps, band efficiency, exact scorecards, tuning guide + FAQ#6
orgoca merged 2 commits into
mainfrom
feat/tuning-scorecard

Conversation

@orgoca

@orgoca orgoca commented Aug 16, 2026

Copy link
Copy Markdown
Owner

The configuration questions users face, answered with measured tools instead of rules of thumb.

The organizing idea

The two whitebox knobs are not symmetric. n_estimators buys fidelity at a linear cost in size and explain time and never costs a guarantee; max_depth is the knob that takes exact attribution (and the scorecard) away above 2. Spend on trees, be stingy with depth — and the new tooling turns that from advice into tables.

What's in

compileml.tunesweep_whitebox (trees × depth grid: holdout Gini retention, Spearman vs teacher, exact_attribution, quantized size, measured per-row explain cost) and sweep_bands (K grid: ordinal-Gini retention, Gini gap, worst within-band AUC + verdict, min volume, monotonicity violations, integer-edge collisions).

compileml.bands.band_efficiency — the money-on-the-table diagnostic: the Gini gap your ladder discards, plus per-band within-band AUC with bootstrap CIs and refinable / exhausted / inconclusive verdicts. Validation check 4 now carries banding_gini_gap and worst_within_band_auc whenever outcomes are supplied — advisory by default, hard-gateable via max_within_band_auc=.

compileml.scorecard (stdlib-only) — at depth ≤ 2 the artifact collapses into an exact points scorecard: bin → points tables plus pairwise interaction grids whose integers re-sum to every decision's raw_micro bit-for-bit. score_from_scorecard re-derives any decision from the printed tables alone — asserted on 300 rows at depths 1 and 2 — so a validator can reproduce production scores in a spreadsheet. Markdown/CSV renderers and a compileml scorecard CLI subcommand; refuses above depth 2 rather than approximating (the same boundary as exact attribution, same reason).

One math subtlety the tests caught: a depth-2 tree can reference three features (root + a different one per child). Exactness survives — depth-2 leaves are products of at most two indicators — but the collapse must split such trees at the root into two ≤2-feature halves. Implemented and covered.

Docshowto/tuning.md walks all eight questions (tree count, depth, the asymmetry, the "doesn't it just become the teacher?" concern, band count, within-band AUC reading guide, scorecards); faq.md adds fourteen Q&As from configuration through determinism. Both in nav; API reference extended.

Gate

Full local suite (110 tests), ruff/black, mkdocs build --strict — all green.

Release note: main is at v0.1.0 — if this should ride the first release, merge before tagging; otherwise it lands cleanly in the next.

orgoca added 2 commits August 16, 2026 11:14
…+ FAQ

Answers the configuration questions users actually face, with measured
tools instead of rules of thumb:

- compileml.tune.sweep_whitebox: trees x depth grid reporting holdout
  Gini retention, Spearman vs teacher, exact_attribution, quantized model
  size, and MEASURED per-row explanation cost. The guide's core message:
  trees are a linear knob that never costs a guarantee; depth is the knob
  that takes exactness away above 2. Spend on trees, be stingy with depth.
- compileml.tune.sweep_bands: band-count grid with ordinal-Gini
  retention, Gini gap, worst within-band AUC + verdict, min band volume,
  monotonicity violations, and integer-edge collisions.
- compileml.bands.band_efficiency: the money-on-the-table diagnostic.
  Gini gap (continuous minus band-ordinal) plus per-band within-band AUC
  with bootstrap CIs and refinable/exhausted/inconclusive verdicts.
  Validation check 4 now carries these fields whenever outcomes are
  supplied — advisory by default, gateable via max_within_band_auc=.
- compileml.scorecard (stdlib-only): at depth <= 2 the artifact collapses
  into an exact points scorecard — bin -> points tables plus pairwise
  interaction grids whose integers re-sum to every decision's raw_micro
  bit-for-bit (score_from_scorecard re-derives decisions from the printed
  tables; asserted on 300 rows at depths 1 and 2). Markdown/CSV
  renderers; compileml scorecard CLI subcommand; refuses above depth 2
  rather than approximating. Handles the depth-2 subtlety where one tree
  references three features (root + one per child) by splitting at the
  root into two <=2-feature halves — exactness is preserved because
  depth-2 leaves are products of at most two indicators.
- docs/howto/tuning.md: the eight configuration questions with the
  trees-vs-depth asymmetry, sweep walkthroughs, within-band AUC reading
  guide, and the depth 1/2/3 attribution-scorecard-fidelity table.
- docs/faq.md: fourteen questions from configuration to determinism.
The 0.1.0 wheel published to PyPI carried correct metadata but a stale
hardcoded compileml.__version__ of 0.1.0.dev0 — two version declarations
(pyproject and __init__) that were never wired together, so the module
attribute, compileml inspect, and every artifact's compileml_version
reported dev while PyPI said 0.1.0.

Fix is structural, not another parallel bump: __version__ in
src/compileml/__init__.py is now the single source of truth and
pyproject reads it at build time (setuptools dynamic version, static
attr — no import at build). Verified locally: wheel metadata == module
attribute == 0.1.1, twine check passed.

CHANGELOG restructured with the 0.1.1 section (noting what was wrong
with 0.1.0); RELEASING.md bump instructions point at the new single
source.
@orgoca

orgoca commented Aug 16, 2026

Copy link
Copy Markdown
Owner Author

Added to this PR: version single-sourced at 0.1.1. Root cause of the "still appeared as dev" mystery: PyPI's 0.1.0 metadata was actually correct — the stale value was the hardcoded compileml.__version__ = "0.1.0.dev0" in __init__.py, a second declaration never wired to pyproject. That's what import compileml, compileml inspect, and every artifact's compileml_version displayed.

Fix is structural: __init__.py is now the only version declaration and pyproject reads it at build time (dynamic = ["version"]). Verified locally: wheel metadata == module attribute == 0.1.1, twine check passed. RELEASING.md updated to point at the new single source.

Merging this PR leaves main tag-ready: git tag v0.1.1, push, publish the GitHub release.

@orgoca
orgoca merged commit 2bc4c63 into main Aug 16, 2026
20 checks passed
@orgoca
orgoca deleted the feat/tuning-scorecard branch August 16, 2026 17:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant