Repository navigation
Conversation
…generated client The adapter submits a household report (a stored household under a baseline and an optional reform), reads it, and starts another run, and turns the entrypoint's declared answers into the errors the economy report adapter already uses: a 404 naming the report is not found, a 422 carries the entrypoint's reason, and a 400, a 503 or an unreadable answer means the entrypoint cannot be used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and policies first A submission of kind household names a stored household, a baseline policy and an optional reform policy. Before the simulation service is asked, the country must have household calculations (a household-only country does), the household and each policy must be the country's, and the household must have a default year, the year the report calculates. The answer names the PolicyEngine.py version of the run's catalog version, read from the catalog. Economy submissions reach the economy report service as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eports A report read by its ID is looked for among the country's economy reports and then among its household reports; a report of neither kind is a 404 that names no kind. A listing holds both kinds in the order asked, household reports without their calculations. A failure other than "not found", such as an unavailable simulation service, is never taken for a missing report. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…h force A report that is not an economy report of the country is looked for among its household reports and run again on the current catalog version, with the manual trigger; force recalculates both households. A household-only country can run its household reports again, and keeps refusing its other report IDs as before. Every run item now names its kind, so a run answer is one of the two kinds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he simulation service A saved report's v2 ID that is not one of the country's economy reports is looked for among its household reports before it is saved, so a user can keep a household report in their account. A household report holds no v1 report number, so a saved report naming both a household report and a v1 report is refused as a conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cross-database integration check now submits, reads and runs again a household report of a household-only country through the routes, reading the countries row, the stored household and the catalog version as the runtime role, and checks that the country still refuses economy reports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The household report requests of /v2/reports (submit, read and re-run) join the workflow contracts, and the generated migration contract documents are exported again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The household calculation routes have their own HouseholdCalculationItem schema, so the report's calculation items are HouseholdReportCalculation* and both can be served from one OpenAPI document without one replacing the other. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rt routes A client generated before the household report routes existed makes the adapter's import fail with ImportError, not ModuleNotFoundError, which answered 500; economy reads of an unknown report reach the household adapter too. It now means the simulation service is unavailable, and the adapter's tests skip with such a client instead of failing to import. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the country first on a re-run A run the service starts is on the catalog version of the PolicyEngine.py version it sent, so the submission's and re-run's answers name that version instead of reading the catalog after the simulation service has acted; a database failure there answered 503 for a report that already existed. A re-run checks the country's household calculations before reading the report, as economy re-runs check theirs, so that refusal does not depend on the simulation service being reachable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /v2/reports/{report_id}/runs serves only economy reports, so its 404
says so instead of "no report has this ID", which is wrong for a household
report the report route returns.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…her kind An unavailable simulation service, on either kind's routes, fails the read, listing or re-run instead of being taken for a report that is missing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The generated client keeps a nested value it cannot parse as it came, such as a run status it does not know or a calculation of another shape, so building the record raised AttributeError or KeyError after the parse and answered 500. The record is now built under the same rule as the parse: an answer that does not parse means the simulation service cannot be used. Two descriptions also catch up: which 400s the Public API cannot rule out itself, and where a run's PolicyEngine.py version comes from. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…est-only property The default checker is now shown to look for household reports by checking a household report ID through it, with the simulation adapters replaced by fakes, so SimulationReferenceService loses the property only that test read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s unchecked The generated models copy nullable UUIDs and date-times, the country and the warnings as they came, so a value of another type reached the strict response models and answered 500. The adapter checks each such field's type while it builds the record, and an answer that fails the check means the simulation service cannot be used (503). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ld lookup A listing left out an economy report whose stored result cannot be read back, and then looked for its ID among household reports, so an unavailable household route answered 503 where the economy listing alone answered 200. The economy service now names the unreadable IDs beside the reports it lists, and only IDs it does not have are looked for among household reports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e re-runs of both kinds Re-running a report ID in a country with neither economy reports nor household calculations answers the economy refusal it answered before, instead of the household one. The re-run request's description covers both kinds' reuse rules, and the household report check takes the report's ID as a UUID. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A household report can set add_missing_variables, which the simulation service applies to both calculations, as /calculate-full and the household calculation routes do. Without it, a household stored with its inputs alone came back with none of the values a report shows, such as net income. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the choice Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## v2plan/2a-202-v2-economy-reports #4132 +/- ##
====================================================================
- Coverage 87.38% 85.66% -1.73%
====================================================================
Files 286 296 +10
Lines 17144 17612 +468
Branches 2760 2813 +53
====================================================================
+ Hits 14981 15087 +106
- Misses 1461 1816 +355
- Partials 702 709 +7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
This branch was successfully 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.
Fixes #4131
Summary
Adds the household kind of
/v2/reports. A household report calculates a household stored through/v2/householdsunder a baseline policy and an optional reform policy, each a/v2/policiespolicy or current law, for the household'sdefault_year. The simulation service calculates and stores it through its/v2/household-reportsroutes, as it does economy reports.Submit:
POST /v2/reportstakes a body discriminated onkind. Economy bodies are unchanged. A household body is{"kind": "household", "country_id", "household_id", "baseline": {"policy_id"}, "reform": {"policy_id"} | null, "add_missing_variables": false}, with no year: the simulation service calculates the household's default year. Withadd_missing_variables, both calculations add every yearly, monthly and eternal variable the household lacks, as/calculate-fulldoes; a re-run keeps the choice. Before asking it, the Public API checks, in the household calculation routes' order, that:countriesrow hashousehold_enabled(otherwise 422);A household-only country passes, and still gets 422 for economy reports.
Read and list:
GET /v2/reports/{report_id}andGET /v2/reports?report_id=…look among the country's economy reports first, then among its household reports. A household report carries its newest run with the baseline's and the reform's calculated households, warnings and SPM receipt. Listings leave out the calculations, as they leave out economy results.Re-run:
POST /v2/reports/{report_id}/runsruns a household report again on the current catalog version, with themanualtrigger, reusing calculations unlessforceis set. A household-only country can re-run its household reports.Saved reports:
/v2/user-reportsaccepts a household report ID after checking it with the simulation service. A household report holds no v1 report number, so saving one together with a v1 report is refused as a conflict.Unchanged and economy-only:
GET /v2/reports/{id}/runsandGET /v2/reports/by-legacy-number/{n}. The simulation service has no household equivalents; the runs list's 404 description says so.Errors:
Changes to the economy kind:
kind: "economy", so a run answer is either kind.POST /v2/reportsdeclares 404.find_reports, whichlist_reportsnow calls and which also names the reports whose stored result cannot be read back. Those reports are still left out of listings, and never looked for among household reports.Household-report code is in modules of its own:
services/v2/household_reports/,services/v2/report_kinds/(which sends each operation to the right kind),libs/simulation_household_reports.pyandfastapi_routes/v2/reports/household_response_models.py. The household report schemas are namedHouseholdReport*, so they do not collide with the household calculation routes'HouseholdCalculation*schemas.Migration PR checklist:
/v2/reports), and user reports (/v2/user-reports)./v2/reports, and the economy changes listed above.Waits for before merging
/v2/reports), which this branch builds on, and the PRs it waits for./v2/household-reports. The economy routes from Run and store v2 economy reports in the Simulation Entrypoint policyengine-sim-api#974 must be deployed as well.policyengine-api-simulation-clientthat contains both the economy and the household report routes (an operator step). Until then, every household path answers 503 when deployed. The tests here ran against a client generated locally from the two simulation service branches' OpenAPI documents together; no shared path or schema differs between them.This branch does not merge in #4092 (household calculations). Its checks before submitting are reimplemented here, because #4092 sits on a different stack.
Environment variables
No new variables. The new code reads:
SIMULATION_ENTRYPOINT_URL: GitHub environment secret (staging,production) → jobenv:of the Cloud Run deploy jobs inpush.yml→deploy_cloud_run_candidate.sh→ Cloud Run runtime, as the economy report routes do.GATEWAY_AUTH_ISSUER,GATEWAY_AUTH_AUDIENCE,GATEWAY_AUTH_CLIENT_IDandGATEWAY_AUTH_CLIENT_SECRET_RESOURCE: organization secrets → the deploy step'senv:→ the deploy script → Cloud Run runtime. The client secret is read from Secret Manager at runtime. These are the values the economy report adapter already uses.countriesrow, the stored household and policies, andtax_benefit_model_versions; the runtime role already has SELECT on all of them.Not verified:
simulation:submitandsimulation:readfor the simulation service's audience;GATEWAY_AUTH_CLIENT_SECRET_RESOURCEnames;SIMULATION_ENTRYPOINT_URLserves a revision with the household report routes.The integration workflow change adds one test module to an existing step. Its database URL and settings are the job's literal disposable values (
V2_MIGRATION_DATABASE_URL,V2_ALEMBIC_DISPOSABLE_TEST,DEPLOYMENT_ENVIRONMENTin the job'senv:).Inline suppressions
None added.
Testing
Each commit was built test-first. Three review rounds, then one extra round for the
add_missing_variablesoption, which was added after them.ruff format,ruff check,mypy,scripts/run_quality_guards.pyandscripts/export_migration_contracts.pypass.Notes for reviewers
policyengine_versionis the version the Public API sent. A run read back takes its version from the catalog.🤖 Generated with Claude Code