Repository navigation
Conversation
MaxGhenis
force-pushed
the
w4/receipt-composition
branch
from
October 12, 2026 03:01
712c36a to
9672ad3
Compare
composed_reform_identity(members) binds several reforms applied in one policyengine-uk Scenario under policyengine-uk.scenario_composition/v1. The digest covers each member's representation, digest and binding in application order: reordering distinct members changes it, current-law members and labels do not, and the binding is code_revision exactly when a member's is. reform_identity refuses the composition representation. Fixes #578 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- composed_reform_identity takes a required applied_before_data_load and binds it in the payload: Scenario.__add__ resets the phase to False, and structural reforms run between the two phases, so the same members early and late are different runs. - The documented semantics now match policyengine-uk 2.125.1: Simulation.__init__ runs a Scenario's modifier and then its parameter changes, in the stated phase; the receipt's model.version names the policyengine-uk that ran. - Each member is revalidated, so an identity edited past its rules with model_copy is refused instead of silently dropped or hashed. - Tests restate the exact preimage (nested compositions included), check that changing any member's digest, representation or binding changes the composition, and pin named current-law behaviour. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t members
- policyengine-uk.scenario_composition/v1 now means one simulation that
applies every member's parameter changes and then each member's
modifier in member order, in the stated phase, whatever the
policyengine-uk version. The payload states the order
("application": "parameter_changes_then_modifiers"). The dashboard's
composer runs exactly this; Scenario.__add__ does not (its merge
depends on grouping, and 2.125.1 runs the modifier first).
- Members must change disjoint parameters, in any form: with disjoint
changes the merged result cannot depend on grouping, which closes the
scalar versus period-map ambiguity the review reproduced.
- Empty containers, bytes, generators and sets are refused as members.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Compositions use the null-preserving payload digest of #571's round 5, as every reform digest now does (composition payloads hold no nulls, so existing composition digests are unchanged). - Tests: a tuple and a list of members give the same composition, and an invalid phase is refused even when no member changes anything. - Docs: a baseline shared by several members (parameter changes only) appears once, at the first sharing member's position, which cannot affect the run (from the dashboard's composer, workstream W5). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MaxGhenis
force-pushed
the
w4/receipt-composition
branch
from
October 12, 2026 11:07
69390c5 to
887084a
Compare
This branch has not been 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 #578
Draft, stacked on #571 (receipt schema v1); review
origin/w4/receipt-schema-v1...HEAD. I'll retarget it to main when #571 merges.Why
The UK Budget dashboard's combined simulation applies several measures in one Scenario. The engine takes one
simulation_modifier, so the combined Scenario's modifier composes the members' module-level modifiers.scenario_reform_identityrightly refuses that composed closure. That leaves a combined run with any structural member without a validreformidentity, andreformis required in schema v1.What this adds
composed_reform_identity(members: Sequence[ReformIdentity], *, name=None) -> ReformIdentitypolicyengine-uk.scenario_composition/v1;{"members": [{"representation", "reform_sha256", "binding"}, ...]}in application order;code_revisionif any member's is, elsecontent.Each member is still bound on its own with
reform_identityorscenario_reform_identity, so every modifier remains a module-level function bound by source and revision.What the representation means: one policyengine-uk
Scenariowhoseparameter_changesare the members' changes merged, and whosesimulation_modifierapplies the members' modifiers in the listed order, after the parameter changes. The composer must check that no two members set one parameter to different values; this function sees only identities and cannot. The docs state that as a condition of using the representation.reform_identityrefuses the composition representation, as it refuses the Scenario one, so a composition can only be built from bound identities.Invariants (each tested)
content_sha256of the stated payload (example test).current_lawmembers anywhere, or relabelling members, does not. Dropping or duplicating a member changes it.current_law. A single member keeps the composition representation, so its digest differs from the member's own.Compatibility
This adds one value to the
representationenum in the v1 schema. v1 is unreleased, so no published schema changes.Checks run locally
tests/test_execution_receipt.py.generate_receipt_schemas.pyregenerated the schema.axiom: n/a: provenance/infrastructure contract, no policy change.
🤖 Generated with Claude Code