Part of #259 (populace-be epic).
What
Implement the first non-PolicyEngine RulesEngine adapter: populace.frame.adapters.axiom, wrapping the Axiom rules engine runtime for the Belgian rule set. The protocol (packages/populace-frame/src/populace/frame/rules.py) is deliberately minimal:
variable_metadata(name) -> VariableMetadata — owning entity, dtype kind, period semantics
variables() -> Sequence[str] — input variables the engine accepts on a dataset (computed/formula-owned outputs excluded)
entity_schema() -> EntitySchema — the engine's entity structure
materialize(bundle, variables, period) -> Mapping[str, np.ndarray] — compute variables, row-aligned to each variable's entity table
export_contract() -> ExportContract — the column-parity contract exports are gated against
write_dataset(...) — write a Frame as an engine-native dataset
Reference implementation: packages/populace-frame/src/populace/frame/adapters/policyengine_us.py.
Provide-side counterpart: the Axiom runtime must expose a vectorized surface for this (tracked in TheAxiomFoundation/axiom-rules-engine — linked from the epic). Coordinate the two so the adapter stays thin.
Design decisions this issue must make
- Engine-native dataset format for BE. There is no policyengine-be package, so the adapter itself owns the export contract — propose entity-table H5 matching the US/UK layout so
populace.data loaders generalize.
- Entity mapping. Belgian PIT is largely individual with household-level elements and regional surcharges; benefits use household/family units.
entity_schema() must express the units the Axiom BE encodings define; document the mapping from SILC household/person structure.
- Formula-owned boundary. The formula-owned-export lesson from the US (frozen engine-computed columns mask reforms) applies from day one: the export contract must classify computed vs input variables so the gate works.
- Reform materialization. The protocol notes reform/branch simulation as a planned breaking extension (
materialize(..., reform=...) or sibling). The BE validation oracle needs counterfactual runs — either land the protocol extension here or sequence the oracle work behind it. State the choice explicitly.
Acceptance
- Behavioral contract tests parameterized over adapters pass for the Axiom adapter wherever semantics overlap with the policyengine-us adapter (metadata resolution, entity alignment, materialize row-alignment, export contract shape).
- Smoke test: materialize the pilot-slice PIT variables for a toy Frame and reproduce hand-computed values for 2–3 example households.
- Nothing outside the adapter imports the Axiom engine.
Part of #259 (populace-be epic).
What
Implement the first non-PolicyEngine
RulesEngineadapter:populace.frame.adapters.axiom, wrapping the Axiom rules engine runtime for the Belgian rule set. The protocol (packages/populace-frame/src/populace/frame/rules.py) is deliberately minimal:variable_metadata(name) -> VariableMetadata— owning entity, dtype kind, period semanticsvariables() -> Sequence[str]— input variables the engine accepts on a dataset (computed/formula-owned outputs excluded)entity_schema() -> EntitySchema— the engine's entity structurematerialize(bundle, variables, period) -> Mapping[str, np.ndarray]— compute variables, row-aligned to each variable's entity tableexport_contract() -> ExportContract— the column-parity contract exports are gated againstwrite_dataset(...)— write a Frame as an engine-native datasetReference implementation:
packages/populace-frame/src/populace/frame/adapters/policyengine_us.py.Provide-side counterpart: the Axiom runtime must expose a vectorized surface for this (tracked in TheAxiomFoundation/axiom-rules-engine — linked from the epic). Coordinate the two so the adapter stays thin.
Design decisions this issue must make
populace.dataloaders generalize.entity_schema()must express the units the Axiom BE encodings define; document the mapping from SILC household/person structure.materialize(..., reform=...)or sibling). The BE validation oracle needs counterfactual runs — either land the protocol extension here or sequence the oracle work behind it. State the choice explicitly.Acceptance