Skip to content

UK rowwise local candidate: rulings, registers, receipts, and the dense release line (#762 PR B) - #870

Open
juaristi22 wants to merge 29 commits into
mainfrom
uk-rowwise-candidate-762-b
Open

UK rowwise local candidate: rulings, registers, receipts, and the dense release line (#762 PR B)#870
juaristi22 wants to merge 29 commits into
mainfrom
uk-rowwise-candidate-762-b

Conversation

@juaristi22

@juaristi22 juaristi22 commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

This completes PR B of #762, following the merged joint-solve machinery in #852: the measured UK local calibration doctrine, reviewed registers, census-vintage uprating, licensed-run receipts, and the dense dataset's assembly and validation path.

The retained R16/R17 candidate is release-blocked under the revised contract. Its historical shippable verdict and assembled-directory validation used the earlier policy. No calibration was rerun, historical result changed, or old gate report re-signed for these review fixes.

Build approach and reviewed scope

Release checks strengthened after review

The four existing quality gates now block release with unchanged numerical limits: 25% target error, the existing hard family-fit rule, max/median weight ratio 100, and ESS fraction 0.01. The 10% family-fit diagnostic remains diagnostic.

Assembly and standalone validation require a complete incumbent-surface evaluation, authenticated against the candidate dataset, run manifest, diagnostics, Ledger and incumbent extraction. The checks rederive accuracy from finite row evidence, including measurable signed-deferred rows, and apply the existing absolute limits. Missing measurements or failed limits prevent release. The evaluation and its supporting manifests enter the artifact/checksum inventory.

The evaluator refuses engine-block counts other than one. Assembly and subsequent validation require measured clean source code and valid exclusion approval windows at the time of validation, closing the later-upload expiry gap. Signed gate reports remain bound to the candidate attempt, and score receipts remain joined to their inputs by hash.

Historical comparison and remaining data gaps

The run receipts preserve both comparisons. R16/R17 achieved 98.8% versus 60.4% within 10% on the selected comparison rows. R18's broader incumbent surface showed 62.7% versus 77.3% locally, exposing council-tax, housing-cost, program and demographic gaps. R17's max/median weight ratio was 400 against the unchanged limit of 100.

Holdout 0.1895 and incumbent fitted loss 0.1815 use different weighting and populations; they cannot be ranked directly. Scoring now carries and validates these separate bases. The review evidence is explicitly a transcription of published aggregates; original R18 row artifacts were unavailable for replay.

The assembly runbook covers microcosm-uk-2024-25-dense, its non-default inspect role and separate human publication step. No data was published.

Validation

At 35161003, rebased onto main at 5ab1b056, the final affected 17-module suite passed 355 tests on Python 3.13.14 and 355 on Python 3.14.6. Independent implementation and rebase verification are clean. Ruff, formatting of changed files, both census checks, reproducible target regeneration, CI inventory and diff checks pass. Hosted checks report separately. No fresh licensed build or calibration was run for these review fixes.

Refs #762, #495, #665, #736, #796, #802, #866, #867, #868, #869. Merge remains subject to María's explicit go-ahead.

@vahid-ahmadi

Copy link
Copy Markdown
Contributor

Review pass at 9f4efc77 (Claude Code, high effort; worktree checkout, Python and committed registers read against the PR body; 21 suites run on the PR tree (844 passed, 0 failed) and again on a scratch merge onto origin/main (all passed, 0 failed, exit 0); both census --check tools current on both; ruff check and ruff format --check clean on all 34 changed Python files; git merge-tree onto main is conflict-free).

One process blocker, then substance

1. CI cannot run on this PR as filed. .github/workflows/test.yml:5-7 triggers on pull_request: branches: [main], and the PR's base is uk-rowwise-candidate-762, so "no checks reported" is structural, not a flake. The base branch is now identical to #852's merged head, but the merge-base with main is 8be32dc9, so the PR does not contain #852's final b875d4c4 merge-from-main and GitHub's "clean" status is against a stale base. My scratch-merge run stands in for CI here, but the PR should be retargeted to main so GitHub actually runs it before it merges.

Findings

2. Should-fix — the dense contract does not bind the signed gate report to the run it validates. _check_uk_dense_gate_report (contract.py:4278) verifies schema, digests, posture, HMAC, and attestation.release_id == report.release_id, but never compares the report's release_id to the build's attempt id, and _validate_uk_dense_release_dir only checks build_id == release_id. So a stale but validly signed shippable report dropped into a hand-assembled directory passes validate_release_dir. The assembler closes this (tools/assemble_uk_dense_release_dir.py:213-244 hash-joins the report to manifest.outputs.local_gate_report.sha256 and checks report.release_id against the Logbook build_id), but the contract is what a consumer runs against a directory it did not assemble. One equality check in the contract makes the two agree.

3. Should-fix — the A16 register's tracking field names the wrong issues. All five expires_on: 2026-10-03 entries in calibration_measure_exclusions.json carry tracking: microcosm#736; the PR body says they are tracked on #866#869, and those issues exist with matching titles. tracking is what the expiry refusal, the manifest receipt and reviewed_limitations cite, so the pointer a reader follows in October should be the per-row issue.

4. Should-fix — the assembler does not hash-join the score to the candidate. assemble_uk_dense_release_dir.py:201, 253-254 copy score_vs_incumbent.json and --incumbent-manifest without checking them against the candidate; the scorer already pins --candidate-diagnostics-sha256 and writes an inputs block (score_uk_local_candidate.py:518), so comparing that to measured["diagnostics"] is the missing line. Related: build_manifest["code"]["git_dirty"] = False (:481) is asserted rather than measured, since the candidate manifest records only git_commit.

5. Should-fix — stale K in signed text. local_area_support_exclusions.json cites rows "at the ruled K=4 (17/49 at K=10)"; the band-H deferral rationale in the generator says "At the ruled K=10, 84 of 296"; local_doctrine.py:88-89 says K=10 refused 86 band-H cells. Doctrine is K=15, and 84 versus 86 disagree with each other. These are the sentences a later reader will trust.

6. Nit — the round-trip is not tested exactly. test_uk_rowwise_candidate.py:1186-1195 checks column names, row count and the weight total with pytest.approx after load_uk_rowwise_dataset; a table-equality assertion is what "undoes the export rename" needs.

Questions

  • What retires a defer_if_compiles=True deferral? The A13/A14 deferrals live in generator code with no window and no re-measurement hook, and target_reference_authoring.py skips the stale-deferral raise for them by design. At K=15 City of London carries about 1.5× the K=10 rows; did R16's area_support_summary.csv still show both micro-LAs below the floor? If not, the A4 exclusion gate should have fired.
  • Lookup fix. incumbent_surface_evaluation.py:307 accepts both target@area@period and target@area, but the test uses only the no-period form, and the tool derives bound via rsplit("@", 1)[0] (:137), which would strip the area if real diagnostics carry no period suffix. Which form do they carry?
  • A17 versus cross-grain. National ons.tenure.* controls exist in uk_population_targets.json; if the country leg is bound, reconciliation rescales LA tenure and the A17 factor is moot on the final surface. R16's 87.3 → 99.2 jump suggests it is not bound. One line from you settles it.
  • _is_census_vintage_hold hard-codes from in (2021, 2022); intended, but a 2031 hold will silently not uprate.

Verified good

  • Doctrine (A): constants at local_doctrine.py:63, 74, 82, 92, pin test updated; _validate_cli_args under --release-candidate refuses the weight rule, epochs ≠ 1500, clones ≠ 15, measure exclusions, skip-holdout, engine blocks > 1 and sample fraction ≠ 1; uniform stays allowed and receipted as {"default": "grain_equal", "effective": "uniform"}.
  • A15/A17 uprating (B): the factor is computed from the ons.households_total fact with an exactly-one match (else ValueError), 29,003,000 / 28,060,832 = 1.0335759; applied to the census-household rows at both grains and to ons.tenure.* cells with a 2021/2022 hold only; an absent fact yields applied: False and the release posture raises; receipted under ladder_household_uprating and tenure_cells; the membership recount gives 359 tenure cells per target with 327 + 32 holds = 1,436, matching R16's 1,308 + 128.
  • A16 (C): the window is enforced at apply time — outside approved_on..expires_on raises, within seven days warns — and the two land rows are absent; 49 exclusions total.
  • Registers (D): 6 adjudications, 2 support exclusions, 19,105 active and 513 signed-deferred (19,618 − 19,105), every deferred cell carrying a reason id; no timestamps in committed registers.
  • Signing (E): signer, battery and contract share one byte-identical _canonical_json_bytes; a missing key appends a failure rather than passing; tests cover tampered signature, post-signing edit, dev posture, failing blocking gate and missing key; the dense digests are lockstep-tested against the live manifest.
  • Evaluator (F): the regional roll-up reindexes household weight to persons and masks by region and closed age band; council-tax bands by household mask; an unknown region raises.
  • PR A residuals (G): test_candidate_multi_block_engine_run_is_never_releasable asserts releasable: False with single_block_engine: False; the golden target_frame is now check_exact=True. Thank you for taking both.
  • No gates.json, roster or spec changes in the diff.

Needs the licensed engine or data

That ons.households_total resolves to exactly one fact on the real Ledger; K=15 support for E06000053 and E09000001 and band H; the frame's council_tax_band string form; the real diagnostics name format; R17 = R16 byte identity; every R16–R18 fit number; and the regional fixture's 207 rows against the body's 198.


No code-level blocker. Retarget to main so CI runs, then 2 and 3 are the two I would land before merge — the contract binding because it is what a consumer runs, the tracking ids because they are what the October expiry points at. 4 through 6 are tightening. The uprating, the expiry refusal, the single canonical form with tamper tests and the assembler's hash-join are the substance, and they check out.

@juaristi22
juaristi22 force-pushed the uk-rowwise-candidate-762-b branch from 9f4efc7 to 5c86c5f Compare September 7, 2026 10:53
@juaristi22
juaristi22 changed the base branch from uk-rowwise-candidate-762 to main September 7, 2026 10:53
@juaristi22 juaristi22 closed this Sep 7, 2026
@juaristi22 juaristi22 reopened this Sep 7, 2026
@juaristi22

Copy link
Copy Markdown
Collaborator Author

Thanks. Retargeted to main (rebased onto b875d4c) so CI runs; fixes in 5c86c5f.

(2) The contract now binds report.release_id to build_manifest.attempt_id and refuses a build manifest without one.

(3) The five A16 rows track #866#869 per row.

(4) The assembler hash-joins score.artifacts.candidate_diagnostics.sha256 to the diagnostics bytes and the two incumbent digests to --incumbent-manifest outputs; git_dirty is measured by the driver and recorded as measured or unmeasured, never asserted.

(5) The three sentences now state K=15 with history: Scilly 24 rows / ESS 8.1, City of London 72 / 11.0 on R17; band H unsupported in 76 of 296 authorities at K=15; K=10 refused 86 authority cells, 84 of them band H. Register regenerated from the pinned feed, rationale strings only.

(6) Round-trip is exact, weights compared as the typed vector.

Questions: a defer_if_compiles deferral retires on regeneration once the support exists, and the A4 exclusions still bind at K=15; diagnostics names carry @2025 and both forms are tested; no country-level ons.tenure.* control is bound (declared at local_authority only), so A17 is live on the final surface; _is_census_vintage_hold now takes its years from the ladder's oa_vintage.

@vahid-ahmadi vahid-ahmadi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Second pass at d5f04a80 (Claude Code, high effort; worktree checkout, the fix commit 5c86c5fd and the two later commits read against the dispositions; the 21 suites from round one: 853 passed, 0 failed, 0 skipped; both census tools current; ruff check clean; the merge from main carries only #849 with an import reconciliation in one test file and no evil-merge content).

All six findings closed as described, with tests that fail on the previous head where a failing test is possible.

2. Verified. The contract reads build_manifest.attempt_id, fails on a missing or empty value, and _check_uk_dense_gate_report fails when report.release_id differs from it (contract.py:4230-4242, :4290-4332); build_manifest.json is a required release file so a missing manifest cannot bypass it. The two new contract tests — a validly signed report from another attempt, and a manifest with the attempt id deleted — both fail on 9f4efc77. The driver signs with state.build_id and the assembler already writes the Logbook build_id as attempt_id, so an R17-style directory still validates.

3. Verified. Savings interest → #866, housing benefit → #867, both plan-2 stocks → #868, JSA → #869, matching the issue titles, pinned in test_uk_measure_simulation.py. One pre-existing slip in a row the fix touched: the JSA reason says "1.8x at initialization" while 199k against 71k is 2.8×, which is what #869's title says.

4. Verified. The assembler requires the score's candidate_diagnostics.sha256 to equal the measured diagnostics digest and the two incumbent digests to equal --incumbent-manifest outputs (assemble_uk_dense_release_dir.py:255-283); git_dirty is taken from the candidate manifest when it is a bool and recorded as unmeasured otherwise (:504-518), with the driver measuring it by git status --porcelain --untracked-files=no and returning None outside a repository. Three new assembler tests, all failing on the old head. One policy observation rather than a finding: the dense contract never inspects git_dirty, so a candidate measured dirty, or unmeasured, still assembles and validates with exit 0 — the new test asserts exactly that. "Never asserted" is satisfied; whether a dirty candidate should ship is a call for María.

5. Verified and internally consistent. The three sentences agree on K=15 with the K=10 history (84 band-H plus the two micro-authorities = 86), and the receipts corroborate the K=10 line. The K=15 figures themselves (Scilly 24 rows / ESS 8.1, City of London 72 / 11.0, 76 of 296) are not in the receipts file, so they rest on R17. The membership regeneration is rationale strings only: 298 leaf changes, 297 of them rationale text and one the disclosed source_fact_feed rename. One wording note: with 72 rows City of London now clears the 50-row floor, so "unreachable by clone count" is true only of the ESS leg.

6. Verified. Per-entity assert_frame_equal on all columns and the household weights compared as the written column with assert_array_equal. check_dtype=False is unnecessary — it passes with dtypes checked — so it could be tightened.

Questions. _is_census_vintage_hold now derives its years from the ladder's oa_vintage; the new test fails on the old head. One residual: a hold from a non-census vintage is skipped silently — tenure_cells counts only uprated cells, and if oa_vintage were missing the year set would be empty while applied could still read true. A count of skipped holds in the receipt would close that. Both bound-name forms are tested. The A17 answer (no country-level tenure control bound) settles that question.

Nit. ruff format --check flags one long assert in test_uk_council_tax_targets.py:97 from 88c45551; CI runs only ruff check, so not blocking.


Approving. The two things worth a line from you rather than a change: whether a measured-dirty candidate should be allowed to assemble, and a skipped-hold count in the uprating receipt.

@anth-volk anth-volk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found six release-affecting issues in this revision. I think the first two should be resolved before publication.

  1. High — Failed accuracy checks still permit release. Local target accuracy, per-program accuracy, weight concentration, and effective sample size are configured with criticality: diagnostic, meaning their failure is only recorded and does not prevent release (configuration). The release decision excludes those failures (release decision), and a test explicitly accepts a weight ratio above the limit while asserting releasable is True (test). The real run recorded a maximum-to-median weight ratio of 400 and 42 local targets more than 25% wrong, yet was accepted (run record). These limits should prevent release, with tests proving that excessive program totals and concentrated weights are rejected.

  2. High — The comparison that exposed the worst results is optional. The release assembler requires score_vs_incumbent.json but not the later evaluation against the current dataset's own target set (assembler inputs, packaged evidence). The required comparison reports 98.8% versus 60.4% on this branch's selected targets, while the omitted evaluation finds only 62.7% of local targets within 10%, versus 77.3% for the current dataset, as well as very large council-tax and program discrepancies (results). The assembler should require and preserve this evaluation, then apply explicit limits to the reported discrepancies. The assembler test currently uses only 30 households and two targets, so it cannot exercise these real-output conditions (test fixture).

  3. High — The evaluation tool permits a processing mode already proven to multiply national totals. --engine-blocks accepts any integer and passes it directly into the calculation (argument and use, calculation call). The branch documents that processing 15 groups inflated corporate land value exactly fifteen-fold, from £2.04tn to £30.7tn (evidence). This evaluator should reject every value except 1, and an end-to-end command test should verify the refusal.

  4. Medium — The reported held-back score is not comparable to the fitted scores shown beside it. Held-back targets are weighted to give geographic categories equal influence and exclude national targets (calculation). The fitted candidate and current-dataset scores instead give each target row equal influence (scoring). Using the same per-row error cap does not put differently weighted results on one scale, so the direct comparison of 0.1895 with 0.1815 is unsupported. Existing tests verify the cap and fold count but not loss_weight_scale or the target-weighting rule (tests). All displayed scores should be recomputed with one weighting method, or clearly separated and no longer compared directly.

  5. Medium — A release produced from uncommitted code is accepted. The specialized UK validator reads the build description but does not call the general validation that requires code.git_dirty to be false; it checks only the build identifier and attempt identifier in this section (validator). The assembler test explicitly accepts both an unknown state and git_dirty: true (test). This can produce data from code that differs from the recorded commit. The specialized validator should require a measured, clean working tree and test both rejection cases.

  6. Medium — Time-limited exclusions can expire after assembly without preventing upload. Expiry is checked while preparing the candidate (preparation check), but the assembled release validator only checks the copied coverage data structurally and the upload path only calls that validator (assembled validation, upload path). Several exclusions expire on 2026-10-03, so a release assembled in September could still be uploaded after its approvals expire. Publication should re-check every required expiry date, and tests should cover both expired and missing dates.

I ran all 17 changed test modules relevant to this work; they passed, as did git diff --check. I could not reproduce the full UK calculation because its private input data is not present locally. The real-output evidence above is therefore based on the committed run records; a sanitized machine-readable result should be retained and exercised by the release tests.

juaristi22 and others added 16 commits September 7, 2026 23:18
…usions (PR B)

Maria's rulings of 2026-09-02: accept the SPI-frame proxy, the unbanded-only
HMRC surface, the ONS total-population universe for age structure, and the
VOA household proxy for council-tax bands; replace the UC household-grain
basis with benefit-unit grain; re-word the census disclosure-control record
to cover the local-authority leg the ladder binds; and exclude the Isles of
Scilly and the City of London from the local-authority support floor on the
measured K=4 and K=10 shortfalls. Windows to 2026-12-02.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…feed (#762 A13, PR B)

The sixth licensed dry-run reached the cross-grain reconciliation and the
engine refused the council-tax band groups: England and Scotland carry
country-grain stock-by-band controls, Wales carries none in the pinned feed,
so the 174 active Welsh local-authority cells form an unparented leg. Per
Maria's A13 ruling those cells are signed-deferred
(council_tax_wales_country_control_absent) until a Wales control exists; no
Welsh control is minted from the local cells. Deferring an available fact
needs an explicit opt-in on the area deferral (defer_if_compiles), scoped to
this adjudication; ordinary missing-cell deferrals still go stale when their
cell compiles. Surface 19,618 -> 19,444 active; council tax 2,541 -> 2,367;
pins moved accordingly.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t the receipts

Measured at f100 on spine-m: K=4 refused 172 constituency UC child-band cells
with zero support; K=10 cleared every constituency cell and refused 86
local-authority cells, 84 of them council-tax band H, because the spine
carries 170 band-H households from 49 raw FRS sources. Per Maria's A14 ruling
the 296 band-H local-authority cells are signed-deferred
(council_tax_band_h_spine_support_absent) and the two support-floor
exclusion areas' own local-authority cells are signed-deferred
(local_authority_support_floor_excluded); the exclusion reasons record the
amendment. Surface 19,444 -> 19,105 active; pins moved accordingly. The
receipts document opens with R0-R5 (identity, dry-run K sweep and cross-grain
receipt, f001, f010, the K=4 refusal, the K=10 measurement).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Both rules fit the local surface (every family but council tax at or above
99 percent within 10 percent); grain_equal lifts the national rows from 78 to
92 percent within 10 percent and concentrates weight harder (189 versus 12
constituencies below the ESS floor). Both sit on the 100x stretch bound, so
A3 is the binding decision; the 20 and 10 measurements follow.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ement)

Tightening the bound from 100 to 10 leaves loss and every fit share unchanged
to a tenth of a point under both rules; bound 10 under uniform is the only run
that clears the support floor (min constituency ESS 54.1, exit 0).
grain_equal at 10 keeps the 92 percent national fit and misses the floor in
five constituencies by 0.3 to 7.7 ESS; the K=15 escalation is R9.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ion)

grain_equal at K=15 and bound 10 passes every release-blocking gate (min
constituency ESS 54.1) while keeping the national rows at 92 percent within
10 percent; uniform at K=15 passes with more margin and 79 percent national.
Memory stays flat with per-block engine resolution; wall grows 50 percent.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1500 epochs is close to converged under uniform and still moving under
grain_equal; uniform spends the extra epochs on the national rows (78.6 to
85.2 percent within 10 percent), grain_equal spends them chasing the
unreachable housing-benefit row (max/median 827 to 2,857). Health audit:
mechanics clean across 14 runs; flags are the epoch cap, the census-2021
household mass cut landing on single pensioners, and six unreachable
national rows (proposed rulings A15, A16).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…762)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…er uprating; A16 exclusions (#762)

María's rulings of 2026-09-03, each the measured choice in receipts
R6-R10:

- UK_LOCAL_MAX_WEIGHT_RATIO 100 -> 10 (A3): no fit cost at 100/20/10, the
  only bound that clears the ESS floor, and the national doctrine's bound.
- UK_LOCAL_TARGET_WEIGHT_RULE = grain_equal (A2): national rows 92-93
  percent within 10 percent versus 78-85 under uniform; uniform stays a
  receipted override.
- UK_LOCAL_CLONE_COUNT = 15 and UK_LOCAL_SOLVE_EPOCHS = 1500 as doctrine
  constants; the driver defaults read them and --release-candidate refuses
  other values.
- A15: every ladder census household row is scaled by one national factor
  from the Ledger's ons.households_total fact at the calibration year
  (29,003,000 / 28,060,832 = 1.033577), fail-closed by name, receipted in
  the manifest, mandatory under --release-candidate.
- A16: seven reviewed measure exclusions (land value x2, savings interest,
  housing benefit, SLC plan-2 borrowers x2, JSA claimants), unreachable by
  reweighting on spine-m, one-month window to 2026-10-03, tracked on
  microcosm#736.

Receipt R12 records the applied values and the verification.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e posture; manifest records measure exclusions (#762)

Under the ruled doctrine (bound 10, grain_equal, K=15, 1500 epochs, A15
uprating, A16 exclusions) every release-blocking gate passes: national 94.7
percent within 10 percent, max/median weight 398 (was 2,857), median
constituency ESS 219, households 28.93M, holdout mean 0.204 versus 0.304
uncalibrated. Tenure falls to 87 percent within 10 percent because its
census-2021 cells were not uprated with the household rows (proposed A17).

Driver: the gate battery now receives release_candidate from the CLI
instead of a hard-coded False, and the manifest carries the measure
exclusions the national compile stood on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ipt areas the incumbent lacks (#762)

On the 19,089 rows both can estimate the candidate's capped loss is 0.0146
against the incumbent's 0.181 (98.0 versus 60.4 percent within 10 percent;
16,973 versus 2,116 head-to-head wins). The incumbent has no weights for
Northern Ireland's N09000011, so the scorer now records
incumbent_missing_areas and scores those 16 rows candidate-only instead of
refusing; the candidate's full-surface loss and its loss on the compared
rows are both reported.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…on; withdraw two A16 exclusions; receipt block sensitivity (#762)

Comparing initial national estimates between the 15-block and single-block
runs: corporate land value is exactly 15x under blocks (the policyengine-uk
formula allocates a fixed national aggregate by share of the block's total
weighted corporate wealth), total land value 5.4x, SLC repayments 1.7 percent;
361 of 364 rows identical. Single-block resolution puts the land rows within
3 and 9 percent of the ONS balance sheet, so their two exclusions are
withdrawn (register 51 -> 49; A16 is five rows). The manifest's
measure_resolution now names the known population-normalised measures and
says a per-block run is not evidence for adjudicating them.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…-candidate pre-flight (#762)

María's A17 ruling (2026-09-03): the 1,436 census tenure cells (Census
2021; Scotland 2022) held to the calibration period take the same national
household factor as the ladder rows, so the tenure partition keeps its
published shares at the uprated level. Keyed on the hold metadata: a tenure
cell compiled from a fact at the calibration period is never touched. The
receipt rides ladder_household_uprating.tenure_cells.

tools/preflight_uk_local_release_candidate.py checks, fail-closed and by
name, the launch environment (signing key, pins, digests, doctrine) and a
finished run (release posture attested, shippable, every release-blocking
gate passed, single-block engine, doctrine values, A15/A17 uprating,
measure exclusions and their windows, holdout, Logbook row, artifact
digest). On R13 it names the four defects the re-run fixes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ation, registry entry, assembler, pre-flight release check (#762 A18)

microcosm-uk-2024-25-dense follows the national constant-id approach under
the non-default local-area role with UK evidence: the signed local
gate-battery report verified with the executor's key (release posture,
shippable, the six local entries, scoped digests pinned and lockstep-tested,
HMAC recomputed), the incumbent score, and a uk_source_coverage.json naming
the spine, Ledger artifact, ladder, incumbent, doctrine, exclusions, signed
deferrals, holdout and uprating. Artifacts pin to the release id or a
per-cut tag; the registry gains ("uk", 2025, "dense") in the private repo.
tools/assemble_uk_dense_release_dir.py verifies the hash join, re-runs the
candidate pre-flight, stages, validates and renames; it prints the
--no-latest publication command for the human step. Runbook in docs/.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t within 10 percent, shippable, holdout 0.190 (#762)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…re-flight authenticates the report as the contract will (#762)

Found when assembling the dense line from R16: the release contract could
not authenticate the signed local report. resign_uk_gate_report (used by
finalize_uk_scoped_gate_report for the local and the national seam reports)
signed with the Logbook's canonical JSON, which renders integral floats
without the .0 (50 instead of 50.0), while the battery and every verifier
use json.dumps's form. Any report whose gate details carry an integral
float - the local battery's ESS floor 50.0 - therefore failed
verification. Sign with the battery's canonical bytes; a regression test
finalizes a report carrying 50.0 and verifies it under the contract. The
candidate pre-flight now runs the contract's report verification so this
class of defect surfaces right after a run.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
juaristi22 and others added 13 commits September 7, 2026 23:20
…ical form (#762)

The test had encoded the Logbook canonical form the defective re-signer
used; it now recomputes the HMAC the way every verifier does.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…dentical weights to R16) and the first contract-valid dense release directory (#762)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…, signed items included (#762 I9)

tools/evaluate_uk_incumbent_surface.py scores a dense candidate on the
vendored, hash-pinned fixtures of the incumbent's national (637 rows) and
local (23,545 rows) target surfaces: the national rows join to our compiled
specs by name, normalised name or single-cell contract id and are estimated
through the un-excluded registry's constraint matrix over the calibrated
weights, so the signed-out rows are measured too; the local rows map to our
metrics by name (the VOA bands by alias) and are estimated from the
engine-resolved household metrics; every row carries our status - bound,
measure-excluded (with tracking and expiry), signed-deferred (with the
reason id), no fact, or not ported with the parity register's concern - and
the incumbent's own estimates on its local surface come from the extractor
tables. Summaries by grain, source and metric; a markdown report that leads
with the ugly part.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the export rename (#762)

The rowwise writer renames every entity's clone-index column to the
artifact's shared clone_index at export; the Frame's flattening rule then
refuses the artifact in the compact national loader, so no tool of ours
could open the dense H5 (found by the incumbent-surface evaluator). The
reader renames clone_index to <entity>_clone_index per table and assembles
and validates the frame as the national loader does. The end-to-end test
pins both behaviours; the evaluator loads through it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…repared frame (#762 I9)

The resolver returns the adapter's prepared frame carrying the resolved
measure columns; building the matrix over the raw frame skipped all 403
rows. Also keys the counterfactual filter on the contract's measurement
kind, since compiled specs carry the measure as a column name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ows; fix the local target-id lookup (#762 I9)

The metric -> target-id map was inverted, so every incumbent local row
read 'no_reference'; a unit test pins the direction. The incumbent's 198
regional rows (ONS age by region, VOA council-tax band by region) are now
measured by rolling the frame up by assigned-area region, with the FRS
region agreement receipted, instead of being reported as unmatched.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…items measured (#762 I9)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
#762 PR B)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… --engine-blocks K, exact golden frame (#762 PR B)

An f100 run resolved in two engine blocks now has an end-to-end assertion
that the manifest writes releasable: false with release_posture naming
single_block_engine, so a future caller bypassing _release_verdict is
caught. The dense builder's golden target_frame is compared exactly, like
its matrix.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…er-row A16 issues, score hash-joins, measured git_dirty, K=15 texts, exact round-trip (#762)

- The dense contract binds the signed gate report to the build's attempt_id
  (a validly signed report from another run is refused; a build manifest
  without attempt_id is refused).
- The five A16 register rows point at their own spine-defect issues
  (#866-#869) so the October expiry follows the per-row pointer.
- The assembler hash-joins the score receipt to the candidate diagnostics
  bytes and to the incumbent manifest's outputs, and records git_dirty as
  measured by the candidate build (the driver now measures it) or as
  unmeasured, never asserted clean.
- The three K sentences state K=15 with history: Scilly 24 rows / ESS 8.1
  and City of London 72 rows / ESS 11.0 on R17; band H has no support in 76
  of the 296 deferred authorities at K=15 (84 at K=10); K=10 refused 86
  local-authority cells (84 band-H plus the two micro-authorities). The
  membership register is regenerated from the pinned feed with only the
  rationale strings changed; the generator records the artifact-relative
  feed name instead of the operator's path.
- The row-wise round-trip test compares every table exactly and the weight
  vector against the written column.
- _is_census_vintage_hold takes its census years from the ladder's
  oa_vintage instead of a constant; a hold from a non-census vintage never
  takes the household factor.
- Both bound-name forms (with and without the period) are tested.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The council-tax deferral test still pinned the K=10 sentence the review
round replaced; it now pins the K=15 fact and the K=10 history.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@juaristi22
juaristi22 force-pushed the uk-rowwise-candidate-762-b branch from d5f04a8 to 3516100 Compare September 7, 2026 21:33
@juaristi22

Copy link
Copy Markdown
Collaborator Author

@vahid-ahmadi @anth-volk Thanks for the reviews. I've addressed Anthony's findings and Vahid's second-pass points, and rebased onto main at 5ab1b056. The current head is 35161003.

For Anthony's six findings:

  1. Quality gates now block release. Target fit, family fit, weight concentration and ESS failures are no longer diagnostic-only. All numerical thresholds and the existing family-gate rules are preserved, including the diagnostic within-10% measure. Regression tests exercise actual excessive errors and problematic weights, rather than only substituting a failed gate status.

  2. Evaluation on the incumbent's target surface is required. Assembly and standalone directory validation now require authenticated, complete row evidence covering the pinned 637 national and 23,545 local targets, including measurable deferred rows. The evaluation binds the candidate dataset, original manifest, diagnostics, Ledger and incumbent inputs. Validation recomputes the summary and verdict from finite row measurements using the existing absolute limits; missing, mismatched or failing evidence refuses release. National rows compare against the incumbent's target values; local rows also require its realized estimates. No national realized estimates or new relative-to-incumbent tolerance are implied. The retained original inputs and copied release metadata are cross-checked, and the data validator remains independent of the build package and engine.

  3. Evaluator block count is enforced. evaluate_uk_incumbent_surface.py rejects every --engine-blocks value except 1 during argument parsing, before reading files or loading the engine. The regression invokes the actual CLI with unavailable input paths.

  4. Fitted and holdout losses are explicitly separated. The producer records the actual weighting rule, scale, population and grains, and the scorer validates that basis. The report and runbook withdraw the direct ranking of the historical fitted and holdout losses; their numerical values remain unchanged.

  5. Release code provenance must be measured and clean. Both assembly and later directory validation require code.git_dirty to be exactly false; missing, null, malformed and dirty states are rejected. Diagnostic runs remain possible.

  6. Exclusions are checked at validation/upload time. Original approval and expiry records are retained and checked against the current date. Copied coverage records must match those originals exactly. Independent verification exposed and then confirmed the repair of an expiry-extension bypass: editing a copied date and refreshing packaging checksums can no longer hide an expired original approval. Deletion is covered too. Upload invokes the directory validator before sending bytes; separate indefinite support/binding adjudications remain unchanged.

For Vahid's second pass, I've corrected the JSA ratio to 2.8×, clarified that City of London's 72 rows meet the row floor while ESS 11 remains below 50, enabled exact dtype checks in the roundtrip test, and formatted the council-tax assertion. Tenure-uprating receipts now distinguish attempted, eligible, applied and skipped holds with vintage/reason metadata, including missing and non-census cases; preflight checks the actual tenure holds. The dirty-code question is addressed above. These rationale edits preserve the approval fields.

The rebase preserves main's 314 newly activated PIPR rows and all 513 signed deferrals, giving 19,419 active references. Regeneration from the authenticated updated Chronicle feed is reproducible, and both census checks pass.

Final validation on the rebased code: 355 tests passed on Python 3.13.14 and 355 on Python 3.14.6 across the affected 17 modules. Independent implementation and rebase verification are clean; Ruff, changed-file formatting, CI inventory and diff checks pass. Hosted CI is still running, with no completed failures at posting time.

The runbook, historical receipts and PR description now state the release limitation explicitly. No licensed build or calibration was rerun, no approval was renewed, and no historical verdict was re-signed. The additional review evidence is labelled as a transcription of published aggregates, not an original R18 replay. The existing dense candidate remains blocked from release.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants