Skip to content

WS-C deferred adjudications and the reconciliation layer #736

Open

Description

@juaristi22

Central registry of the adjudications deferred during the #622 build-out (PR #735) and the calibration-target deferrals accumulated since, to be reviewed as the spine (#145/WS-E) and calibration workstreams converge on the first certified cut. Each item links its signed rationale in the committed resources (uk/target_reference_membership.json, uk/ledger_compile_parity_*_signed_differences.json, uk/calibration_measure_exclusions.json). Items graduate to their own issues when they become actionable. Spine-lane counterpart: #796.

Deferred adjudications from the #622 build-out

The uk_target_fit disposition remainder (PR #793's adjudication queue)

The adjudicated exclusion pass (42 windowed entries, expiring 2026-11-26, correct-or-renew at apply time) landed in PR #793; the first certified cut blocks on what remains:

National calibration-target issues previously untracked here

Refs: #622, #735, #665, #145, #796, PR #793.

Activity

  1. juaristi22 commented on Aug 22, 2026

    @juaristi22
    CollaboratorAuthor

    Item 10 resolved: #623 narrowed to run-readiness (not closed) — the tooling is delivered by draft PR #743 (doctrine, live parity trio, US-format diagnostics with the chronicle pin, #578 rule-1 scorer, staging-candidate posture, runbook); the licensed armed run is held until WS-E E8 (#684) + E10 (#686) complete or María names a different base. #623 stays open for the run + acceptance evidence; the aggregate-scaler ruling (item context) remains open on #623 itself.

  2. juaristi22 commented on Aug 24, 2026

    @juaristi22
    CollaboratorAuthor

    Registry coverage: 29 contract targets have no reference row — verified findings + adjudication queue

    Folding the #623-lane registry findings here per María's ruling (2026-08-25): the coverage work does not ride PR #743, which ships as calibration-seam-only. Everything below was verified mechanically against the pinned feed (chronicle-uk-artifact-1cab809, facts 226358e7…, 107,550 rows), the real compiler (compile_ledger_target_references), the real generator (tools/generate_uk_target_references.py), and policyengine-uk's variable registry.

    The gap, exactly

    uk_national_targets.json declares 189 contract targets; target_references.json carries 388 references covering only 160 of them. The other 29 compile into no calibration, no score, and no coverage receipt. verify_register_coverage.py reports 388/388 because it counts references, not contract targets — a true statement about the wrong denominator.

    Nuance worth keeping: the gap was never invisible. The membership report records all 29 as non-active candidates (417 = 388 active + 27 no_fact_at_or_before_period + 1 multi_fact + 1 signed_excluded). It was recorded but unenforced — nothing turns an unexplained coverage hole into a failure.

    Root causes (verified by re-running the generator against the current feed: it reproduces 388/29 exactly)

    1. 27 of 29: the generator's geography-pin heuristic. _geography_id_for_target infers a pin from target-id substrings and merges it over the contract selector, so the selector matches zero facts:
      • obr.council_tax_{england,scotland,wales} → pinned E92/S92/W92 while OBR files everything at K02000001 (the split is by concept, not geography); obr.domestic_rates → pinned N92000002 by substring rule, facts at K02000001.
      • slc.* → pinned GB (K03000001) vs the facts' England (E92000001) for borrowers/support and S92/W92/N92 for the devolved repayments.
      • dwp.pip.* → pinned GB vs the facts' England+Wales (K04000001).
      • scotgov.* → falls to UK ("scottish" ≠ "scotland" as a substring) vs S92000003.
    2. Multi-year SLC/SCP concepts additionally need period pins: chronicle's layouts embed the year, so eligible facts across years carry distinct semantic keys and the resolver's latest-match refuses. The selector vocabulary already supports period_value; with pins, everything compiles (verified 42/42 in a synthetic run).
    3. The 9 Scottish council-tax-stock selectors also lack source_concept (feed carries scotgov.chargeable_dwellings_band_a…_h/_total, Scotland, month 2025-09) — both fixes needed.

    What is wireable — and what is not

    Wireable now: 29 references closing 27 targets (verified end-to-end, values resolved):

    • 4 OBR (council tax E £41.9bn / S £3.05bn / W £2.40bn 2025 projections; domestic rates £494m),
    • 4 SLC borrowers (plan-2 liable 9.71m / above-threshold 4.46m; plan-5 230k / 35k — 2025 projections),
    • 6 SLC support (maintenance 1.16m recipients / £8.59bn; ADG 18.6k / £55.4m; PLA 99.6k / £181.4m — 2024 actuals),
    • 3 devolved repayments (S £203.3m / W £229.1m / NI £181.7m),
    • 2 PIP daily living (standard 1,283,000 / enhanced 1,608,000 — Jan 2025, England+Wales),
    • 1 Scottish child payment (£471.0m — 2025 projection, not the £455.8m 2024 actual),
    • 9 Scottish council-tax stock bands (band A 498,707 … total 2,623,149).

    All 29 bindings' variables verified present in policyengine-uk (866 variables — pip_dl_category, council_tax_less_benefit, student_loan_plan, council_tax_band, etc.).

    NOT wireable — the 13 property-income amounts. They sit under the generator's standing signed exclusion: the incumbent's amount target carries the ×1.9 property-income undercount adjustment (policyengine-uk-data #311/#230; HMRC PRIS £46.68bn vs SPI ~£24.5bn), so binding raw SPI facts would knowingly calibrate to ~10/19 of the incumbent's concept. They stay out pending a chronicle PRIS package or a first-class value-scaling operation (chronicle#196 lane).

    Blocked — ons.population.scotland_households_3plus_children: selector reaches 30,925 age facts and cannot answer a household question; the right concept (ons.families_households_table7) has no Scotland cut. Filed as chronicle#196; worth neutralising so it fails loudly.

    Adjudications needed (María)

    1. Property-income signed exclusion — keep signed out (default) or overrule? If kept: route is chronicle PRIS package / value-scaling op.
    2. Devolved repayments contract split — the binding note "the resolved geography binds the model country filter" describes the incumbent's pipeline; microcosm's materializer has no geography→filter translation. Proposal: split slc.repayments.devolved_total into three contract targets with explicit country binding filters (the OBR council-tax pattern). Contract count 189→191.
    3. PIP geography — facts are England+Wales; the binding counts pip_dl_category model-wide, so Scotland's ADP claimants inflate the estimate against an E+W target. Add a country filter to the two bindings, or record a signed asymmetry?
    4. Forecast-period convention — OBR/borrowers/SCP resolve 2025 projections under allow_source_projection (the naive compile silently yields the prior-year observation instead). Confirm projections are the intended targets, matching the existing 24 OBR references.
    5. Generator changes — honor contract-declared geography before the substring heuristic (heuristic stays as fallback so the existing 388 regenerate byte-identically), plus period_value selector pins for borrowers ("2025"), slc.support ("2024"), SCP ("2025").

    Mechanics when this lands (one commit, after the digest-neutral seam work)

    Regenerate — never hand-edit: target_references.json + membership (generator), and the two parity signed-differences resources (tools/build_uk_ledger_compile_parity_signed_differences.py). The parity fixtures describe the June/incumbent sides and do not change; the 2023 gate already tolerates 2025-only references (211/388 compile at 2023 today). Pinned counts that move: ACTIVE_REFERENCE_COUNT 388→417, per-family membership counts, contract target count 189→191. All legacy_json — no spec/gate-battery digest movement.

    Plus the regression guard: a test on the committed JSONs (CI has no feed) asserting every contract target has ≥1 reference or a membership status in {signed_excluded, blocked-with-tracking-issue} — turning the already-recorded statuses into an enforced contract.

    Re-score both artifacts on the new register before quoting any head-to-head; the v9 figures (297/71/10, losses 0.085 vs 0.235) don't carry across a denominator change. Closes ~20 of the 65 incumbent-only national rows; the 13 property amounts join the fact-gap bucket.

    🤖 Posted from the #623 working session (Claude Code).

  3. juaristi22 commented on Aug 24, 2026

    @juaristi22
    CollaboratorAuthor

    Correction: I measured against a stale base — E2 is already fixed on main

    My comment above was computed against the #743 branch, which sits 245 commits behind main. Measured against main the numbers are different, and one of my two work items is already done.

    Against main today: 397 references covering 169 of 189 contract targets — 20 unreferenced, not 29.

    @MaxGhenis's d9d5a45e ("Pin the scotgov council-tax stock targets to Scotland", 2026-08-23) already wired the nine scotgov.council_tax_stock.* targets, and diagnosed the same root cause I described — the substring geography rule sees no "scotland" in "scotgov", pins to the UK, and the pin is merged into the selector and matched against fact.geography.id, which Chronicle stamps S92000003. Membership moved 388 → 397 active, no_fact_at_or_before_period 27 → 18. So E2 is closed; disregard that section.

    Two things survive the correction, and one is worth deciding deliberately.

    The remaining 20 break down as: 13 property-income amounts (standing signed exclusion — unchanged), 1 blocked (ons.population.scotland_households_3plus_children, chronicle#196), and 6 groups still unwired: OBR council tax ×3 + domestic rates, SLC borrowers ×4, SLC support ×6, devolved repayments, PIP ×2, Scottish child payment. All still verified wireable against the pinned feed, with the same adjudications outstanding (devolved contract split, PIP England+Wales geography, forecast-period convention).

    The fix strategy question is now live rather than hypothetical. d9d5a45e fixed the geography rule with a targeted prefix special-case:

    if target_id.startswith(SCOTGOV_COUNCIL_TAX_STOCK_PREFIX):
        return UK_GEOGRAPHY_IDS["scotland"]

    That is correct and well-documented for those nine. But each remaining group needs its own special-case under that approach — OBR files at K02000001 while the rule infers E92/S92/W92 from the target name; SLC borrowers are England while the rule infers GB; PIP is England+Wales; the devolved rows are per-country. That is five more branches in a heuristic whose failure mode is silent: a wrong pin yields zero matches, and a zero-match target is deferred rather than raised.

    The alternative I verified: let a geography_level/geography_id declared on the contract's own ledger_selector win over the inferred pin, keeping the heuristic as the fallback. The existing references regenerate byte-identically (the heuristic still answers wherever the contract is silent), and each future target states its geography where a reader would look for it. Worth a ruling before anyone writes the sixth special-case.

    Everything else in my comment above stands — the compile verification, the property-income exclusion, the regeneration inventory, and the regression guard, which is the item that would have caught this class in the first place.

    Apologies for the stale baseline; I should have measured against main rather than the working branch.

  4. juaristi22 commented on Sep 3, 2026

    @juaristi22
    CollaboratorAuthor

    Erratum and two follow-ups on the #762 items above (2026-09-03).

    A16 erratum — the two ONS land rows are withdrawn. ons.land.corporate_land_value (listed at 8.7×) and ons.land.land_value (2.5×) were not unreachable. The misses were an artefact of the candidate driver's per-block engine resolution: policyengine-uk's corporate_land_value allocates a fixed national aggregate by each household's share of total weighted corporate wealth, and with the engine run per clone block every block reproduced the whole aggregate (×15.000 at K=15, receipt R15 in experiments/762-uk-rowwise-candidate-receipts.md). Single-block resolution — the release posture — puts them within 3 % and 9 % of the ONS balance-sheet rows, and the next release-candidate run binds them. The A16 register holds five entries (savings interest, housing benefit, the two plan-2 borrower stocks, JSA claimants; 49 exclusions in total), still expiring 2026-10-03. No other national row is block-sensitive (361 of 364 identical), and the manifest now names the population-normalised measures whenever blocks are used. The five remaining rows are filed as spine issues (linked from the #686 PR body).

    A17 (ruling 2026-09-03) — census tenure cells uprate with the household rows. The 1,436 tenure-by-authority cells (Census 2021 for England, Wales and Northern Ireland; Scotland's Census 2022) partition the same household universe as the ladder rows and were held at their census vintage; after A15 they summed to 95.7 % of the uprated household rows and the solver let owned-outright absorb the gap (+8.2 % median). Held tenure cells now take the same national household factor (1.033577 = ONS ons.households_total 29,003,000 for 2025 over the ladder's 28,060,832), receipted beside the ladder rows; a tenure cell compiled from a fact at the calibration period is never touched.

    Ask to the fact side, so both holds retire rather than persist: please add to the Ledger, at 2025 or the latest available vintage, whichever is later — (a) household counts by parliamentary constituency and by local authority (ONS household estimates / projections for England and Wales; NRS and NISRA equivalents), so the ladder rows bind to a published 2025 level instead of a census count × one national factor; (b) tenure by local authority at the latest published vintage (English Housing Survey / Census-based estimates where any post-2021 series exists), so the A17 uprating retires per cell; (c) the Welsh council-tax dwelling stock by band (StatsWales), still deferred under A13. The compile keys the uprating on the hold metadata, so the day a later fact lands the corresponding cells bind as published with no code change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions