Skip to content

feat: Add modelled_policies field to TaxBenefitModel#93

Draft
SakshiKekre wants to merge 72 commits intomainfrom
feat/modelled-policies
Draft

feat: Add modelled_policies field to TaxBenefitModel#93
SakshiKekre wants to merge 72 commits intomainfrom
feat/modelled-policies

Conversation

@SakshiKekre
Copy link
Contributor

Summary

  • Add modelled_policies JSON field to TaxBenefitModel to store which policies are modeled per country
  • Extract data from country packages (policyengine-us, policyengine-uk) during seeding
  • Add Alembic migration for the new column

Context

The app-v2 needs to know which policies are modeled (e.g., Federal income tax, SNAP, state taxes). Previously this came from the v1 metadata endpoint. This PR adds it to the v2 API structure.

Test plan

  • Run migration: uv run alembic upgrade head
  • Re-seed: uv run python scripts/seed.py
  • Verify GET /tax-benefit-models/ returns modelled_policies

anth-volk and others added 30 commits February 17, 2026 00:39
feat: Add household support (CRUD, associations, impact analysis)
- Add Region SQLModel with filtering fields (code, label, region_type,
  requires_filter, filter_field, filter_value, dataset_id, etc.)
- Add Alembic migration for regions table
- Add GET /regions/ endpoint with filters by model and region type
- Add GET /regions/{region_id} and GET /regions/by-code/{code} endpoints
- Add region parameter to analysis endpoint with dataset/region resolution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add filter_field and filter_value to Simulation model
- Include filter params in deterministic simulation ID generation
- Pass filter params from region to simulation creation
- Pass filter params to policyengine.py PESimulation when running

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Wire filter_field/filter_value through Modal functions to policyengine.py:
  - simulate_economy_uk, simulate_economy_us
  - economy_comparison_uk, economy_comparison_us
- Add fixtures_regions.py with factory functions for test data
- Add 25 unit tests for region resolution and filtering:
  - test__given_region_with_filter__then_filter_params_included.py
  - test__given_region_without_filter__then_filter_params_none.py
  - test__given_dataset_id__then_region_is_none.py
  - test__given_same_params__then_deterministic_id.py
  - test__given_invalid_region__then_404_error.py
  - test__given_existing_simulation__then_reuses_existing.py

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add seed_regions.py to populate the regions table with geographic data
from policyengine.py's region registries:

- US: National + 51 states (DC included)
- UK: National + 4 countries (England, Scotland, Wales, NI)

Optional flags:
- --include-places: Add US cities (333 places over 100K population)
- --include-districts: Add US congressional districts (436)
- --us-only / --uk-only: Seed only one country

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add --skip-regions, --include-places, and --include-districts CLI options
to seed.py. Regions are now seeded as part of the standard database setup
process, sourcing region definitions from policyengine.py's registries.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Default behavior now seeds all US regions (national, states, districts, places).
Use --skip-places and --skip-districts to exclude specific region types.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Break up monolithic seed.py into focused subscripts:
- seed_utils.py: Shared utilities (get_session, bulk_insert, console)
- seed_models.py: TaxBenefitModel, Version, Variables, Parameters, ParameterValues
- seed_datasets.py: Dataset seeding and S3 upload
- seed_policies.py: Example policy reforms
- seed_regions.py: Geographic regions (updated to use seed_utils)

Main seed.py is now an orchestrator with preset configurations:
- full: Everything (default)
- lite: Both countries, 2026 only, skip state params, core regions
- minimal: Both countries, 2026 only, no policies/regions
- uk-lite, uk-minimal: UK-only variants
- us-lite, us-minimal: US-only variants

Each subscript can also run standalone with its own CLI.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Tests were written before _get_or_create_simulation and
_get_deterministic_simulation_id gained the simulation_type parameter.
Add SimulationType.ECONOMY and use keyword args for dataset_id/filter
params to match the current function signatures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Merge 6 separate test__given_* files into test_analysis.py organized
by function tested: TestResolveDatasetAndRegion, TestGetDeterministicSimulationId,
TestGetOrCreateSimulation. Fix pre-existing test_missing_dataset_id assertion
(400 not 422). Move @pytest.mark.integration from file-level to class-level.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This test hits the real database (valid request passes validation),
so it needs a running Supabase instance like the other integration tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
feat: Add regions support for geographic analysis
- Remove .DS_Store, docs/, and supabase/.temp/ from git tracking
- Add these patterns to .gitignore
- Update test_user_policies.py to include country_id in all tests
- Rename test_list_user_policies_filter_by_tax_benefit_model to
  test_list_user_policies_filter_by_country

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Move setup helpers (create_policy, create_user_policy) and constants
(US_COUNTRY_ID, UK_COUNTRY_ID) to test_fixtures/fixtures_user_policies.py.
Revert accidental supabase/.temp/cli-latest version change.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add extra='forbid' to UserPolicyUpdate so Pydantic returns 422 if
clients send fields beyond 'label' (e.g. user_id, policy_id).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The fixtures were passing tax_benefit_model_version_id (a non-existent
field, silently ignored by SQLModel) instead of tax_benefit_model_id
(now required). Updated create_policy fixture and its 3 call sites.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add user-policy associations and Alembic migrations
Two migrations (0002_user_policies and f419b5f4acba) both descended from
the initial schema, creating two Alembic heads. This empty merge migration
reconciles them into a single linear chain so future migrations can be added.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Simulation model already uses these fields for regional economy
simulations (e.g., filtering a dataset to a specific state), but no
Alembic migration created the columns. This aligns the DB schema with
the existing Python model.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
anth-volk and others added 26 commits February 20, 2026 19:17
52 tests covering:
- Income change formulas (V1 vs corrected), structure, classification, edge cases
- _safe_float sanitization, _build_response for all Phase 2 output fields
  (poverty, inequality, budget_summary, intra_decile, program_statistics,
  detailed_budget), pending/completed report states

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ase-2

Wire up all V1 economy comparison outputs (Phase 2 parity)
Create congressional_district_impacts table and wire per-district income
change computation into US economy comparison (local and Modal). Add
congressional_district_impact field to EconomicImpactResponse.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds ConstituencyImpact DB model, Alembic migration, and wires
constituency computation into both local and Modal UK economy
comparison paths. Uses GCS-hosted weight matrix and constituency CSV.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds LocalAuthorityImpact DB model, Alembic migration, and wires
computation into both local and Modal UK economy comparison paths.
Uses GCS-hosted weight matrix and local authority CSV.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ne.py

Migrate all intra-decile computation (UK+US, local+Modal) from the
API's inline intra_decile.py helper to policyengine.py's new
IntraDecileImpact output class.

Add wealth decile impact and intra-wealth-decile impact for UK
economy comparisons, using DecileImpact with decile_variable=
"household_wealth_decile". Add decile_type column to
intra_decile_impacts table to distinguish income vs wealth records.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extend fixtures with factory functions for congressional district,
constituency, local authority, wealth decile, and intra-wealth-decile
records. Add test classes verifying _build_response() populates all
new fields correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ase-3

Phase 3: Expensive computations — API wiring
Define ComputationModule dataclass and MODULE_REGISTRY with 10 modules
(decile, program_statistics, poverty, inequality, budget_summary,
intra_decile, congressional_district, constituency, local_authority,
wealth_decile) plus helper functions for country filtering and validation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Returns available economy analysis modules from the registry, with
optional country query param to filter by UK/US applicability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Accepts same inputs as /analysis/economic-impact plus a modules list.
Validates module names against the registry for the given country,
triggers computation, and filters the response to only include fields
for the requested modules. Includes GET polling endpoint with optional
modules query param.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tions

Move each module's computation logic (decile, poverty, inequality,
budget_summary, program_statistics, intra_decile, constituency,
local_authority, wealth_decile, congressional_district) into standalone
functions in computation_modules.py with UK/US dispatch tables.

The local economy comparison functions now call run_modules() with an
optional modules list, enabling selective computation from the
/analysis/economy-custom endpoint.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add comprehensive test coverage for module registry, analysis options,
economy-custom endpoint, and computation module dispatch system.
Includes lint/format fixes from ruff.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ase-4

Phase 4: Custom computation modules
Allows looking up parameters by their exact names for a given model,
returning ParameterRead[] for matches. Enables the app to fetch metadata
for specific parameters (e.g. those in a saved policy) without loading
the entire parameter catalog.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Accepts country_id and parent_path, returns direct children as nodes
(with child_count) or leaf parameters (with full metadata). Adds
COUNTRY_MODEL_NAMES mapping to constants for country_id resolution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Accepts a list of variable names and country_id, returns matching
VariableRead objects. Mirrors the parameters/by-name pattern for
targeted variable fetching without bulk loading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Returns the model and its latest version in a single response, keyed
by country_id (us/uk). Used on page load for model version checking
and cache invalidation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ers/by-name

Aligns the POST /parameters/by-name endpoint with GET /parameters/children
by accepting country_id ("us" or "uk") and resolving the model name
internally via COUNTRY_MODEL_NAMES.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ase-4a

feat: Phase 4a — Lazy parameter tree & model version endpoints
Add a 'testing' preset to seed.py that seeds only ~100 curated US
variables and ~100 parameters (by prefix), enabling fast local database
setup for integration testing.

Changes:
- SeedConfig: add variable_whitelist and parameter_prefixes fields
- seed_models.py: add whitelist/prefix filtering before row construction
- seed.py: add TESTING_VARIABLES, TESTING_PARAMETER_PREFIXES constants
- Wire new params through run_seed → seed_us_model → seed_model

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Policy model requires tax_benefit_model_id (NOT NULL), but
seed_policies.py was not passing it to the constructor.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add environment_name param to all modal.Function.from_name calls so
  functions resolve against the testing environment (not main)
- Add modal_environment setting to Pydantic Settings (default: testing)
- Install policyengine from app-v2-migration branch instead of PyPI
- Add pydantic-settings and git to Modal base image dependencies
- Use SUPABASE_SERVICE_KEY for storage access (private bucket)
- Add US variable pre-calculation step matching the UK function
- Use household_net_income for US decile impacts (matches v1 API)
- Bump economy_comparison_us memory to 24GB for full dataset processing
- Update .env.example with Modal environment documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add region_id foreign key to Simulation model for region provenance
- Alembic migration 963e91da9298 applied to deployed Supabase
- Pass region_id when creating economy simulations
- Fix polling endpoints to look up region from simulation.region_id
- Simplify _build_region_info to use direct FK instead of filter matching
- Add /reports/{id}/full and /user-reports/{id}/full composite endpoints
- Extend PolicyRead with parameter_values (ParameterValueWithName)
- Update policy endpoints to eager-load parameter values with names

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- POST /analysis/rerun/{report_id}: resets report + simulations to
  PENDING, deletes all result records, and re-triggers computation.
  Works for both economy and household reports.
- computation_modules: use country-specific income variable for decile
  impacts (household_net_income for US, equiv_household_net_income for
  UK) instead of hardcoded UK variable. Accepts country_id via kwargs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Base automatically changed from app-v2-migration to main March 5, 2026 18:54
Add ParameterNode model and migration to store folder structure labels
for the parameter tree (e.g., "HMRC" instead of "hmrc").

Changes:
- Add ParameterNode SQLModel with name, label, description fields
- Add Alembic migration for parameter_nodes table
- Update seed_models.py to seed nodes from policyengine.py
- Update /parameters/children to use node labels from DB

Requires: PolicyEngine/policyengine.py#254
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