Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
d59359c
Call the Simulation Entrypoint's household report routes through its …
anth-volk Oct 29, 2026
99b6c86
Submit household reports at POST /v2/reports, checking the household …
anth-volk Oct 29, 2026
5fcc26d
Read and list household reports through /v2/reports, beside economy r…
anth-volk Oct 29, 2026
53a7002
Run household reports again at POST /v2/reports/{report_id}/runs, wit…
anth-volk Oct 29, 2026
0d78c5a
Save household report IDs in saved reports after checking them with t…
anth-volk Oct 29, 2026
d0b8630
Check household reports against migrated Postgres as the runtime role
anth-volk Oct 29, 2026
3ebc27d
Register household reports in the route contracts
anth-volk Oct 29, 2026
61cb7e0
Name the household report's calculation schemas for household reports
anth-volk Oct 29, 2026
df8d714
Answer 503 when the installed simulation client has no household repo…
anth-volk Oct 29, 2026
cf34b6e
Name a new household run's version without a database read, and check…
anth-volk Oct 29, 2026
b8ef2b0
Say in the runs list's 404 that household reports do not list their runs
anth-volk Oct 29, 2026
7ae76ea
Test that only a missing report of one kind sends a request to the ot…
anth-volk Oct 29, 2026
060ef7b
Answer 503 when a household report answer's nested values do not parse
anth-volk Oct 29, 2026
0433f5c
Test the default saved-report check with fake services instead of a t…
anth-volk Oct 29, 2026
fbd14a0
Check the types of household report fields the generated client copie…
anth-volk Oct 29, 2026
c509918
Leave an unreadable economy report out of a listing without a househo…
anth-volk Oct 29, 2026
2a0765d
Keep the economy refusal for a country with neither kind, and describ…
anth-volk Oct 29, 2026
423bb3b
Let a household report ask for every variable the household lacks
anth-volk Oct 29, 2026
5c1afd8
Say which variables a household report adds, and that a re-run keeps …
anth-volk Oct 29, 2026
a509419
Remove the households the household report integration test stores
anth-volk Oct 30, 2026
202880c
Check for households left behind after the removal commits, in its ow…
anth-volk Oct 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/v2-integration-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ jobs:
run: uv run coverage run --branch -m pytest -q tests/integration/test_v2_catalog_installed.py
env:
RUN_V2_CATALOG_COMPATIBILITY: "1"
- name: Test v2 metadata publication, resource routes, the countries list and economy reports
run: uv run coverage run -a --branch -m pytest -q tests/integration/test_v2_catalog_publication.py tests/integration/test_v2_metadata_routes.py tests/integration/test_v2_country_routes.py tests/integration/test_v2_economy_reports.py
- name: Test v2 metadata publication, resource routes, the countries list and economy and household reports
run: uv run coverage run -a --branch -m pytest -q tests/integration/test_v2_catalog_publication.py tests/integration/test_v2_metadata_routes.py tests/integration/test_v2_country_routes.py tests/integration/test_v2_economy_reports.py tests/integration/test_v2_household_reports.py
- name: Test v2 policy persistence and immediate v1 mirroring
run: uv run coverage run -a --branch -m pytest -q tests/integration/test_v2_policy_persistence.py tests/integration/test_v1_policy_dual_write.py tests/integration/test_mysql_policy_dual_write.py tests/integration/test_v2_user_policy_mirroring.py tests/integration/test_v1_user_policy_dual_write.py
- name: Test signed-in identity provisioning and user associations
Expand Down
1 change: 1 addition & 0 deletions changelog.d/v2-household-reports.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Household reports at /v2/reports: a household stored through /v2/households under a baseline and an optional reform, calculated by the simulation service for the household's default year, for any country with household calculations, including a household-only one.
15 changes: 13 additions & 2 deletions docs/engineering/migration-contracts.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Generated from `policyengine_api/migration_registry.py` and `tests/contract/regi
| Metric | Count |
| --- | ---: |
| route group count | 9 |
| workflow count | 18 |
| request count | 96 |
| workflow count | 19 |
| request count | 99 |
| db entity count | 6 |
| sim flow count | 3 |

Expand Down Expand Up @@ -213,6 +213,17 @@ Generated from `policyengine_api/migration_registry.py` and `tests/contract/regi
| `POST` | `/v2/reports/{report_id}/runs?country_id=us` | 201 | `report` | none | `status`, `message`, `result.item.id`, `result.item.trigger`, `result.item.tax_benefit_model_version_id`, `result.item.policyengine_version`, `result.item.status` |
| `GET` | `/v2/reports/{report_id}/runs?country_id=us` | 200 | `report` | none | `status`, `message`, `result.items` |

