Skip to content

Hold critical targets inside their gate tolerance during calibration - #1330

Draft
MaxGhenis wants to merge 7 commits into
mainfrom
critical-target-band-penalty
Draft

MaxGhenis wants to merge 7 commits into
mainfrom
critical-target-band-penalty

Conversation

@MaxGhenis

@MaxGhenis MaxGhenis commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Draft. This adds critical-target bands to US calibration. Max ruled on 2026-10-20 (d1749, revised) to fix the solve rather than hand-weight the SSA family. The PR stays a draft until the d1386 validation rerun below reports.

Why

The d1386 Route A release failed its critical-target gate. The Social Security benefits total came out 6.4% under SSA's figure, and the retirement total 8.5% under.

What

  • Solver (microcosm.calibrate.solve):

    • The term. An optional per-target band, set by target_band_tolerances and target_band_penalty. For each banded row the objective adds penalty * max(|relative error| - tolerance, 0):
      • zero inside the band, so it leaves the fit alone there;
      • the relative error is the gate's own, (estimate - target) / target, or estimate - target when the target is 0;
      • only the banded rows enter the term.
    • Coverage. Every solve path takes it:
      • Adam _optimize: the tracked objective and the closing comparison;
      • _optimize_proximal;
      • the L0 budget search;
      • calibrate;
      • refit_l0_selection;
      • calibrate_l0_refit, in both phases.
    • Unchanged: relative_error_loss, final_loss and the loss trajectory.
    • Diagnostics. options["target_band"] records each banded row's tolerance, final relative error and violation, the maximum violation, and any banded targets the constraint matrix skipped.
    • Refusals:
      • a band whose every row was skipped, the same refusal as a band on no row;
      • a banded nonzero target that rounds to zero in float32.
    • Default. Off in the library: no tolerances, or penalty 0, means no band.
    • No guarantee. The penalty doesn't provably dominate every competing target.
      • Past the band, the band pulls on the target at slope penalty, in the same direction as the target's own fit term.
      • With the default loss scales, that fit term's slope is the target's loss share, at most 1.
      • The other targets' fit terms can pull against both.
      • Any remaining violation is recorded, and the release gate still judges the result.
    • Retention. Best-iterate retention compares fit plus band, the objective the optimizer minimizes. It keeps an iterate outside a band whenever the fit it gains exceeds the penalty times the violation it adds.
  • Exact-k ladder (us_runtime/exact_k_ladder.py): forwards the band to its three calibrate/refit calls.

  • Release (tools/build_us_fiscal_refresh_release.py):

    • What it bands. _critical_target_band_tolerances bands every row that the 18 US_CRITICAL_TARGET_FIT_REQUIREMENTS match, using the gate's own _critical_requirement_matches_target. A row matches by name, or by family plus role. Each band is the tightest matching tolerance times a margin.
    • New flags:
      • --critical-target-band-penalty: default 1; 0 turns the band off; finite and ≥ 0.
      • --critical-target-band-margin: default 0.9; in (0, 1].
    • Provenance. calibration_diagnostics.json build.critical_target_band and the calibrating telemetry stage record {penalty, margin, banded_rows}.
    • Not banded: the SOI Table 1.4 national-dollar gate (25%). That gate exists to catch imputation defects, as in Build M live default: non_sch_d_capital_gains lands at $74.6B vs its $10.2B SOI target (+635%); Schedule-D CGD route is empty #462, where non_sch_d_capital_gains shipped at $74.6B against $10.2B. Banding it would let the weights absorb a defect instead of failing the build loudly. Its 9 rows were at most 10.8% off in the failed release, inside the gate. The validation rerun checks them.
    • Rows relaxed for a support defect stay banded. The medical-expense row, relaxed to 25% after Build M live default: non_sch_d_capital_gains lands at $74.6B vs its $10.2B SOI target (+635%); Schedule-D CGD route is empty #462, is banded like the other 17, per d1749. Whether such rows should be skipped, as the Table 1.4 gate is, is queued for Max as d1785. That row is at +0.01% on d1386, so its band doesn't bind there.
    • Release default changes. The band is on in the release, so release solves change.
  • Exact-k ladder releases (tools/build_us_exact_k_ladder_release.py):

    • The config may pin calibration.critical_target_band_penalty and calibration.critical_target_band_margin, which are forwarded to the builder. Without them the builder's defaults apply.
    • The exact-k incumbent gate scores fit loss alone. A banded candidate therefore spends some fit to hold its critical targets against an incumbent that may have been solved without a band. A ladder release should check that gate or pin the band.
    • The target-loss basis is unchanged, since the comparison metric is unchanged. Adding the band to it would fail every existing incumbent's exact basis match.
  • Re-pins. solve.py is a spec input, so these moved:

    • the seed protocol and map hashes;
    • the F0 coverage evidence (41/41);
    • the multispine pool spec digest;
    • the calibrate parity pins;
    • the loader golden vector.

    The calibrate repin tool accepted, so the parity outputs didn't move.

