Skip to content

Fix the executor simulation runtime's Pyright errors - #871

Merged
anth-volk merged 2 commits into
mainfrom
pyright-executor-runtime
Oct 26, 2026
Merged

anth-volk merged 2 commits into
mainfrom
pyright-executor-runtime

Conversation

@anth-volk

@anth-volk anth-volk commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #870

Same-Repository Draft PR Check

  • This PR is a draft.
  • This PR is from a branch in PolicyEngine/policyengine-sim-api, not a personal fork.

Summary

Fourth in the Pyright stack, on top of #869. Fixes all 54 Pyright errors in the executor's simulation_runtime.py without changing what a run does. The executor's baseline goes from 126 entries to 72.

Commit Errors fixed Baseline after
Open the simulation runtime's spans with the typed span scope 49 77
Type the simulation runtime's policy, region and dataset reads 5 72

No scopes.operation helper was needed: this module opens only spans.

What changed

  • Spans. The nine runtime.span(...) scopes become scopes.span(runtime, ...), including the credential-setup span chosen by a conditional expression, for consistency (Pyright didn't flag that one). That removes the 47 possibly-unbound errors.
  • _build_simulation's return type. With baseline and reform bound, Pyright reported that a Simulation can't be passed to _report_calculation_start, which takes a StageReportingSimulation (the 2 errors were already baselined, worded Unbound | Simulation). _build_simulation returns one in both branches (ArtifactBaselineSimulation subclasses it), and _report_calculation_start relies on that by calling on_first_ensure, so the return annotation now says StageReportingSimulation. The unused Simulation import goes.
  • Compiled reform. compile_reform returns None only for an empty policy, which _compile_interval_policy has already returned unchanged. A None result now returns the policy too (unreachable), as policyengine's own _reform_dict_to_parameter_values does.
  • UK region type. prefix not in {"constituency", "local_authority"} didn't narrow prefix, because a set display is typed set[str]. A tuple keeps the literal types, so prefix narrows to the two values Region.region_type accepts.
  • Input dataset entity data. The UK weight-matrix check counts households from dataset.data.entity_data, but policyengine types Dataset.data as BaseModel | None. It now reads entity_data with getattr(..., None) and requires a dict, raising TypeError with the dataset's name when none is loaded; before, that case raised AttributeError. A loaded dataset counts the same households. Narrowing on the value, rather than isinstance(..., UKYearData), keeps the existing tests' SimpleNamespace datasets valid. It also needs no new import into a module that keeps policyengine out of its module-level imports.
  • Compiled policy variable. _build_simulation reassigned its policy: dict | None parameter to _compile_interval_policy's result, which may be a Policy. The result now has its own name, runtime_policy, used in the three places that read the reassigned name.

The microdata weight checks (sim.microdata.*) recognise weighted frames by expressions such as <simulation>.output_dataset.data.<entity>. The dataset read changed here is the input dataset (dataset.data), which they don't track, before and after; test_microdata_weight_boundaries.py passes.

Commits (red, then green)

  1. Red: with the 49 entries removed from the baseline, the check on the code before the fix reported 49 errors it doesn't list. Green: passes with 77; executor tests pass.
  2. Red: with the module's last 5 entries removed, the check reported them. Green: passes with 72; executor tests pass, including test_uk_weight_matrix_guard.py.

Suppressions added

None.

Real bugs found

None.

Self-review

review-code on this PR's diff, run by a separate agent, found no bugs and no material code-quality issues. It confirmed:

  • the 54 removed entries are exactly this module's;
  • each commit's Pyright output equals its baseline;
  • each change preserves what a run does.

It noted that the new TypeError for an input dataset with no entity data is untested, and that a dataset loaded from a file can't reach it. #873 switches that check to the shared EntityFrames protocol.

Environment variables

No CI, image or deployment configuration changes, and no new environment-variable reads. simulation_runtime.py runs in the Modal simulation workers; it now imports policyengine_simulation_observability.scopes (#864), part of the observability library the images already install.

Rebase onto #879 (2026-10-22)

Rebased onto the rebuilt #869 after #879 merged. Where this section and the text above differ, this section is current.

What conflicted. simulation_runtime.py, in the first commit. #879 had already opened the run's eight request, dataset, policy and simulation-build spans in _run_simulation_impl_core with scopes.span, and annotated _build_simulation as returning StageReportingSimulation. That removed the same 49 errors this commit removed.

How it was resolved. #879's code is kept, including its baked per-state dataset lookup inside the dataset-load span. The first commit now only opens the credential-setup span in setup_gcp_credentials with scopes.span, and adds _build_simulation's docstring. Neither changes the error count, so its baseline stays at 77. The second commit applied cleanly and removes the module's last 5 errors.

Commit Errors fixed Baseline after
Open the simulation runtime's spans with the typed span scope 0 (#879 fixed the 49) 77
Type the simulation runtime's policy, region and dataset reads 5 72

Baseline at this PR's head: 72 entries, the same entries as before the rebase.

Checks after the rebase. Pyright passes with 72 at both commits. The precompute, precompute app, output builder, state datasets, artifact keys, image setup, bundle image, GCP credentials, runtime policy, UK weight-matrix and annotation tests pass (314). Ruff 0.15.22 format and check are clean. The quality guards and the rules guard against #869 pass. render leaves no changes. No new noqa.

Rebase onto main after #904 and #881 (2026-10-26)

Rebased onto main 34209283, then onto 1f985a73 after #862 merged, which changed nothing in this PR. Where this section and the text above differ, this section is current.

What conflicted. simulation_runtime.py, rules/baselines/pyright-executor.txt, rules/registry.toml and docs/generated/rules.md. Both conflicting blocks in simulation_runtime.py were in _build_uk_weight_replacement_region and _require_certified_uk_weight_matrix, which #881 deleted.

How it was resolved.

  • main's code is kept, including its UK area routing helpers.
  • The UK region type and input dataset entity data fixes above went with the deleted functions.
  • The compiled reform None check and the compiled policy variable rename (runtime_policy) still apply.
  • The second commit is now "Type the simulation runtime's compiled-policy reads".
  • The baseline and the registry count were regenerated from a Pyright run, not merged by hand, and docs/generated/rules.md was regenerated with python -m scripts.rules render.
Commit Errors fixed Baseline after
Open the simulation runtime's spans with the typed span scope 0 68
Type the simulation runtime's compiled-policy reads 2 66

Baseline at this PR's head: 66 entries (main has 68).

Testing

  • python -m scripts.rules pyright --sync: the executor passes with its 66 baselined errors; every other package matches its rule (gateway 0, apis-integ 4 baselined, the libraries and entry 0).
  • Executor unit tests: 1865 passed, 22 skipped.
  • Quality guards, the rules tool's tests (191) and ruff 0.15.22 format and check: pass. No new noqa, type: ignore or pyright: ignore.

This PR is now the bottom of the stack, so its CI runs in full.

🤖 Generated with Claude Code

@anth-volk
anth-volk added this pull request to stack #867 October 21, 2026 15:11
@anth-volk
anth-volk force-pushed the pyright-executor-runtime branch 3 times, most recently from 3724c77 to 53cea05 Compare October 21, 2026 16:59
@anth-volk
anth-volk force-pushed the pyright-executor-runtime branch 2 times, most recently from 75b2e5a to 9258240 Compare October 21, 2026 21:37
@anth-volk
anth-volk force-pushed the pyright-executor-runtime branch from 9258240 to 21be642 Compare October 21, 2026 22:16
Base automatically changed from pyright-executor-modal to main October 22, 2026 13:01
@anth-volk
anth-volk force-pushed the pyright-executor-runtime branch 3 times, most recently from fde2bcb to de86f9d Compare October 26, 2026 11:55
anth-volk and others added 2 commits October 26, 2026 16:26
#879 already opens the annual run's eight request, dataset, policy and
simulation-build spans in simulation_runtime.py with scopes.span, and
annotates _build_simulation as returning the StageReportingSimulation
that _report_calculation_start needs. This commit opens the ninth span,
credential setup in setup_gcp_credentials, the same way, and documents
why _build_simulation returns a StageReportingSimulation in both
branches (ArtifactBaselineSimulation subclasses it).

Neither change alters what a run does, and the executor's baseline stays
at 68 entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The last 2 Pyright errors in simulation_runtime.py, without changing
what a run does:

- _compile_interval_policy: compile_reform returns None only for an
  empty policy, which the function has already returned, so a None
  result now returns the policy unchanged instead of failing on
  .items().
- _build_simulation reassigned its `policy: dict | None` parameter to
  the compiled policy, which may be a Policy; the result now has its own
  name, runtime_policy, used where the reassigned name was.

The UK weight-matrix fallback, whose region-type and entity-data reads
this change also typed before, has since been removed from main, so
those two fixes are no longer part of it.

The executor's baseline drops from 68 entries to 66, and
docs/generated/rules.md is rendered again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk force-pushed the pyright-executor-runtime branch from de86f9d to 10fa9fa Compare October 26, 2026 12:27
@anth-volk
anth-volk marked this pull request as ready for review October 26, 2026 12:54
@anth-volk
anth-volk requested a review from a team as a code owner October 26, 2026 12:54
@anth-volk
anth-volk merged commit 7de689e into main Oct 26, 2026
24 checks passed
@anth-volk
anth-volk deleted the pyright-executor-runtime branch October 26, 2026 12:55
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.

Fix the executor simulation runtime's 54 Pyright errors

1 participant