Repository navigation
Build the module-release test's systems with automatic GC off - #2716
Conversation
Module names carry id(system). A collection during the loop lets a later system reuse a dead one's address and overwrite its modules instead of adding an owner, so no release falls due and the test fails although nothing leaked. This failed pe-uk#2092's merge-queue run (40698045501, Test / Python 4/6). Keep automatic collection off while the systems are built; the release still collects. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Aggregate impact on certified data: passBase Checks: 0 broken by this change, 1 failing on both sides, 0 fixed. Moves flagged for review: 0 (thresholds in Notes
Moves flagged for reviewNone. Spending by benefit and service
Caseloads
Standard reform costings (change in gov_balance)
Standard reforms: change in each reform's target
Household net income by decileNo household's net income changes in any year. No change in any year: receipts by tax head; government balance, each component counted once; model totals; household income totals; population; poverty rates; people in poverty; inequality; mean household net income in each side's own deciles. Checks failing on both base and head (1)
Counted-once checkEach of 91 components was raised by £1 per unit in 2026-27, and every head of its totals was read household by household: its own head must rise by exactly £1, no other tax head may move, no other benefit may rise, and the model's own total must move by what its heads moved. A head that breaks a rule is measured again twice: with every other head held at its baseline value, and with every other head held at its value after the first £1 while the component rises again. It fails where either still shows the response. 0 failed; 0 were skipped.
Provenance
Dataset: Receipts by tax head: head levels
Spending by benefit and service: head levels
Caseloads: head levels
Government balance, each component counted once: head levels
Model totals: head levels
Household income totals: head levels
Population: head levels
Poverty rates: head levels
People in poverty: head levels
Inequality: head levels
Mean household net income in each side's own deciles: head levels
Standard reform costings (change in gov_balance): head levels
Standard reforms: change in each reform's target: head levels
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
UK hub: enqueued at
🤖 Generated with Claude Code |
test_dead_systems_modules_are_released_while_a_test_runsdepends on when Python collects garbage. It failed in #2092's merge-queue run (40698045501, Test / Python 4/6) with "no release ran while the systems were built". The same test had passed in #2092's own CI, and the merge queue removed #2092. No other failed run since 26 October has this failure. The hub checked 12 failed Code changes runs. The independent review checked 20 failed runs, with 39 readable Python-job logs; one job's log returned 404.Why it fails
The conftest releases dead systems' variable modules once more than eight systems own modules beyond those alive at the last release. Core names each module after
id(system), which is the system's address (checked: a live system's id prefixes its modules, for example4674774160_…_in_original_frs). The test builds 11 systems and expects a release.If a collection frees a dead system during that loop, a later system can take its address. The new system then overwrites the dead system's modules instead of adding an owner, so no release falls due. Nothing leaks: the owner count stays bounded. But
assert scansfails.Measured locally on main plus #2092, with Python 3.13, 11 builds:
gc.collect()after each buildThe change
The test builds its systems with automatic collection off, restoring the previous setting afterwards. The dead systems then wait for the release's own
gc.collect(), so each build adds an owner. The bound assertion and the hook it tests are unchanged. This is a test-only change.Checks
Independent review: an Opus 5.5 review approved 6a82610 with no P1 or P2 findings. It confirmed from core 3.33.12 that module names carry
id(self)and are assigned straight intosys.modules. It also found a second path the fix covers: a reused address can match the conftest's_adding_systemand skip that build's hook. With the unchanged test bodies and real core systems, it reproduced the old test's failure, and the fixed test passed. Its mutations failed as they should: hook removed, release threshold 8 → 9, clean-up made a no-op. GC state was restored when the constructor raised, whether collection started enabled or disabled. Its two wording points are applied: this body, and the changelog fragment, at the current head.All runs used
run_capped.py, with pytest at-n 0.add_variables_from_filegc.set_threshold(700, 1, 1)ruff format --check,ruff check,git diff --checkWhat the checks show: automatic collections no longer decide whether the test passes, and it still fails if the build hook stops releasing. An explicit
gc.collect()during system construction would still defeat it. policyengine-core has none. Outside tests, policyengine-uk's only calls are inutils/aggregate_impact/measure.py; the conftest's release calls it on purpose.Reproducer: policyengine_uk/tests/test_variable_module_release.py::test_dead_systems_modules_are_released_while_a_test_runs
axiom: n/a: test infrastructure only
🤖 Generated with Claude Code