Skip to content

Remove the None presets and checks around Stage 12 span and operation blocks - #965

Merged
anth-volk merged 2 commits into
mainfrom
remove-span-none-presets
Oct 27, 2026
Merged

anth-volk merged 2 commits into
mainfrom
remove-span-none-presets

Conversation

@anth-volk

Copy link
Copy Markdown
Contributor

Fixes #964

Removes the None presets and None checks that #712 put around Stage 12 span and operation blocks so Pyright, reading policyengine-observability's scopes as possibly suppressing an exception, would not report their values as possibly unbound. Since #959, every package uses 3.0.4, whose scopes are annotated as returning Literal[False] from __exit__ and __aexit__ and return False on every path, so each block either assigns its value or its exception reaches the caller.

What is removed, and why each check could not fail

Module and function Removed Value assigned in the block
src/modal/v2_app.py run_single_simulation_segment_us result = None, "Stage 12 segment calculation returned no result" calculate_segment(...).model_dump(mode="python"), a dict
src/modal/v2_app.py run_single_simulation_us result = None, "Stage 12 US simulation returned no result" run_single_simulation(...), typed dict[str, Any]; every path returns a dict or raises
src/modal/v2_app.py run_single_simulation_uk result = None, "Stage 12 UK simulation returned no result" the same function
src/modal/v2_app.py coordinate_report result = None, "Stage 12 report coordinator returned no result" stage12_runtime.coordinate_report(...), typed dict[str, Any]; every path returns a dict or raises
stage12_runtime/fanout.py Stage12SegmentRunner.run, dispatch span call = None and _require_call, "Stage 12 segment dispatch returned no call" the FunctionCall that modal 1.4.2's Function.spawn creates and returns on every path (it raises for a generator function, and the segment function is not one)
stage12_runtime/fanout.py Stage12SegmentRunner.run, wait span payloads: list[object] | None = None, "Stage 12 segment wait returned no payloads" _collect(...), typed list[object]; returns a list or raises
stage12_runtime/fanout.py Stage12SegmentRunner.run, merge span merged: SimulationCalculation | None = None, "Stage 12 segment merge returned no calculation" merge_segment_results(...), which returns a SimulationCalculation

The four Modal functions and the merge now return from inside their block, because ruff's RET504 rejects assigning a value only to return it. The scope still ends, and each Modal function's runtime still shuts down, before the function returns.

A search of the executor, gateway and entrypoint src directories for any value set to None before a span, operation or other with block and used after it found one other: setup_gcp_credentials sets creds_file = None before an ExitStack block that leaves it unassigned when credentials are already configured or absent. That check is reachable and stays.

Tests

Removing unreachable code changes no behaviour, so there is no failing test to write first. The first commit adds tests that run every block involved, and they pass before and after the removal:

  • the four Modal functions with the observability runtime the services build (OpenTelemetry disabled), returning their result and passing an application error to the caller unchanged, never as a "returned no result" RuntimeError;
  • the segment runner with that runtime: a successful run, and an error in each of the dispatch, wait and merge blocks; and a merge failure with the existing recording runtime, the one block that had no failure test.

Checks

  • uv run --frozen pytest tests/ in projects/policyengine-simulation-executor: 1889 passed, 22 skipped, 3 deselected at both commits.
  • python -m scripts.rules pyright --sync projects/policyengine-simulation-executor: no errors at both commits.
  • ruff 0.15.22: ruff format --check projects/*/src libs/*/src and ruff check . pass.
  • python scripts/run_quality_guards.py, python -m scripts.rules guard --base-ref origin/main and python -m unittest discover -s scripts/rules/tests -t . pass; python -m scripts.rules render leaves no diff.

🤖 Generated with Claude Code

anth-volk and others added 2 commits October 28, 2026 00:36
…scopes

The Stage 12 Modal functions in v2_app.py and the segment runner in
stage12_runtime/fanout.py set a variable to None before a span or
operation block and check it after the block. The next commit removes
those presets and checks, which only satisfied Pyright before
policyengine-observability 3.0.4. These tests run every block involved
and pass on the current code.

- The existing v2_app tests run the four functions with a recording
  runtime whose operation is a generator context manager. Two new
  parametrized tests run them with the observability runtime the
  services build (OpenTelemetry disabled), through its real operation
  scope: each function returns its calculation's result, and an error
  raised in the block reaches the caller unchanged, never as the
  "returned no result" RuntimeError.
- The segment runner already had tests for its dispatch and wait blocks
  succeeding and failing. A new test makes the merge block fail, and four
  tests run the runner with the real runtime: a successful run, and an
  error raised in each of the dispatch, wait and merge blocks, which
  reaches the caller unchanged.
- conftest.py gains a real_observability_runtime fixture that builds that
  runtime, with Google Cloud logging unset, and shuts it down afterwards.
  The dispatch-failure setup moves into a helper the old and new
  dispatch tests share.

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

Before policyengine-observability 3.0.4, Pyright read the span and
operation scopes as possibly suppressing the exception raised in their
block. #712 therefore set each value a block assigns to None before the
block and raised a RuntimeError after it when the value was still None.
3.0.4 annotates the scopes' __exit__ and __aexit__ as returning
Literal[False], and they return False on every path, so the block either
assigns its value or its exception reaches the caller. None of the
assigned values can be None either:

- v2_app.py: run_single_simulation_segment_us returns
  calculate_segment(...).model_dump(mode="python"), a dict;
  run_single_simulation_us and run_single_simulation_uk return
  run_single_simulation(...), and coordinate_report returns
  coordinate_report(...), both typed dict[str, Any], and every path of
  each returns a dict or raises. Each function now returns from inside
  its operation block (ruff's RET504 rejects assigning and then
  returning); the operation still ends, and the runtime still shuts
  down, before the function returns.
- fanout.py: the dispatched call is the FunctionCall that modal 1.4.2's
  Function.spawn creates and returns on every path (it raises for a
  generator function, and the segment function is not one), so
  _require_call, the only check of it, is removed with the preset;
  _collect returns a list or raises; and merge_segment_results returns a
  SimulationCalculation, now from inside the merge span.

The removed RuntimeErrors could not be raised, so behaviour is unchanged
and there is no failing test to write: the tests added in the previous
commit, which run each block through the real runtime scopes, pass
before and after. Pyright still reports no errors in the executor.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@anth-volk
anth-volk marked this pull request as ready for review October 27, 2026 21:28
@anth-volk
anth-volk merged commit ac7f8fe into main Oct 27, 2026
23 of 24 checks passed
@anth-volk
anth-volk deleted the remove-span-none-presets branch October 27, 2026 21:28
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.

Remove the None presets and checks around Stage 12 span and operation blocks

1 participant