### `household_reports_v2`

- Current contract: `typed_v2_resources`
- Future owner: Household reports on v2

| Method | Path | Status | Route group | Required headers | Stable response fields |
| --- | --- | ---: | --- | --- | --- |
| `POST` | `/v2/reports?country_id=uk` | 201 | `report` | none | `status`, `message`, `result.item.id`, `result.item.country_id`, `result.item.kind`, `result.item.year`, `result.item.household_id`, `result.item.baseline_simulation_id`, `result.item.reform_simulation_id`, `result.item.status`, `result.item.run` |
| `GET` | `/v2/reports/{report_id}?country_id=uk` | 200 | `report` | none | `status`, `message`, `result.item.id`, `result.item.kind`, `result.item.status`, `result.item.run.baseline.result`, `result.item.run.reform.result` |
| `POST` | `/v2/reports/{report_id}/runs?country_id=uk` | 201 | `report` | none | `status`, `message`, `result.item.kind`, `result.item.id`, `result.item.trigger`, `result.item.tax_benefit_model_version_id`, `result.item.policyengine_version`, `result.item.status` |

### `metadata_resources_v2_preview`

- Current contract: `typed_v2_resources`
Expand Down
64 changes: 62 additions & 2 deletions docs/generated/migration_contracts.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"metadata": {
"db_entity_count": 6,
"request_count": 96,
"request_count": 99,
"route_group_count": 9,
"sim_flow_count": 3,
"workflow_count": 18
"workflow_count": 19
},
"route_groups": [
{
Expand Down Expand Up @@ -1471,6 +1471,66 @@
}
]
},
{
"current_contract": "typed_v2_resources",
"future_owner_pr": "Household reports on v2",
"name": "household_reports_v2",
"requests": [
{
"expected_status": 201,
"headers": [],
"method": "POST",
"path": "/v2/reports?country_id=uk",
"route_group": "report",
"stable_response_fields": [
"status",
"message",
"result.item.id",
"result.item.country_id",
"result.item.kind",
"result.item.year",
"result.item.household_id",
"result.item.baseline_simulation_id",
"result.item.reform_simulation_id",
"result.item.status",
"result.item.run"
]
},
{
"expected_status": 200,
"headers": [],
"method": "GET",
"path": "/v2/reports/{report_id}?country_id=uk",
"route_group": "report",
"stable_response_fields": [
"status",
"message",
"result.item.id",
"result.item.kind",
"result.item.status",
"result.item.run.baseline.result",
"result.item.run.reform.result"
]
},
{
"expected_status": 201,
"headers": [],
"method": "POST",
"path": "/v2/reports/{report_id}/runs?country_id=uk",
"route_group": "report",
"stable_response_fields": [
"status",
"message",
"result.item.kind",
"result.item.id",
"result.item.trigger",
"result.item.tax_benefit_model_version_id",
"result.item.policyengine_version",
"result.item.status"
]
}
]
},
{
"current_contract": "typed_v2_resources",
"future_owner_pr": "Later metadata read cutover and v2 route-prefix removal",
Expand Down
84 changes: 82 additions & 2 deletions policyengine_api/fastapi_routes/dependencies.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,13 @@
SimulationReferenceChecker,
)
from policyengine_api.services.v2.countries.types import CountryRead
from policyengine_api.services.v2.economy_reports.types import EconomyReportFields
from policyengine_api.services.v2.economy_reports.types import (
EconomyReportFields,
EconomyReportListing,
)
from policyengine_api.services.v2.household_reports.types import (
HouseholdReportSimulation,
)
from policyengine_api.services.v2.households.types import (
HouseholdPage,
HouseholdRead,
Expand Down Expand Up @@ -62,6 +68,9 @@
PolicyPage,
PolicyRead,
)
from policyengine_api.services.v2.report_kinds.types import (
HouseholdReportOperations as V2HouseholdReportResourceService,
)
from policyengine_api.services.v2.simulation_entrypoint.types import (
EconomyReportRecord,
EconomyReportRunRecord,
Expand Down Expand Up @@ -382,6 +391,12 @@ def list_reports(
"""Return the country's reports among ``report_ids``, in order, once each."""
...

def find_reports(
self, *, country_id: str, report_ids: Sequence[UUID]
) -> EconomyReportListing:
"""List the country's reports among ``report_ids``, naming the unreadable."""
...

def list_report_runs(
self, *, country_id: str, report_id: UUID
) -> tuple[EconomyReportRunRecord, ...]:
Expand Down Expand Up @@ -901,6 +916,57 @@ def _default_v2_economy_report_service_factory() -> V2EconomyReportResourceServi
)


def _default_household_report_simulation() -> HouseholdReportSimulation:
"""Return the process's adapter for the entrypoint's household report routes.

Raise ``SimulationServiceUnavailableError`` when the generated client is
not installed or has no household report routes (a client generated
before them, whose import fails with ``ImportError``), or the entrypoint
URL or gateway auth is unusable.
"""
try:
from policyengine_api.libs.simulation_household_reports import (
shared_household_reports,
)
except ImportError as error:
if (error.name or "").split(".")[0] != SIMULATION_CLIENT_PACKAGE:
raise
msg = (
"the generated simulation client (policyengine-api-simulation-client) "
"is not installed or has no household report routes"
)
raise SimulationServiceUnavailableError(msg) from error
return shared_household_reports()


def _default_v2_household_report_service_factory() -> V2HouseholdReportResourceService:
"""Build the household report service; the adapter waits for its first call.

Refusals the Public API decides itself, such as a household-only
country's missing household, then answer without the simulation client.
"""
from policyengine_api.data.v2.database import (
get_v2_session_factory,
)
from policyengine_api.services.v2.household_reports.database_session import (
HouseholdReportDatabaseSession,
)
from policyengine_api.services.v2.household_reports.services import (
DeferredHouseholdReportSimulation,
V2HouseholdReportService,
)

return V2HouseholdReportService(
HouseholdReportDatabaseSession(get_v2_session_factory()),
households=_default_v2_household_service_factory(),
policies=_default_v2_policy_service_factory(),
simulation=DeferredHouseholdReportSimulation(
_default_household_report_simulation
),
current_policyengine_version=_running_policyengine_version(),
)


def _default_v2_policy_service_factory() -> V2PolicyResourceService:
from policyengine_api.data.v2.database import (
get_v2_session_factory,
Expand Down Expand Up @@ -987,11 +1053,19 @@ def _default_legacy_reference_checker() -> LegacyReferenceChecker:

def _default_simulation_reference_checker() -> SimulationReferenceChecker:
"""Defer the simulation client until a request checks a v2 reference."""
from policyengine_api.services.v2.household_reports.services import (
DeferredHouseholdReportSimulation,
)
from policyengine_api.services.v2.simulation_refs.services import (
SimulationReferenceService,
)

return SimulationReferenceService(_deferred_economy_report_simulation())
return SimulationReferenceService(
_deferred_economy_report_simulation(),
household_reports=DeferredHouseholdReportSimulation(
_default_household_report_simulation
),
)


def _default_v2_user_policy_service_factory() -> V2UserPolicyResourceService:
Expand Down Expand Up @@ -1091,6 +1165,9 @@ class NativeRouteDependencies:
v2_economy_report_service_factory: (
Callable[[], V2EconomyReportResourceService] | None
) = None
v2_household_report_service_factory: (
Callable[[], V2HouseholdReportResourceService] | None
) = None
v2_policy_service_factory: Callable[[], V2PolicyResourceService] | None = None
v2_household_service_factory: Callable[[], V2HouseholdResourceService] | None = None
v2_user_policy_service_factory: Callable[[], V2UserPolicyResourceService] | None = (
Expand Down Expand Up @@ -1125,6 +1202,9 @@ def defaults(cls) -> NativeRouteDependencies:
v2_economy_report_service_factory=(
_default_v2_economy_report_service_factory
),
v2_household_report_service_factory=(
_default_v2_household_report_service_factory
),
v2_policy_service_factory=_default_v2_policy_service_factory,
v2_household_service_factory=_default_v2_household_service_factory,
v2_user_policy_service_factory=(_default_v2_user_policy_service_factory),
Expand Down
Loading
Loading