Skip to content

FIX-0: T20 remediation programme, tracking issue #419

Description

@mateuszwalo

Tracking issue for the remediation programme that comes out of the T20 findings (#389) and
the statistics defects in #390. Plan document: plans/FIX-PLAN-T20-2026-08-23.md.

What this is fixing

Three facts drive the whole thing.

  1. selection_mode="xai" never uses saliency for arbitration. It is a greedy argmax on
    selection-validation accuracy, and the benchmarked contrast was accuracy-argmax vs random.
    It is null at n=10 across two datasets and three protocols.
  2. That criterion is close to orthogonal to the objective. On Waterbirds it sits at ~97% while
    the objective sits at 59%, and candidate accuracies differ by fractions of a point.
  3. The equal-compute protocol costs the deployed model two thirds of its budget. Matching
    deployed epochs closes 4.46 pp to 0.09 pp on Imagewoof.

Plus a family of silent-failure defects found at source.

Phase 0, independent fixes, all parallel

Phase 1, turn saliency into measurements

Phase 2, selection refactor

Phase 3, record and observe

Phase 4, search policy

Block 7, calibration and falsification

Sequencing that matters

Phase 3 before Phase 4. Shadow mode (#411) records the diagnosis on every run
without letting it decide anything. It is what makes #417 possible: from the moment
it lands, every run that was going to happen anyway becomes a calibration sample at zero extra
GPU cost. Without it the only way to get thresholds is to guess, which is the mistake this
whole programme exists to undo.

Thresholds stay None. #405 makes the library refuse diagnostic mode until they
are supplied, and #417 is the only issue allowed to supply them.

Defaults do not move until Block 7 says so. #413 ships the policies with
exhaustive still default.

Kill criterion, stated up front. If the calibrated rule does not beat metric_argmax on
held-out seeds, diagnosis_single does not become the default and the result is published as a
negative result, the same way T20's null was.

Schedule

Week Dates Content
CW9 Aug 25-31 #394 to #398 in parallel, #399 alongside, #402 starts
CW10 Sep 1-7 #399 to #401 finish, Phase 1, #406 starts
CW11 Sep 8-14 Phase 2, Phase 3, shadow runs start collecting
CW12 Sep 15-21 Phase 4, #416, #417 running
CW13 Sep 22-30 Buffer. #418, defaults decision, docs, retro

Roughly 200h of estimates against roughly 195h of capacity, so the plan is full. If it slips,
#412 drops first, then Block 7 becomes a post-cohort study with the shadow data
already collected.

Out of scope for the cohort, deliberately: augmentation_schedule (sequential ICD then AICD,
stochastic mix, Proposal B). It opens a new untested axis and is not needed to close either
defect the benchmarks identified.

Decisions already taken


Status, 2026-08-30

Phase 0 dev items, Phase 1 and Phase 2 are complete. Phase 3 is half done.

phase state
Phase 0 (dev) #394 #395 #396 #397 done. #398#401 open, taken by others
Phase 1 complete: #402 #403 #404 #405
Phase 2 complete: #406 #407 #408 #409
Phase 3 #410 #411 done, #412 open
Phase 4 #413 #414 #415 open
Block 7 #416 #417 #418 open

Shadow mode is live. Since #411 landed, every run with XAI enabled writes shadow_records.jsonl: the saliency statistics and robustness metrics per candidate, with the arm that was kept flagged. That is the calibration set #417 needs, accumulating at no extra GPU cost from runs that were going to happen anyway. The sooner the team's benchmark runs go through a current build, the larger that set is when #417 starts.

Two decisions taken while implementing, both flagged in their PRs and reversible:

One deviation from an issue's steps: #408 step 5 asks to reuse the paired estimator from benchmarks/stats.py (#398). That file does not exist yet, so the estimator lives in bnnr/training/paired.py and the convention difference (sample-level mean vs seed-level median, and why) is documented. Aligning them is a follow-up once #398 lands.

Also fixed, filed off the back of #396: #421 (DifPresets/ProCAM CPU/GPU parity) is implemented in #429 but not merged — it changes numpy-path colour output and is waiting on a call about which channel order to keep.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1Audit backlog: before next releasecohortBNNR 2026 cohort tasktrack:devCohort development task

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions