Skip to content

Give the Social Security state backend the names Core 3.33.13 needs - #10504

Merged
hua7450 merged 1 commit into
PolicyEngine:mainfrom
hua7450:fix-ss-state-backend-core-imports
Oct 27, 2026
Merged

hua7450 merged 1 commit into
PolicyEngine:mainfrom
hua7450:fix-ss-state-backend-core-imports

Conversation

@hua7450

@hua7450 hua7450 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

What and why

Main's release runs fail Full Suite - Rest (Python shard 3) on core/test_social_security_input_state_machine.py (run 40544965026):

policyengine_core/simulations/simulation_builder.py:347: in build_default_simulation
    id_count = operator.index(count)
NameError: name 'operator' is not defined

The test's backend (core/_social_security_state_backend.py, from #10400) runs Core's installed SimulationBuilder, Simulation, holder and dumper source in namespaces it builds itself. policyengine-core 3.33.13 (released 2026-10-27 16:43 UTC; CI installs the latest Core on every run) gave those functions two new globals the namespaces lack:

  • build_default_simulation now checks its count with operator.index. The builder namespace now gets the operator module.
  • restore_simulation now calls _restore_count for each population after restoring the entities. The backend already stubs _dump_entity and _restore_entity for its one-person fixture, so _restore_count gets a no-op stub beside them. Without it the test fails next with NameError: name '_restore_count' is not defined.

The earlier failures on main today were a different test: core/test_mt_state_agi_invariants.py, which #10496 fixed. Runs that include #10496 fail only on this test.

To find every name Core's executed functions need, I listed the global names each function reads that neither its namespace nor builtins define. Core 3.33.13 adds exactly these two names to the list. The other seven (psutil, tools, EnumArray, SimulationMacroCache, Reform, pd and SituationParsingError) were missing under 3.33.12 too and sit on branches the fixture never runs: reforms, datasets, the macro cache and error paths.

Test plan

  • For policy changes: not applicable (test fixture only).
  • Source conflicts: not applicable.
  • make format
  • Changelog fragment in changelog.d/
  • test_social_security_input_state_machine.py locally: fails with the operator NameError on Core 3.33.13 before the change; passes on Core 3.33.13 and 3.33.12 after it.
  • Without the _restore_count stub, Core 3.33.13 fails the test with NameError: name '_restore_count' is not defined.

axiom: n/a: test fixture change only, no policy change.

🤖 Generated with Claude Code

policyengine-core 3.33.13 calls operator.index in build_default_simulation
and _restore_count in restore_simulation. The state-machine backend runs
those installed source bodies in namespaces it builds, which had neither,
so test_social_security_input_state_machine failed with NameError on main.
Add the operator module, and stub _restore_count beside the existing
_restore_entity stub for the one-person fixture.

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

DTrim99 commented Oct 27, 2026

Copy link
Copy Markdown
Collaborator

Program Review

Source Documents

  • PDF: none (infrastructure PR — test fixture compatibility with policyengine-core 3.33.13)
  • Scope: PR changes only. The PR changes policyengine_us/tests/core/_social_security_state_backend.py and adds changelog.d/fix-ss-state-backend-core-imports.fixed.md. Head ea3b1d9bf1 is 1 commit ahead of main and 0 behind.

Critical (Must Fix)

None.

  • The fix is complete. Core 3.33.13 adds exactly two global names that the executed bodies read and the backend did not define:
    • operator, read at Core simulation_builder.py:347
    • _restore_count, read at Core simulation_dumper.py:113
  • The PR supplies both in _social_security_state_backend.py: import operator (:42), operator=operator (:535) and the _restore_count=lambda *args: None stub (:679).
  • No third name is new. A bytecode walk covered all 129 bodies executed on 3.33.13.
  • Local runs. On 3.33.13 the base fails with main's NameError. The head passes on 3.33.13, 3.33.12, 3.33.2 (locked) and 3.33.1 (the floor). These runs needed a shim for Windows filenames (suggestion 3).
  • The stub is safe. For this fixture it gives the count the real function would, 1. Core holders/holder.py:690 raises if any count were wrong.
  • The changelog fragment is valid. It sits at the top level of changelog.d/, is named after the branch, has type fixed and is one sentence.

Should Address

None. The test review left one item open, and it is now closed. Rest Python shard 3 (job 122378770311) logged Updated policyengine-core v3.33.2 -> v3.33.13 and then test_social_security_input_state_machine.py::TestSocialSecurityInputStateMachine::runTest PASSED (5.67s).

Suggestions

  1. Add a guard that every global the executed bodies read resolves. Lines: _social_security_state_backend.py:110-113, :489-536, :663-680. Both validators raised this. It is a follow-up and does not block the PR.
    • How it works:
      • Record the functions that execute() returns.
      • Collect LOAD_GLOBAL names with dis.get_instructions, recursing into nested code objects. Do not use co_names, which also holds attribute names.
      • Check each name against fn.__globals__ and builtins.
    • Allowlist the seven names that are already unresolved but unreachable, with one reason each: tools, psutil, Reform, pd, SimulationMacroCache, EnumArray and SituationParsingError.
    • Benefit. The next new Core name would fail at setup, with its function and line. Today it surfaces as a Hypothesis falsifying example in whichever run first installs the new Core.
    • US-side drift. compiled_hooks (:117-135) drops imports. A new import in tools/social_security_inputs.py therefore has to be copied by hand into hook_module (:750-765), and the guard would catch a missed one.
    • Seeding is only a partial alternative. Seeding each namespace from its module's stdlib imports would have supplied operator, but not _restore_count, which is a module-level function. If you add seeding, limit it to stdlib (plus numpy) and apply the fixture's overrides afterwards. That keeps it from reintroducing Simulation, SimulationBuilder, OnDiskStorage or check_type.
    • Cost. No one has measured it. It should take well under a second in the Rest core group, since it needs no country import, dataset or parameter tree.
  2. Comment why _restore_entity returns 1 (:675).
    • Core 3.33.13 discards the value (simulation_dumper.py:106).
    • On 3.33.12 and earlier, including the locked 3.33.2, it becomes the person count (3.33.2 simulation_dumper.py:93,99).
    • A later cleanup that changed it to None would break the locked version.
  3. Pre-existing: dump filenames fail on Windows (:147,153, from Add composable Social Security benefit levers #10400, outside the diff).
    • Disk.put writes default_{period}.npy, so a compound period such as year:2023:2 raises OSError: [Errno 22] on Windows.
    • Core's OnDiskStorage swaps : for ; (on_disk_storage.py:61-64,403-405).
    • CI runs on Linux, so this does not block the PR.
  4. Pre-existing: the module docstring has a 133-character line (:9, outside the diff). ruff is clean, because the repo ignores E501 and ruff format does not rewrap docstrings. Rewrapping is optional.
  5. Quick Feedback skips helper-only changes (follow-up outside this PR). See policyengine_us/tests/run_selective_tests.py:212-215, :317-320 and :614-617.
    • A changed _-prefixed helper maps to itself. Pytest collects no tests from it, so the runner skips it. This PR's 2m1s Quick Feedback pass is therefore not evidence for the fix.
    • Map a changed helper to the test files in the same directory that name it; here that is test_social_security_input_state_machine.py:36-39. Fixes like this one would then get a fast check against the newest Core.

Validation Summary

Check Result
Regulatory Accuracy Skipped (no policy change)
Reference Quality Skipped (no parameters)
Code Patterns 0 issues (4 suggestions)
Test Coverage 0 gaps (2 suggestions). The target test passed on Core 3.33.13 in Rest shard 3.
PDF Value Audit Skipped
CI Status Refreshed 2026-10-27: 26 passed, 7 pending, 0 failed. All 6 Rest Python shards and all 11 Baseline shards passed. Still pending: Microsimulation and 6 Contrib shards (other-shard-1, other-shard-2b, states-shard-1 to 4). None of them loads the changed backend.

Review Severity: APPROVE

Next Steps

To auto-fix issues: /fix-pr 10504

No fixes are required.

  • Before merging, wait for the 7 pending jobs to finish. The Microsimulation job runs Core 3.33.13's real count.npy round trip (tests/microsimulation/test_social_security_current_law.py).
  • To reproduce locally, first match CI's Core with uv lock --upgrade-package policyengine-core && uv sync --extra dev, and do not commit the lock change. A plain uv sync --locked stays on 3.33.2 and does not reproduce main's failure.

@DTrim99 DTrim99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved after /review-program: 0 critical, 0 should-address, 5 suggestions (see the review comment). The fix supplies both globals Core 3.33.13 newly reads (operator, _restore_count), and Rest shard 3 ran the state-machine test on Core 3.33.13 and passed.

@hua7450
hua7450 merged commit 22e80a8 into PolicyEngine:main Oct 27, 2026
33 checks passed
hua7450 added a commit that referenced this pull request Oct 27, 2026
Brings in the Social Security state backend fix for Core 3.33.13 (#10504).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
hua7450 added a commit to hua7450/policyengine-us that referenced this pull request Oct 27, 2026
Brings in the Social Security state backend fix for Core 3.33.13 (PolicyEngine#10504).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis added a commit that referenced this pull request Oct 28, 2026
#10400 was squash-merged as 9969420, so Git's merge base is the
pre-#10400 commit d453360 and every file #10400 added and this branch
then changed shows as an add/add conflict. Each was resolved against
#10400's head a6dcc92:

- The four social_security_*_pia_ratio_factor.py variables, Makefile and
  tests/code_health/test_rest_python_groups.py: main's copy equals
  #10400's head, so this branch's filled version (built on that head) is
  kept.
- tests/core/_social_security_state_backend.py: this branch's copy equals
  #10400's head and main changed it afterwards (#10504, Core 3.33.13
  names), so main's version is kept.
- changelog.d/ss-benefit-levers.added.md: main's release compiled and
  removed it; removed here too.

A merge-tree run with a6dcc92 as the base gives the same tree apart
from the version files (CHANGELOG.md, pyproject.toml, uv.lock), which
this merge takes from main.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.

2 participants