Invariants

These hold for every input.

  1. The band term is ≥ 0, and it is 0 exactly when every banded row is inside its tolerance (test_property_violation_is_the_distance_outside_the_band).

  2. Units don't matter: scaling a row's estimate and target together leaves its violation unchanged (test_property_violation_does_not_depend_on_units).

  3. The torch and numpy forms agree: the torch term the solver minimizes equals penalty * target_band_violations(...) (test_property_torch_term_matches_the_numpy_reference, a differential test).

  4. No band, no change: tolerances with penalty 0, or a band that never binds, gives weights bit-identical to a solve without a band (test_tolerances_without_a_penalty_change_nothing, test_a_band_that_never_binds_changes_nothing).

  5. Band and gate agree. test_the_band_covers_exactly_what_the_real_gate_judges is a differential against the real _critical_target_fit_failures. Its fixture covers:

    • every requirement's named rows;
    • family-plus-role aliases;
    • congressional-district twins;
    • a non-critical row.

    With each banded row's error at 1.001× its gate tolerance, the gate fails exactly the banded rows; at 0.999×, it fails none.

  6. Malformed input is refused:

    • a positive penalty with no tolerances;
    • tolerances that band no row, or only skipped rows;
    • negative or non-finite tolerances;
    • a tolerance vector of the wrong shape;
    • a negative or non-finite penalty;
    • a banded target below float32 range;
    • a release or ladder margin outside (0, 1].

Tests

  • test_target_bands.py, 23 tests:
    • a synthetic conflict: without a band the heavier target wins; with one, the critical row holds inside 5%;
    • the band holding on the prox, budget-search and conserve-mass-with-ratio-cap paths;
    • both L0-refit phases: the band pulls the stochastic selection phase in and holds the refit that ships;
    • the skip and float32 edge cases;
    • the no-op cases;
    • the refusals;
    • three Hypothesis properties.
  • test_us_release_critical_target_band.py:
    • named rows and role aliases;
    • no critical row;
    • the real-gate differential;
    • flag defaults and refusals;
    • structural checks that every solve _main can run receives **band_kwargs, and that the ladder forwards the band on all three calls.
  • The _main harness (test_main_writes_diagnostics_before_post_calibration_gate_failure): the L0 and exact-k branches receive the band, and the diagnostics record it.
  • Ladder:
    • a spy test that the full-pool solve, the Sampford selection and its refit each receive the band;
    • launcher tests for the new config keys.
  • Existing suites: test_solve.py, the graph parity pins and the test_spec_engine_* suites.

