Repository navigation
Conversation
…ache pytest keeps every collected item until the session ends, and each YamlItem kept its simulation and the system it ran on. The runner also cached every reform system it built, a full clone of the baseline each, forever. A policyengine-us run of ~1,500 baseline files in one process reached 118 GB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI's full suite failed test_finished_cases_release_their_simulations with one live Simulation left by an earlier test module in the same process. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… by class Review findings on 8607c73: - the bound was enforced only after inserting a new system, so a later call (or run on the same baseline) asking for a smaller cache, or 0, kept what a larger bound had cached: every call now trims to its own bound first; - class reforms passed without a reform_key all keyed as "" and shared one cached system (also on master): they now key by the class; the runner's inline reform classes still key by their reform_key; - reforms key as a tuple rather than a ':'-joined string; - --reform-cache-size rejects a negative value when it is parsed, rather than failing every case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Measurements of this PR, alone and combined with #570, on the two policyengine-us CI batches that have been dying on 16 GB runners since 3.32.12 (PolicyEngine/policyengine-us#9757). Each row is one
All runs passed every case.
Scripts, logs and raw results: |
…ues by type Round-2 review of 760a001: - a case whose simulation failed to build left it registered on the cached system: teardown now restores the system's simulation to what it was before the case, whether or not the build finished; - traced cases kept one tracer (and its results) per date: ParameterNode cached a tracer-bound wrapper per instant. It now caches the plain node and wraps it on each traced read, which also traces nodes cached before tracing started; teardown resets the cached system's trace fields when they hold the case's tracer; - inline parameter values key by repr, so 0.2 and "0.2" no longer share a system. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TaxBenefitSystem.get_parameters_at_instant cached whatever the parameter tree returned. While the tree is marked traced that is a tracing wrapper holding the reading simulation's tracer, so the system kept one tracer, and the results it recorded, per date; served a node cached before tracing started untraced; and recorded later reads, after tracing stopped or under a later tracer, in the first one. Since #574 core's simulations trace through a per-call view and never mark the shared tree, so the round-3 scenario (traced YAML cases at distinct dates whose formula calls get_parameters_at_instant) no longer leaks; its test fails on 3c7d199 and passes on the merge. Code outside core still marks the tree (policyengine-us's isolate_parameter_tracing sets trace, tracer and branch_name on the root), and then the system cache kept 16 tracers after 16 traced cases at distinct dates. The system cache now caches the plain node and, while the tree is traced, wraps it for that read only, as ParameterNode._get_at_instant does. Tests: example tests across 16 distinct dates, a Hypothesis differential property of the system's path against the tree's, and two YAML runs at 16 distinct dates with weak references to tracers and recorded results. The docs now say each system still caches its parameters at every distinct instant read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hypothesis's too_slow health check times input generation by the wall clock. Round 3 saw test_cache_matches_reference_lru fail it under host load (53 s of generation) and then pass in isolation; it checks nothing the property is about. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft: the October 7 CI repair is at
91744d3e6c88b1a56f7e81f1001f8cdeba3c9af8. Runtime validation at this head remains pending. Existing downstream measurements were completed on earlier snapshots, as linked below.Problem
On 2026-10-02 two
policyengine-core test <~1,500 policyengine-us baseline YAML files> -c policyengine_usprocesses reached 118 GB and 111 GB on a 128 GB Mac and had to be killed. Two of the causes are intools/test_runner.py:YamlItemkeptsimulationandtax_benefit_systemafter its case ran. Every simulation of the run stayed alive._tax_benefit_system_cachekept every system it built, one per distinctreforms/extensions/ dotted-parameter-input combination, and never evicted. Each is a full clone of the baseline. On policyengine-us one measured 1.16 to 1.20 GB and 43 to 47 s to build.Simulation.__init__also setstax_benefit_system.simulation = self, so a cached system kept the last simulation built on it.The third cause, a copy of the whole parameter tree per instant, is in #570 (lazy
ParameterNodeAtInstant); the two PRs are independent.Change
YamlItem.teardowndrops the case's simulation, its system, and the system's back-reference to that simulation.reform_cache_sizereform systems (default 2). It is set withpolicyengine-core test --reform-cache-size Noroptions["reform_cache_size"]; 0 caches none.Replaying the cache over policyengine-us's whole
tests/policytree in run order (31,393 cases, 433 distinct reform combinations) gives 434 builds with no bound and 504 at size 2 (453 at 4). Two keeps the per-process peak at about two reform systems, and costs about 16% more builds.Invariants
test_runner_memory.py).test_reform_cache_property.py, Hypothesis): for any request sequence and any size 0 to 3, the cache holds at mostsizereform systems, returns a cached object exactly when the reference LRU would, always returns a system built for exactly the requested reforms and extensions, and keeps one reform-free system that is never the baseline itself.Existing test targets
The following targets were already listed in this PR; they are not claimed as executed at the current head.
uv run pytest tests/core/tools/test_runner tests/core/test_tax_benefit_system_cache_identity.py tests/core/test_yaml.py--reform-cache-size 1.October 7 CI repair
Merged canonical
masterat5d68130be487f0b87d47fc75ef300f36ad46f7cawith a history-preserving merge and no conflicts.ExceptionInfoobjects on collected items even with no reruns configured. The nested memory-test session disables that dev plugin while the outer session retains its rerun behavior. The probe explicitly retains collected items; failure tests cover both builder paths, an unknown variable, and absent/existing prior simulation backlinks. A successful-build case checks the same ownership invariant.Validation at the repair head
ruff format --check .(348 files),ruff check ., changed-source AST parsing, andgit diff --check.~/reviews/us-hub/scripts/heavy_run.sh core569-targeted env UV_CACHE_DIR=/private/tmp/core-569-build-artifacts/uv-cache uv run --no-sync pytest tests/core/test_tracing_parameter_isolation.py tests/core/tools/test_runner/test_runner_memory.py tests/core/test_parameter_tracing_cache.py tests/core/test_parameter_tracing_cache_property.py tests/core/tools/test_runner/test_reform_cache_property.py -q -n 2 -p no:cacheproviderexited 75 before pytest ran. The sandbox denies the wrapper'spscall, preventing its required nice-level check. No bypass was attempted.91744d3e6c88b1a56f7e81f1001f8cdeba3c9af8with no unresolved P1/P2 findings in the repair delta. Runtime validation and current green CI remain required; this draft is not marked ready.Downstream impact
Completed measurements were posted October 3 for core
760a001a, and its combination with #5704e6bc315, using PE-US615a0f2d. Those earlier results are not measurements of this repair head. Fresh measurement is pending for91744d3e6c88b1a56f7e81f1001f8cdeba3c9af8and its eventual combination with #570.No country-policy or partner baseline files were changed in this repair; no new partner-impact gate or methodology decision is introduced. Whichever of #569 and #570 lands second must rerun the overlapping parameter-cache and runner-memory tests. Preserve #570's recorded #567 ordering constraint.
🤖 Generated with Claude Code