Declarative country spec schema with Belgium as its first consumer#269
Merged
Conversation
…umer populace.build.country_spec loads a spec-only country package as one validated, content-hashed object: the existing source/support-spine manifests plus three new typed resources — geography_spine.json (clone-and-assign, vintage-aware geography codes; mismatch is a compile error per the populace#205 lesson), gates.json (gate selection from the gates.py vocabulary with release_blocking/diagnostic criticality), and release_contract.json (repos, artifact set, data_build_id naming with ordinal tokens refused, licence boundary with restricted => private enforced). target_references.json rows parse as LedgerTargetReference and any observed-value key is refused — values live in Ledger. country_stage_plan() compiles the manifests into a StagePlan with the US plan's no-fallback posture, and every resource byte is pinned by a sha256 in the golden-file test. The be/ package is the first full consumer: BE-SILC source stage (real EU-SILC register names, income-reference-year lag declared as data), commune NIS spine (2025 vintage, NUTS1-constrained assignment, collision avoidance), six initial target-reference families bound to the planned ledger-be packages, a gate selection that deliberately omits the incumbent-comparison gates (external oracles replace self-parity), and the private-repo release contract. Zero Python in the country folder; the US and UK packages load through the same loader unchanged. Two general operation kinds join the source-manifest vocabulary: map_columns and declare_income_reference_offset. Fixes #261. Part of #259. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
10 tasks
…, recursive value guard - Replace belgium_pit_final_income_tax_payable (does not exist in rulespec-be) with belgium_pit_federal_and_local_tax_before_withholding, the actual assessed-total liability output (Article 134 federal tax plus Articles 465-468 local additions), matching the SPF Finances "assessed total" series the target anchors. - Tighten the ordinal-token guard: lookahead instead of \b so embedded tokens (populace_xx_v2_staging) are refused, while sha-v2x and nuts1 stay benign. Loader-level tests for both sides. - Recurse the observed-value guard: a value key nested under ledger_selector or metadata is refused like a top-level one. - Regenerate the Belgian golden (fingerprint acc6e4b7bcbe). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
Author
Adversarial re-review (re-run of the review that died at last night's session limit)Reviewed at Findings → fixes
Noted, no action needed
Clean probesGate allowlist is an exact match with 🤖 Generated with Claude Code |
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 #261. Part of #259 (populace-be epic); the concrete first step of #159/#160, built greenfield for Belgium on the conventions the repo already enforces (
country_package.json, spec-only country packages, manifest-defined stages, Ledger references).What
populace.build.country_spec— one loader for a spec-only country package, returning a validated, content-hashedCountrySpec:source_stages.json→SourceManifest,support_spine.json→SupportSpineManifest); the US and UK packages load through the same loader (tested).from_mappingvalidation style:geography_spine.json(GeographySpineManifest) — clone-and-assign spine as data: geography level, code system and vintage, pool multiplier, collision avoidance, assignment source citation.vintage_policyadmits only"error"— a commune-grain target bound to one code vintage joined against a spine of another must fail compilation, never silently partial-join (the Translate old-vintage CD targets to current district geography #205 lesson, schema-enforced).gates.json(GatesManifest) — gate selection from thegates.pyvocabulary withrelease_blocking/diagnosticcriticality per selection; unknown gate functions are refused, and a package whose every gate is diagnostic is refused (no release contract).release_contract.json(ReleaseContractManifest) — artifact repo/staging repo, dataset filename template, required release files, public/private boundary, licence.restricted licence ⇒ private repois enforced at parse, and ordinal version tokens (-v1,_v2) anywhere in names are refused (data_build_id + HF revisions are the versioning).target_references.jsonrows parse asLedgerTargetReference(the exact class the US fiscal references use), and any row carrying an observed-value key (value,values,observed…) is refused with "values live in Ledger" — targets are references, structurally.country_stage_plan(spec, implementations)compiles source stages + the spine stage into aStagePlanwith the US plan's no-fallback posture: every declared stage needs an implementation, unknown implementations are refused, and each stage carries its manifest citation as the donor record.CountrySpec.fingerprintcomposes them (trace.compute_composition_fingerprint), so a release manifest can name exactly the spec content that built it.be/country package — the first full consumer, pure data (zero.py, enforced by the existingtest_spec_only_country_packages.pywhich now covers it automatically):source_stages.json— the BE-SILC stage against real EU-SILC register names (DB030/RB030 ids, DB040 region, DB090 weights, PY010G → the Axiom article-23 worker-remuneration input), with the survey-year/income-reference-year lag declared as a first-class operation (declare_income_reference_offset: -1) so the build's period bookkeeping and the target profiles bind to the same basis (feeds ledger#71).geography_spine.json— commune NIS spine, 2025 vintage, 20× clone pool, NUTS1-constrained assignment (SILC carries region; the spine assigns the commune), collision avoidance; generalizes the UK OA rowwise operators (implementation lands with Build the Belgian calibration surface by recalibrating the US release recipe #263).target_references.json— six initial families by reference (Statbel demography, Statbel commune fiscal income @ NIS 2025 diagnostic-only, SPF PIT total against the Axiom settlement output, ONSS contributions, ONEM caseloads, NBB validation-tier anchor), source names bound to the planned ledger-be packages (ledger#69/Investigate ACA take-up and plan-choice inputs driving high PTC estimates #70 own the facts and the full profile).gates.json— release-blocking national+NUTS1 posture with commune rows diagnostic (the Replace all remaining policyengine-us-data artifacts with Populace #204 CD posture); the incumbent-comparison gates (parity/export_surface/target_surface) are deliberately not selected — Belgium has no incumbent; external oracles replace self-parity (Validate populace-be against EUROMOD-BE and Federal Planning Bureau scores #264).release_contract.json—policyengine/populace-be-private+ staging repo, country-neutralsource_coverage.jsonnaming (per Stand up the populace-be release channel #265),reform_validation.jsonin the required set, restricted-licence boundary.Two general operation kinds join the source-manifest vocabulary:
map_columnsanddeclare_income_reference_offset(general operators, not country escape hatches).Acceptance, as verified
packages/populace-build/src/populace/build/be/contains zero.py— and the standing spec-only tests now enforce that forbe/with no test changes.tests/golden/be_country_spec.json; editing any BE spec byte fails the test until the golden is regenerated and reviewed. Deterministic across loads (fingerprint-stability test).test_us_plan).mkdir+ five JSON files copied and edited; the loader, plan compiler, hashes, and enforcement tests need no changes (the US/UK-load tests are the proof).Full populace-build suite + frame + data pass locally; ruff clean.
🤖 Generated with Claude Code