Review

  • An Opus 5.5 adversarial review of a8e6ba3fd approved, with no blocker or major findings. c51e64774 addresses its minor findings and nits; 277b321d2 re-pins.
  • An Opus 5.5 delta review of 277b321d2 requested changes for one finding, D1 (major): a new launcher test passed k=8, which the builder refuses. It confirmed F1–F12 fixed. e6beb31a4:
    • fixes D1;
    • adds the D2 assertions (the written build block and telemetry carry the band) and the D3 test (a row two requirements match takes the tighter band);
    • rewords the two D4 sentences;
    • re-pins.
  • D5, whether rows relaxed for a support defect should be banded, is queued for Max as d1785.
  • What the review executed:
    • band off is bit-identical to origin/main across 9 solver configurations;
    • the band reaches every solve path;
    • band and real gate agree under a differential;
    • the re-pins are explained by solve.py bytes alone.

Validation rerun (2026-10-21, code e6beb31a4): the gate holds, but the fit converges far more slowly

The d1386 release was rerun from this branch with the band at its defaults (penalty 1, margin 0.9) and no multiplier. It ran on the saved target frame, inside reservation route-a-band-exp-2026-10-21. All three runs are scored on the failed release's loss weights.

failed release ssa=4 band
Social Security total −6.42% (fails 5%) +0.03% −3.24%
critical rows outside the gate 1 of 22 0 0
loss (capped MAPE) 0.0241 0.0237 0.0351
targets within 5% 89.4% 89.5% 83.4%
targets within 10% 93.1% 93.2% 88.7%
effective sample size 73,750 72,166 88,276
  • What went wrong. The band's fit loss lags from epoch 10 on: 0.109 against 0.050 at epoch 100. At epoch 1,500 it is still falling (0.0359 to 0.0351 over the last 100 epochs), while the release had flattened at 0.024. So the band slows convergence; it does not settle at a worse optimum.
  • Breadth of the loss. 947 IRS SOI rows end more than 1 point worse, and 109 better.
  • Table 1.4. All 9 national dollar rows stay inside 25%.
  • QRF register. Four d1748 columns fall under 0.75 with these weights, so the register mismatched: alimony_expense, alimony_income, estate_income and farm_rent_income are stale. That was the run's only failed gate.
  • Status. The PR stays a draft while the slowdown is diagnosed. Evidence is in 893/route-a-rerun-20261018/experiments/band/band-comparison-e6beb31a4584.txt.
  • A synthetic reproduction didn't show it. Every penalty fit fine on a 4,000-record, 301-target problem with the same structure: experiments/band/synthetic/band_dynamics.py. So the cause on the real problem is unconfirmed.
  • Hypothesis to test. A penalty of 1 is about 500× Social Security's own loss share (0.0019). Adam scales each weight's step by its recent gradient size, so a band gradient that large could keep the steps of the affected households small long after the band stops binding.
  • Max's ruling, d1811 (2026-10-21). d1386 ships with --target-family-loss-multiplier ssa=4, which fixed Social Security with no fit cost. This PR's next step is to replace the fixed penalty with an adaptive multiplier: each critical row's penalty starts at 0 and rises only while that row is outside its band.

Plan

  • Solver band term: Adam, proximal, L0 search, calibrate, the L0 refit
  • Release wiring, flags and diagnostics
  • Tests: properties, the torch/numpy differential, a synthetic conflict, every solve path, the wiring
  • Spec-digest re-pins (solve.py bytes)
  • Independent review (Opus 5.5, APPROVE at a8e6ba3fd), findings addressed
  • Delta review of c51e64774..277b321d2 (REQUEST_CHANGES on D1; fixed)
  • Confirming review of e6beb31a4 (Opus 5.5, APPROVE)
  • Rerun the d1386 release from this branch with bands and no multiplier. It passes the gate but fails the fit criterion (see above). Pass criteria:
    • all 18 critical requirements (22 rows) inside their gate tolerance;
    • the 9 Table 1.4 national dollar rows inside 25%;
    • the QRF columns exactly matching the d1748 register;
    • an overall fit comparison against the failed release and the ssa=4 experiment, scored with one fixed set of loss weights.

