Repository navigation
Calculate stored households through /v2/household-calculations - #4274
Merged
Merged
Conversation
…cks (failing) The request model's axis limits, the country, default year and missing-parameter checks come before anything is sent to the simulation service. The modules they test do not exist yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
HouseholdCalculationInput takes a stored household and an optional stored policy, with the simulation service's axis limits, add_missing_variables and optional SPM settings. The validators refuse a country without household calculations and a household without a default year, and the policy validators refuse a policy that sets parameters the running catalog version lacks, a check later calculation routes can share. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A job's status, result document and error are read into a calculation: a succeeded job's household in its stored key order, with its warnings and SPM choice and receipt; a refused job's error; a job that failed unexpectedly by its error message. The integration tests read the jobs as the runtime role, through the service. The modules do not exist yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET's read path: a read connector loads one household job by ID, a database session module opens the read sessions, a validator reads the job's result document as its status says, and a transformation builds the calculation from the job. A succeeded job must hold one policy result, which keeps the key order the json column stored; a refused job gives the household function's error, and one that failed without a failure document its error message. Database failures become a typed storage error, so the routes need not import SQLAlchemy. The cross-database integration check runs the read as the runtime role. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (failing) The service checks the country's household_enabled, that the household and policy exist in that country, the household's default year and the policy's missing parameters, in that order, and calls the simulation service only when every check passes. The submission method does not exist yet. The last test, of a database failure while reading, checks the read path committed before and passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
submit_calculation checks the country, the household and policy, the household's default year and the policy's missing parameters, then sends the calculation to the simulation service through the HouseholdCalculationSubmitter protocol, and returns the job the service created with the year it calculates. require_default_year now returns the year it checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ling) The client posts a calculation's IDs and options to the Cloud Run simulation service's POST /household-calculations, reads the 202's job ID and status, passes the service's 422 reasons through, and treats every other answer, no answer, an unreadable answer, a gateway token it cannot fetch and missing configuration as the service being unavailable. The module does not exist yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ocol SimulationHouseholdCalculationClient implements the service's HouseholdCalculationSubmitter. It posts to the Cloud Run simulation service's POST /household-calculations through the HTTP client SimulationEntrypointClient builds, so it shares its gateway credentials, correlation headers, transport and instrumentation. A 202's job ID and status are read with hand-written models that ignore fields they don't name; a 422's reasons reach the caller; every other answer is the service being unavailable. post_household_calculation is the only code that sends the request, so wiring the generated simulation client changes that one function and adds the dependency. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ailing) POST answers 202 with the new job, needs no account, and answers each refusal: 422 for a malformed request, a country without household calculations, a household without a default year and the simulation service's 422 reasons; 422 missing_parameters naming the parameters; 404 for a household or policy not stored in that country; 503 when the simulation service or v2 storage is unavailable. GET reads the job and answers 404, 500 for an unreadable result and 503. The OpenAPI test lists the two new paths. The routes do not exist yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
POST takes a stored household, an optional stored policy, axes, add_missing_variables and SPM settings, needs no account, and answers 202 with the new job's ID and status, the household and policy, and the year calculated. A policy setting parameters the running catalog version lacks gets 422 with code missing_parameters and their names, in a new error model in errors_support that later calculation routes can share. GET reads the job from household_jobs and answers its status, result and error. The service is built by a default factory that imports the simulation client only on first use, and the new modules join ruff's list of modules loaded only inside functions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…failing) /v2/household-calculations belongs to the household route group. Its request log records what it uses whatever the household flags select: a submission reads Supabase and computes on the Cloud Run simulation service's v2 household functions, a read reads Supabase only. The contract registry and the generated contract documents gain the two routes. None of this exists yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…tracts /v2/household-calculations joins the household route group. Its request log records the sources it uses, not the household group's database, entrypoint and compute flags: both routes read Supabase, and a submission computes on the Cloud Run simulation service's v2 household functions. The contract registry gains the two routes, and the generated contract documents are regenerated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The simulation service's household contract names exactly one policy, so a succeeded job's HouseholdExecutionResult holds that policy's household, warnings and SPM receipt in its output, beside the SPM selection applied, instead of a list of policy results. The failure document keeps its shape. The reader still expects the list, so these tests fail with an unreadable result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The stored document models now read the household, warnings and SPM receipt from the output of a HouseholdExecutionResult that names one policy. The two document models convert themselves into the calculation's output and failure, so they are the only code that names the simulation contract's fields, and a change to those names stays in one place. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Catalog publication records, for each US catalog version, whether the simulation service's public GET /versions lists a certified SPM capability for its PolicyEngine.py version, with the settings schema and defaults, in a new nullable tax_benefit_model_versions.spm_availability column added by a revision on the saved-item keys revision. /v2/model-catalog serves it as spm. Publication needs SIMULATION_ENTRYPOINT_URL, which the seeding workflow passes, and the catalog writer role records the column. None of this exists yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
tax_benefit_model_versions gains the nullable JSON column spm_availability, in revision 0c136a278f29, autogenerated on the saved-item keys revision 81b728a088e7, which is now V2_ALEMBIC_HEAD_REVISION. After publishing the catalog, publication records for each US version of the installed PolicyEngine.py whether the simulation service's public GET /versions lists a certified SPM capability for it, with the settings schema and defaults; a version it does not serve yet, or an unreadable answer, stays unrecorded for the next run. /v2/model-catalog serves it as spm. Publication needs SIMULATION_ENTRYPOINT_URL, which the seeding workflow now passes from the environment's secret. The documents that list what changes on a version after publication name the new column, including its effect on each process's kept responses. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The live checks store households and reforms through /v2/households and /v2/policies, submit them to /v2/household-calculations and read each job until it finishes: a submit and read cycle, six calculations submitted at once within their latency limits, a household across 401 axis points, and a parity set of three US and three UK households compared value by value with the in-process /calculate and /calculate-full. A unit test checks the parity households that add variables calculate one year on both sides. The workflow test expects the household checks to run after the other live tests with fewer workers, and the job's limit to be 30 minutes, which the script and workflow don't do yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
run_live_staging_tests.sh runs the household calculation and parity checks in a second pytest run, on 4 workers, once the other live tests finish, so the six submissions sent at once never share the candidate's six request slots with them. The live job's limit rises from 20 to 30 minutes; it has taken about 10 minutes before this change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Stage 11 household deployment notes describe both routes: the checks before submission and their answers, how the simulation service's answers are mapped, how GET reads household_jobs, where the simulation call is made, and the live staging checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…docs The simulation contract's household functions record a job that raised or was cancelled with a null result and an error message starting household_function_error or household_function_cancelled. The error model's documentation names them, and the tests use that format. Nothing else changes: the single-policy result and the failure document already match the contract. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…4261 Master gained the user types revisions 617f531f1506 and 970be5d29283 on the saved-item keys revision, the parent of the SPM availability revision 0c136a278f29. Its down_revision moves to 970be5d29283, which V2_ALEMBIC_HEAD_REVISION's 0c136a278f29 now follows; generating it again on 970be5d29283 gives the same two operations. The revision chain test and the Alembic skill list both master's revisions and this one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The route runs with the real countries, households and policies services over the v2 tables in SQLite, so the policy check runs the real catalog query. A submission, a missing-parameter refusal and an unknown household pass. When the catalog query fails, the policy service raises MetadataCatalogUnavailableError, which the route answers 500 instead of 503, as /v2/policies answers it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The policy service reports a catalog it cannot query as MetadataCatalogUnavailableError. The household calculation service now turns it, like a SQLAlchemy error, into its storage error, which the route answers 503, as /v2/policies does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…02 (failing) Through the route and the real simulation client, the submission carries the request ID and an observability ID: the caller's, or a new one. Sim's 400 and 503 answers name their code, and a 503 after Modal refused the call names the household job it failed. A 202 whose body cannot be read means sim has already created the job, so it is its own error, which the route answers 502 rather than the 503 that invites a retry. The submission sends no observability ID yet, and the error does not exist. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…r an unreadable 202 The submission binds the request's observability ID (the caller's, or a new one) before it calls the simulation service, so the shared request hook sends it with the request ID, and sim passes it to the household function. A 400 or 503 from sim gives its code and reason in the 503's message, and a 503 after Modal refused the call names the job sim failed. A 202 whose body cannot be read raises SimulationServiceAnswerUnreadableError, answered 502: the job already exists, so the caller is not invited to submit again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A submission should be sent again only after a 503 or a failed connection, never after a 502, which now means the simulation service created the job; a read may be sent again after a 502, 503 or 504 or a failed connection. The live fixture sends a submission again after any of 502, 503 and 504, and never after a failed connection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…onnection The live fixture now sends a submission again only after a 503 or a failed connection, never after a 502, which means the simulation service created the job, and sends a read again after a 502, 503 or 504 or a failed connection. The live script and modules say the checks pass only once the simulation service's household calculation route is on staging, so the change that adds them merges only after that deployment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Publication's evidence should list the versions it recorded SPM availability for and those it left unknown, with the reason when the simulation service's versions couldn't be read, which the command also prints to stderr. /v2/model-catalog should serve a version without a recorded availability as available null, unknown, apart from a recorded absence, available false. Publication now reports nothing, and the catalog serves both as false. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nown record_published_spm_availability returns what it recorded and which versions it didn't, with the reason when the simulation service's versions couldn't be read. Initialization adds that to the publication evidence, which the command prints, and the command also prints the reason to stderr. /v2/model-catalog serves a version without a recorded availability as available null, unknown, apart from a recorded absence, available false. The Stage 9 runbook's publication step names SIMULATION_ENTRYPOINT_URL, which publication now needs, and says how a failed versions read is reported. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A succeeded job's document whose schema_version is missing or isn't 1 should be unreadable, and a failure document of another version should be read as none, so the job's error message says why it failed. The document models ignore schema_version, so both are read as version 1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2s and 504s with 502 - Publication logs that SPM availability was not recorded only when some version is still unrecorded, after reading which are. - A 502 or 504 from sim, which only a proxy in front of it answers, now raises SimulationServiceAnswerUnreadableError (502): the job may exist. - The OpenAPI 502 description and the Stage 11 notes list the lost-answer and proxy cases, the Stage 11 notes no longer list "no answer" as 503, and the header text says it carries the attempt's ID, which sim never received after a connection never made or a token failure. - The warning test keeps the module's logger enabled, since Alembic's logging setup, which another test may run in the same process, disables loggers that existed before it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #4274 +/- ##
==========================================
+ Coverage 92.51% 92.66% +0.15%
==========================================
Files 318 329 +11
Lines 18137 18783 +646
Branches 3002 3114 +112
==========================================
+ Hits 16779 17405 +626
- Misses 814 824 +10
- Partials 544 554 +10
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…on again (failing) The Public API won't choose household job IDs, and no route finds a job without its ID, so a 502 can't ask the caller to check whether the job exists. The tests expect each 502 to ask for the calculation to be submitted again and to say this creates a second job if the first request went through, keeping each case's detail: the transport error, the proxy's status, sim's 500 code and reason, or the unreadable 202. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No route finds a household job without its ID, so the 502 can no longer ask the caller to check whether the job exists. After an unreadable 202, sim's 500, an answer lost after sending, or a proxy's 502 or 504, the message now reads "The simulation service may have received the request, but its answer was lost (<what happened>). Submit the household calculation again; if the first request went through, this creates a second job." The parentheses keep each case's detail: the transport error, the proxy's status, sim's 500 code and reason, or the unreadable 202. The OpenAPI 502 description, the error types' docstrings and the Stage 11 notes say the same. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… 503s Both submit docstrings now list a proxy's 502 or 504 with the unreadable 202 and the lost answer, and the protocol's docstring no longer leaves those to "any other refusal or failure". The 500 error's docstring and the route's comment say directly that a 502 is used because the job may already exist, so submitting again may create a second one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…edential (failing) Master's deployed-API tests now send the CI server credential through the api_client fixture, since the Public API refuses requests without it once PUBLIC_API_SERVER_CREDENTIAL_REQUIRED=1. The parallel household check opens a client per calculation, so the tests expect a client of the deployed Public API that sends CI_SERVER_ACCESS_TOKEN, and that fails without it rather than skipping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parallel household check opens a client per calculation, outside the api_client fixture that now sends the CI server credential. A new deployed_api_client in the live fixture builds the same client: the credential from CI_SERVER_ACCESS_TOKEN in Authorization, failing rather than skipping without it, the same timeout and redirects. The parallel check uses it, so it keeps passing once the Public API requires a server credential. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…re builds it (failing) The review found that deployed_api_client copied the api_client fixture's settings. The tests now expect the builder in tests/integration/deployed_api_credentials.py, which the fixture will use too, so both clients are built the same way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s in one place deployed_api_client moves to tests/integration/deployed_api_credentials.py, and the api_client fixture builds its client with it, so a check that needs clients of its own sends exactly what the fixture sends. The live fixture's docstring no longer says it needs only httpx, since the live job installs the locked dev environment, and the testing skill names deployed_api_client for checks that need their own clients. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…irect rule once Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ext stays out (failing) Sim may create the household job before answering a status the Public API doesn't otherwise handle (200, a redirect, 408, 409, 501 and the like), so the tests expect those to answer 502: "The simulation service may have created the household job, but it failed (<status> <code>).", as an unreadable 202 and sim's 500 do. Only answers sim gives before its route creates a job (401, 403, 404, 405, 413, 429 and 503), its 400, a connection never made and a gateway token that can't be fetched stay 503. Sim's 500 and 503 text may hold stored data, so only the status and a code that is a fixed identifier reach the caller; the 400 and 422 refusals keep their reasons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…the caller Sim may create the household job before answering a status the Public API doesn't otherwise handle, so any status other than 202, 400, 422, 500, a proxy's 502 or 504, and the ones sim answers before its route runs (401, 403, 404, 405, 413, 429 and 503) now answers 502: "The simulation service may have created the household job, but it failed (<status> <code>). Submit the household calculation again; if the first request went through, this creates a second job." An unreadable 202 and sim's 500 use the same first sentence; lost answers and a proxy's 502 or 504 keep "its answer was lost". Sim's text may hold stored data and the route needs no account, so after its 500 or 503, or an unexpected status, the message gives only the status and a code that is a fixed identifier (lower-case letters, digits and underscores, starting with a letter, at most 64 characters); the failed job's ID is no longer named either. The 400 and 422 refusals keep their reasons. The answer reading moves out of submit into one function. The OpenAPI 502 description, the error docstrings and the Stage 11 notes describe the new classes of answer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ead apart from reasons (failing) Sim's own 503 always names its code; without one, Cloud Run's front end answered in its place, possibly after the job was created, so the tests expect 502 "its answer was lost (a proxy answered 503)". A code that isn't text no longer makes a 400's reason or a 422's field list unreadable, a 400 without a textual reason gives its status and code, the submit route's OpenAPI 503 says only a 400 keeps sim's reason, and the tests cover a 403 with FastAPI's body, statuses outside 200 to 599, and the exact unreadable-422 message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om reasons Sim's own 503 always names its code. A 503 without one came from Cloud Run's front end, possibly after sim created the job, so it now answers 502 "its answer was lost (a proxy answered 503)", like a proxy's 502 or 504. The code is read from the answer's JSON on its own, so a code that isn't text no longer makes a 400's reason or a 422's field list unreadable; a 400 without a textual reason gives its status and code. The submit route's OpenAPI 503 no longer promises sim's reason: only a 400 keeps it. The docs and names now say that no job of the submission runs after a 503-class answer, rather than that none was created, since sim fails the job it created when Modal refuses the call. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… as a 500 (failing) The standard-library parser that reads sim's code raises RecursionError on a deeply nested body, which the route answers 500 without the "submit again" message. The tests expect such a body, a top-level JSON value that isn't an object and bytes that aren't UTF-8 to read as no body, and the OpenAPI 503 to list sim's not_configured 503. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…3 into a 500 The code was read with the standard-library parser, which raises RecursionError on a deeply nested body; the route answered that 500, without the "submit again" message. Each answer other than 202 is now parsed once, by pydantic's parser, which reports its depth limit and bytes that aren't UTF-8 as a ValidationError, into a record of its status, its fixed-identifier code and its refusal, from which every message is built. The OpenAPI 503, the error docstring and the Stage 11 notes list sim's not_configured 503, and the constant of statuses after which no job runs says it holds only sim's own coded 503. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
anth-volk
marked this pull request as ready for review
November 11, 2026 18:04
This was referenced Nov 11, 2026
This branch was previously 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 #4273
Summary
Adds
POST /v2/household-calculationsandGET /v2/household-calculations/{calculation_id}, which calculate a household stored in the Public API through the simulation service's household jobs. Replaces #4092, whose migration chain, reads through the simulation service and module layout no longer fitmaster.POSTneeds no account. In order, it:household_enabled(422);default_year(422);code: "missing_parameters"and the list inmissing_parameters, calling nothing (the check isrequire_policy_parameters_present, reusable by the run routes);add_missing_variables, optionalaxesand optionalspmsettings to the simulation service.The simulation service's answers map as follows:
POSTanswers{job_id, status}, for any of its four statusescalculation_id,status,country_id,household_id,policy_idandyear): ")." No job of the submission will run.). Submit the household calculation again; if the first request went through, this creates a second job."No route finds a household job without its ID, so a 502 asks the caller to submit again rather than check first. The simulation service's own text may hold stored data, and the route needs no account, so only a 400 or 422 passes its reasons on; every other message gives only its status and a
codethat is a fixed identifier (lower-case letters, digits and underscores, starting with a letter, at most 64 characters).Every answer given after the simulation service was called carries
X-PolicyEngine-Observability-Idwith the ID of that attempt. Refusals before it carry none.GETreadshousehold_jobsthrough the v2 layers, as the runtime role, and never calls the simulation service. It answers:warnings,spm_configandspm_provenance, from the simulation service's single-policy result document (contract version 1);code,message,input_errorsandspm_errorfrom the failure document, or the job'serror_messagewhen it has none;SPM availability in the catalog. A new nullable JSON column,
tax_benefit_model_versions.spm_availability(autogenerated revision0c136a278f29on970be5d29283), is recorded at catalog publication from the simulation service'sGET /versions./v2/model-catalogserves it asspm:available: trueorfalseonce recorded,nullwhile unrecorded. When/versionscan't be read, publication still succeeds, and its evidence lists the versions still unrecorded.Also:
/calculateand/calculate-full, under a 30-minute job limit;SIMULATION_ENTRYPOINT_URLadded to the publication step.The call to the simulation service sits behind the
HouseholdCalculationSubmitterprotocol. The adapter,policyengine_api/libs/simulation_household_calculations.py, reusesSimulationEntrypointClient's HTTP client, so the gateway credentials and the request and observability ID headers come from there. Wiring the released generated client is one change, once PolicyEngine/policyengine-sim-api#1046 merges and the simulation service publishes a client release with the household routes: addpolicyengine-api-simulation-client>=<that release>and relock, then replacepost_household_calculation's body with the generatedsubmit_household_calculation.sync_detailed(...), as its docstring shows.The request fields and the answers the adapter reads were checked against PolicyEngine/policyengine-sim-api#1046 at
5fe2a584: the request (country,household_id,policy_id,add_missing_variables, andaxesandspmonly when given), the 202{job_id, status}, the 422 field list, the 400 and 503{code, detail}(the adapter keeps the 400's reason, and of a 503 or 500 only itscode, ignoring a 503'shousehold_job_id), and the JSON 500internal_error. When the simulation service cannot tell whether a job's call started, it now answers 202pendingrather than 503, which the adapter already reads as an accepted job.Merge order
Merge only after the simulation service's
/household-calculationsroute, PolicyEngine/policyengine-sim-api#1046, is deployed to staging. Until then, the live staging checks fail, and with them every Public API staging promotion and release.Tests
API_BASE_URL).alembic -c alembic-v2.ini check: no new operations; one head,0c136a278f29.lint-imports, the rules registry, the quality guards, the migration contract export, ruff, ruff format, shellcheck,uv lock --checkand mypy (including the changeddata/v2files) pass.deployed_api_clientintests/integration/deployed_api_credentials.py, which theapi_clientfixture now builds its client with as well, so both send the same credential and settings. Unit tests were seen failing first; two review rounds of this change found no bugs.Environment variables and secrets
SIMULATION_ENTRYPOINT_URLstagingandproductionenv:, thendeploy_cloud_run_candidate.sh, then the Cloud Run revision. Publication: the publish step'senv:inseed-v2-database.yml(new), whose job declaresenvironment:and is called withsecrets: inherit.GATEWAY_AUTH_ISSUER,GATEWAY_AUTH_AUDIENCE,GATEWAY_AUTH_CLIENT_ID,GATEWAY_AUTH_CLIENT_SECRET_RESOURCEenv:, then the deploy script withGATEWAY_AUTH_REQUIRED=1. Unchanged.V2_RUNTIME_DATABASE_URL_SECRET_RESOURCE,V2_DATA_WRITE_DATABASE_URLAPI_BASE_URL,STAGING_API_TEST_PROBE_IDSTAGING_HOUSEHOLD_*and the poll interval are optional and use their defaults.CI_SERVER_ACCESS_TOKENrequest_ci_server_token.sh(from #4265) from thestagingenvironment'sCI_SERVER_AUTH0_DOMAIN,CI_SERVER_AUTH0_CLIENT_IDandCI_SERVER_AUTH0_AUDIENCEvariables andCI_SERVER_AUTH0_CLIENT_SECRETsecretenv:. The household checks send it through theapi_clientfixture, and the parallel check throughdeployed_api_client, one client per thread.Not verified:
SIMULATION_ENTRYPOINT_URLnames its own simulation service;simulation:submitpermission;GET /versionsdescribes the v2 household functions' SPM support.🤖 Generated with Claude Code