fix(destinations): the masking pass can no longer exit unsafely
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m5s
PR Checks / Backend Smoke (pull_request) Successful in 9s
PR Checks / Build Backend (no push) (pull_request) Successful in 18s
PR Checks / Build Frontend (no push) (pull_request) Successful in 45s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 1m16s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 7m23s
PR Checks / Frontend Typecheck + Tests (pull_request) Successful in 1m5s
PR Checks / Backend Smoke (pull_request) Successful in 9s
PR Checks / Build Backend (no push) (pull_request) Successful in 18s
PR Checks / Build Frontend (no push) (pull_request) Successful in 45s
PR Checks / Build Pipeline (no push) (pull_request) Successful in 1m16s
PR Checks / AI Code Review (Claude) (pull_request) Successful in 7m23s
Review found _mask_for_disclosure could return with its invariant broken and say nothing. add_companion only ever withheld a *published* cell, so a group with one suppressed category and every other one not_applicable — routine in special schools and AP, where few categories apply — left the loop with the lone suppressed cell still solvable. Reproduced on a nine-pupil cohort: one hidden cell, cohort served, residual intact. A disclosure-control pass that fails silently is worse than none, because everything downstream trusts it. The loop now runs until the invariant holds and escalates when no companion exists: the pupil group is dropped from the payload, and an empty block serialises as None so the section is absent rather than an empty shell. disclosure_invariant_holds() is exported so tests assert it directly instead of re-deriving it, and an exhaustive test sweeps all 81 suppression patterns of a four-category group. Also fixes a test that set up six measures and checked one: the loop was `for measure in ["school_sixth_form"]`. It now checks every measure, and against the real invariant — none hidden, or at least two, rather than "at least two", which the five published measures would have failed. No regression on real data: 262 mainstream secondaries, all-pupils bar still drawable on 94%, zero invariant violations, one disadvantaged group dropped by the new escalation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BvdDKvFFSZuMVDH5fEyTob
This commit is contained in:
1 parent
102397fe69
commit
2e9b5c83c5
3 files changed
+181
-42
No files matched your search
@@ -69,7 +69,17 @@ identity, and terminates because cells are only ever added.
|
||||
|
||||
The companion must carry pupils. Suppressing a zero looks like secondary
|
||||
suppression and protects nothing: the residual still equals the original
|
||||
withheld figure. Where no non-zero companion exists, the whole set is withheld.
|
||||
withheld figure.
|
||||
|
||||
Where no companion can do the job — a sparse cohort whose every other category
|
||||
is `not_applicable`, routine in special schools and alternative provision — the
|
||||
pupil group is **dropped from the payload entirely**. A first version simply
|
||||
returned at that point with the violation intact and no signal, which review
|
||||
caught: a disclosure-control pass that fails silently is worse than none,
|
||||
because everything downstream trusts it. The function now cannot terminate
|
||||
except in a state where `disclosure_invariant_holds()` is true, and an
|
||||
exhaustive test sweeps all 81 suppression patterns of a four-category group to
|
||||
prove it.
|
||||
|
||||
Measured cost on the 400-school sample: the all-pupils bar survives on **94%**
|
||||
of mainstream secondaries rather than 100%. That is the price of not
|
||||
|
||||
Reference in new issue
Block a user