🤖 Generated with Claude Code

MaxGhenis and others added 7 commits October 20, 2026 16:27
A band is a tolerance on one target's relative error that the solve should
hold rather than trade away. For each banded row the objective adds
target_band_penalty * max(|relative error| - tolerance, 0). That is zero
inside the band, so it leaves the fit alone there, and outside it is a linear
penalty. The relative error is the critical-target gate's,
(estimate - target) / target. relative_error_loss, final_loss and the
trajectory are unchanged; options["target_band"] records each banded row's
final violation.

Threaded through the Adam and proximal paths, the L0 budget search,
calibrate, refit_l0_selection and calibrate_l0_refit. Off by default
(target_band_penalty=0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every row the critical-target gate judges (US_CRITICAL_TARGET_FIT_REQUIREMENTS,
matched by the gate's own matcher) gets a band at 0.9 of its gate tolerance,
with penalty 1. The band reaches the dense solve, the L0 refit and the exact-k
ladder. --critical-target-band-penalty 0 turns it off;
--critical-target-band-margin sets the fraction. Tests check that the band and
the gate agree on every requirement, and that malformed flags are refused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
solve.py is a spec input, so its bytes move the seed protocol and map
hashes, the F0 coverage evidence, the multispine pool spec digest, the
calibrate parity pins and the loader golden vector. The calibrate repin
tool accepted (outputs unchanged); only the source digest moved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… edge cases

The Opus review of a8e6ba3 approved with minor findings; this commit fixes them.

- Solver: only banded rows enter the band term, so an unbanded target too small for float32 can no longer divide 0 by 0 in the gradient. A banded target that rounds to zero in float32 is refused.
- Solver: a band whose every row the constraint matrix skipped is refused, like a band on no row. A partly skipped band lists the skipped names in options["target_band"]["skipped_banded_targets"].
- Retention and slope comments say what holds. Retention compares fit plus band, so it can keep an iterate slightly outside a band. The slope bound holds with the default loss scales.
- Release: the CLI help and the comment no longer read as a guarantee.
- Release: the diagnostics build block and the calibrating telemetry stage record the band's penalty, margin and banded row count.
- Ladder: the config may pin critical_target_band_penalty and critical_target_band_margin, which are forwarded to the builder. Without them the builder's defaults apply. The docstring notes that the exact-k incumbent gate scores fit loss alone.
- Tests:
  - every solve main() runs receives the band (a structural check over _main, plus the _main harness for the L0 and exact-k branches), and the ladder forwards it on all three calls (a spy and a structural check);
  - the band holds on the prox, budget-search and conserve-mass paths, and in the L0 refit;
  - the skip and float32 edge cases;
  - the launcher's band keys;
  - a differential against the real _critical_target_fit_failures replaces the circular band-vs-gate test.
- us_critical_targets: a note on why the band is not a microcosm#492 per-target loss knob.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The seed protocol and map hashes, the F0 coverage evidence (41/41), the multispine pool spec digest, the calibrate parity pins and the loader golden vector all attest solve.py's bytes. The calibrate repin tool accepted, so outputs did not move. The provenance comments gain a #1330 entry that says US release solves change this time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tighter-band test, wording

- D1: the launcher band test passed k=8, which the builder's --exact-k refuses; it now uses "N".
- D2: the _main harness asserts that the build block the diagnostics writer receives, and the calibrating telemetry stage, carry the band record.
- D3: a row two requirements match (the Social Security name with the itemized family and role) takes the tighter tolerance, checked against the real gate.
- D4: retention keeps an iterate outside a band whenever the fit it gains exceeds the penalty times the violation it adds (no "slightly"). Past the band, the band's pull runs in the same direction as the target's own fit term rather than outweighing it.
- Re-pins for solve.py's docstring bytes: seed protocol and map, F0 coverage (41/41), multispine spec digest, calibrate parity pins, loader golden.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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