Move Stage 12 output planning behind country-owned typed contracts
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 5/5
- Temps estimé
- Plus d'une semaine
- Accessibilité débutants
- 35/100
Piste de recherche
Start by reading stage12_runtime/output_planning.py, SimulationOutputBuilder.serialize(), and the Stage 12 wire-contract definitions; the issue requires documenting current US and UK outputs and their dataset sources before implementation. Then investigate the country-owned policyengine configuration and tests to map calculated, conditional, and preserved columns. Done means a coordinated, versioned planning interface and service conversion satisfy the listed contract, validation, integration, and migration criteria.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Context
Stage 12 must determine the complete output schema before it dispatches the independent baseline and reform simulations. The current implementation in stage12_runtime/output_planning.py does this by constructing data-free Simulation objects with model_construct(), invoking country configuration functions, asking the country model to resolve entity variables, and combining those calculated variables with dataset columns known to the simulation service.
This fixed the immediate failure mode where RequestedSimulationOutput(variables=("*",)) did not materialize every column later consumed by SimulationOutputBuilder. It also gave both child simulations one typed, deterministic plan whose hash can be verified before aggregation.
Issue #707 and PR #708 add timing around this work. They intentionally do not change the planning behavior. This issue tracks the broader cleanup that should follow after #708 is integrated.
Problem
The current implementation has several fragile integration boundaries:
- The simulation service creates partially initialized
Simulationinstances withSimulation.model_construct(..., dataset=None, ...). This bypasses normal model validation and assumes that every output configurator only reads policy, model, andextra_variables. - Output requirements are maintained in two places. The planner predicts which variables the existing report serializer will consume, but the serializer does not expose a typed declaration of those dependencies. A serializer change can therefore make the plan incomplete.
- The simulation service contains country- and dataset-specific knowledge, including UK source columns such as
constituency_code_oaandla_code_oa. - The current
ReportOutputRequirementslooks selective, but Stage 12 requires the complete aggregate profile. Only cliff-impact and labor-supply options currently change the plan. - Frame validation proves that entities and columns exist, but it does not express stronger contracts such as expected data types, nullability, units, or whether a column is calculated or copied from a specific dataset version.
- The planner depends directly on mutable
Simulation.extra_variablesand the internal behavior ofresolve_entity_variables()instead of a dedicated, supported planning interface. - PR #708 passes observability stages into the planner. The instrumentation is useful, but the domain planner should not need to depend on service-specific observability types.
Desired architecture
Make the policyengine package the source of truth for country-owned report-output planning, and keep the simulation service responsible for distributed execution.
policyengine package
Add a public, strongly typed planning interface that accepts explicit report requirements, baseline and reform policy configuration, country, and dataset metadata. It should return a deterministic declaration of:
- calculated variables required for each entity;
- variables added conditionally for labor-supply responses or cliff impacts;
- source-dataset columns that must be preserved;
- any schema metadata needed to validate those outputs.
The interface must not require the caller to construct an invalid or data-free Simulation. It may use a dedicated validated planning context internally.
The report serializer and output planner must share one dependency declaration. Adding a new calculation to a report must either automatically add its required variables to the plan or fail a focused contract test in the package that owns the report calculation.
Dataset-provided columns must come from typed dataset metadata or another country-owned declaration. policyengine-sim-api must not contain a hard-coded list of UK dataset columns.
The package-level types must avoid an inverse dependency on policyengine-simulation-contract. If wire-contract types remain in the simulation repository, add an explicit conversion layer between the package planning result and Stage12OutputPlan.
policyengine-sim-api
Reduce stage12_runtime/output_planning.py to orchestration:
- Validate the Stage 12 report request.
- Convert it into the public
policyengineplanning request. - Invoke the package planning interface once.
- Convert the result into the versioned Stage 12 wire contract.
- Send the identical immutable plan to the baseline and reform workers.
- Retain deterministic sorting, hashing, bundle-provenance checks, row-identity checks, and output-frame validation.
Move timing concerns to the coordinator or inject a neutral planning-observer protocol. The package-facing planner must not import the simulation service's Stage enumeration.
Required investigation
Before implementation, document:
- every output currently consumed by
SimulationOutputBuilder.serialize()for US and UK reports; - which variables are calculated, which are source-dataset columns, and which are conditional;
- the supported dataset/version source for each preserved column;
- whether the complete Stage 12 report profile should remain the only supported profile or whether requirements should become genuinely selective;
- which validation attributes are stable enough to include in the public contract beyond entity and column names;
- the compatibility and release sequence required between
policyenginebundles andpolicyengine-sim-api.
Acceptance criteria
- Stage 12 no longer calls
Simulation.model_construct()to discover output requirements. -
policyengineexposes a documented, strongly typed report-output planning interface for both US and UK. - The report serializer and planner use one source of truth for required calculated variables.
- Dataset-provided columns are declared by country/dataset-owned code or metadata, not hard-coded in
policyengine-sim-api. - The same deterministic plan is still sent to both Stage 12 child simulations.
- Plans remain versioned, canonically ordered, and hashable.
- Child workers still validate their materialized frames before publishing artifacts.
- The coordinator still rejects artifacts with mismatched plans, bundle provenance, roles, output schemas, or row identity.
- The planning interface fails explicitly for unsupported countries, datasets, report profiles, and unavailable source columns.
- Unit tests cover US and UK planning, budget outputs, geographic outputs, cliff impacts, active and inactive labor-supply responses, unsupported datasets, and missing declared columns.
- Contract tests prove that every column consumed by the report serializer is present in the declared output plan.
- Integration tests run baseline and reform children independently and successfully aggregate their validated artifacts.
- Observability continues to distinguish country-model loading, output configuration, variable resolution, and child-input preparation without coupling package domain types to service observability types.
- Migration and release documentation states the minimum compatible
policyenginebundle and the required cross-repository merge/deployment order.
Non-goals
- Removing the typed Stage 12 plan or its hash.
- Combining the independently executed baseline and reform simulations.
- Moving distributed execution or artifact persistence into the
policyenginepackage. - Preserving the current internal planning implementation for backward compatibility; Stage 12 and its certified bundle can move together to the new versioned interface.
Relationship to current work
- #707 / #708 should land independently because their measurements are needed to establish the current preparation cost and confirm the effect of this cleanup.
- This work should be divided into coordinated
policyengineandpolicyengine-sim-apichanges, with the package interface released before the simulation service begins consuming it.
- Langage dominant
- Python
- Étoiles
- 1
- Forks
- 1
- Merge moyen
- 1 j 7 h
- PR mergées (30 j)
- 24
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de PolicyEngine/policyengine-sim-api
-
Integration tests fail due to missing UV virtual environment setupPeut-être pris Une pull request liée à cette issue est ouverte ou déjà fusionnée. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 65/100
PolicyEngine/policyengine-sim-api#314 ·
Les mainteneurs répondent en général sous 1 jour
-
Update policyengine to 6.2.3Peut-être pris @policyengine l’a pris aujourd’hui. Ouverte
Difficulté 1/5 Moins d'une heure Accessibilité débutants 15/100
PolicyEngine/policyengine-sim-api#734 ·
Les mainteneurs répondent en général sous 1 jour
-
Upgrade simulation workers to the forthcoming UK region-filter fixPeut-être pris @anth-volk l’a pris aujourd’hui. Ouverte
Difficulté 3/5 1-3 heures Accessibilité débutants 15/100
PolicyEngine/policyengine-sim-api#732 ·
Les mainteneurs répondent en général sous 1 jour
-
Update policyengine to 6.2.2Peut-être pris @policyengine l’a pris il y a 1 jour. Ouverte
Difficulté 1/5 Moins d'une heure Accessibilité débutants 20/100
PolicyEngine/policyengine-sim-api#730 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 5/5 Plus d'une semaine Accessibilité débutants 35/100
PolicyEngine/policyengine-sim-api#728 ·
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de PolicyEngine/policyengine-sim-api
Issues similaires
-
Difficulté 1/5 Moins d'une heure Accessibilité débutants 85/100
MystenLabs/MemWal#1163 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
infertopics leaves new nodes without a topic when untopiced neighbours outnumber topiced onesPeut-être pris @moneebullah25 l’a pris aujourd’hui. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 72/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 70/100
FinanceFlash/unvibecode#218 ·
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
Les mainteneurs répondent en général sous 1 jour
-
Difficulté 2/5 1-3 heures Accessibilité débutants 70/100
NVIDIA/earth2studio#1241 ·
Les mainteneurs répondent en général sous 3 jours