UK dataset sizes: informed L0 and exact-count candidates (#355) - #877
Conversation
d5f04a8 to
3516100
Compare
d4043ec to
573c4b4
Compare
…evaluate_uk_dataset_size steps 00-90, uk_fit_by_family lifted (#355) Every evaluation piece for a --dataset-households candidate now has one name and one place: - uk_runtime/size_evaluation.py — pure measurement over a run directory: load_run (tolerant of pre-#877 dense runs), run_acceptance (the size-run checklist, not_applicable on dense runs), fit_tables (by grain and family), weight_tables (Kish ESS, distinct sources, stretch vs the Horvitz–Thompson baseline and vs pool design from the selection sidecar or a spine, self-checked against the manifest), area_support_tables (per-grain floors and breaches), gate_table (six ids with criticality), paired_targets (join on name; wins/ties/losses; the reference's red rows tracked through family/area/metric), dense_reference_deltas (size-only effect from the run's own dense reference), frozen_vs_recomputed (national rows against the incumbent-surface evaluator), footprint, and summarize with PRE_REGISTERED_OUTCOMES_V1 flags. No subprocess, no engine, no licensed data in tests. - tools/evaluate_uk_dataset_size.py — the one command: steps 00-run-acceptance, 10-dense-reference, 20-vs-reference/<label>, 30-incumbent-score (score_uk_local_candidate), 40-incumbent-surface (evaluate_uk_incumbent_surface --engine-blocks 1 + frozen vs recomputed), 50-downstream (uk-candidate-eval T3/T4/T5 and the #731 scorecard under this venv, each timed with /usr/bin/time -l), 90-summary (EVALUATION.md + JSON with the pre-registered table and a file index); every step writes receipt.json (inputs and outputs with digests, argv, wall, exit) and is skipped with a reason when its inputs are absent; re-running a step rewrites only its folder. - _fit_by_family lifted from the driver into uk_runtime/diagnostics.py::uk_fit_by_family unchanged; the driver imports it. Tests: test_uk_size_evaluation.py (synthetic run dirs in both manifest shapes, table-format H5s, time -l parsing, red-row mapping, stretch self-check, breaches, flags, refusals) and test_uk_evaluate_dataset_size_tool.py (tree, receipts, manifest, summary; skipped steps; a failing downstream stub recorded without aborting; single-step re-run). Implemented by Codex from .codex-work/PLAN.md; verified here: ruff, format, ci_test_groups --verify, 88 tests across the four UK rowwise/evaluation files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
e8f7c6f to
37f8193
Compare
…evaluate_uk_dataset_size steps 00-90, uk_fit_by_family lifted (#355) Every evaluation piece for a --dataset-households candidate now has one name and one place: - uk_runtime/size_evaluation.py — pure measurement over a run directory: load_run (tolerant of pre-#877 dense runs), run_acceptance (the size-run checklist, not_applicable on dense runs), fit_tables (by grain and family), weight_tables (Kish ESS, distinct sources, stretch vs the Horvitz–Thompson baseline and vs pool design from the selection sidecar or a spine, self-checked against the manifest), area_support_tables (per-grain floors and breaches), gate_table (six ids with criticality), paired_targets (join on name; wins/ties/losses; the reference's red rows tracked through family/area/metric), dense_reference_deltas (size-only effect from the run's own dense reference), frozen_vs_recomputed (national rows against the incumbent-surface evaluator), footprint, and summarize with PRE_REGISTERED_OUTCOMES_V1 flags. No subprocess, no engine, no licensed data in tests. - tools/evaluate_uk_dataset_size.py — the one command: steps 00-run-acceptance, 10-dense-reference, 20-vs-reference/<label>, 30-incumbent-score (score_uk_local_candidate), 40-incumbent-surface (evaluate_uk_incumbent_surface --engine-blocks 1 + frozen vs recomputed), 50-downstream (uk-candidate-eval T3/T4/T5 and the #731 scorecard under this venv, each timed with /usr/bin/time -l), 90-summary (EVALUATION.md + JSON with the pre-registered table and a file index); every step writes receipt.json (inputs and outputs with digests, argv, wall, exit) and is skipped with a reason when its inputs are absent; re-running a step rewrites only its folder. - _fit_by_family lifted from the driver into uk_runtime/diagnostics.py::uk_fit_by_family unchanged; the driver imports it. Tests: test_uk_size_evaluation.py (synthetic run dirs in both manifest shapes, table-format H5s, time -l parsing, red-row mapping, stretch self-check, breaches, flags, refusals) and test_uk_evaluate_dataset_size_tool.py (tree, receipts, manifest, summary; skipped steps; a failing downstream stub recorded without aborting; single-step re-run). Implemented by Codex from .codex-work/PLAN.md; verified here: ruff, format, ci_test_groups --verify, 88 tests across the four UK rowwise/evaluation files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
vahid-ahmadi
left a comment
There was a problem hiding this comment.
Review pass at 37f81933 (Claude Code, high effort; worktree checkout; without the engine: 1,048 passed, 24 skipped, 10 failed — the ten are test_us_multispine_pool_tool needing the US extra, identical on main; ruff check and ruff format clean on all 29 changed Python files; CI green apart from one wheel job unreported).
The default solver paths are byte-identical, and that was checked rather than read
This is the second UK PR in a week to touch the generic solver, so I ran the same synthetic n=300 problem against main's and the PR's microcosm.calibrate in one venv: the count-basis L0 search with target_records, the same under mass="conserve", a fixed l0_lambda, and Sampford select_exact_k plus refit_l0_selection — weights, gate probabilities, support, q, trajectories and losses all hash-identical. Reading confirms why: steer() reduces to the old bisection when the verdict is not_required, and settled() reduces to the old tolerance test without feasible_draw_pi_hi. The US exact-K ladder's tests pass with no fixture regeneration. The parity fixture's direct.csv is unchanged and only the pin moved, asserted bitwise on every platform.
The statistics are right: units with π at or above pi_hi form a certainty stratum, boundary q is m·π/Σπ with a strict cap at one, and exact_k_design_feasibility is the draw's own inequality, property-tested against the draw across all four verdicts. Protected carriers get π exactly one via torch.where on the mask, so forced inclusion lands in the certainty stratum and does not break the design, and the refit asserts none was lost. Refusals carry numbers (the full feasibility scan) rather than errors, the unsupported targets are refused by name — and found exactly the two UC bands this PR then signs — and the resume path verifies arrays, identity keys, household ids, the target surface, initial weights and both closing losses. --release-candidate refuses --dataset-households, the manifest's releasable is false whenever a size is requested, and no registry or pointer moves.
Findings
1. Should-fix — doctrine drift is undetectable on resume. _size_checkpoint_identity (build_uk_rowwise_candidate.py:489-520) carries pins, seeds, epochs and sample settings but no code pin and no doctrine constants; load_uk_size_checkpoint rebuilds with the checkpoint's own target_loss_cap and options, the refit takes max_weight_ratio and mass from the dense solve's options, and the closing-loss check uses the stored cap. If UK_LOCAL_MAX_WEIGHT_RATIO or UK_LOCAL_TARGET_LOSS_CAP change between checkpoint and resume, the refit runs under the old bound while the manifest declares the new one. Put the existing code_pin and the doctrine values into the identity, or assert the restored options against current doctrine after the load.
2. Should-fix — a stale checkpoint in --out is refused only after the dense solve. write_uk_size_checkpoint refuses to overwrite (size_checkpoint.py:135-137), correctly, but it runs after the solve and the search, and _output_paths' pre-solve existence guard does not cover the checkpoint files. A re-run into a directory left by a refused run loses the multi-hour solve at the write. Add the two files to the pre-solve guard.
3. Should-fix — no frozen control covers gates.py, and it sits outside the attested kernel sources. The pre_best_iterate oracle pins the gate module's sha to the current file and imports HardConcrete from it on both sides, so it cannot detect a gate-behaviour change; this PR re-cut that sha. My A/B run is the only evidence of byte identity. Separately, the seed-protocol implementation digest hashes calibrate.solve and calibrate.exact_k only (seeds.py:348-349), so gates.py and the new initialization.py — which now shape L0 behaviour — do not move the attested identity when they change. A frozen-gates control and adding both modules to that list close it.
4. Question — say plainly how deterministic the "draw" was on the licensed runs. The receipts show the protected carriers as certainties at pi_hi = 1 and, at the lower thresholds used for the two 55,000 candidates, a large majority of the selection landing in the certainty stratum with only the tail actually drawn. That is by design — pi_hi is doing the selection — but the body's "exact-count Sampford draw" reads as a random design when it is mostly a threshold on learned π. Reporting the certainty share per run in the body would make the claim honest at a glance. Related: the HT refit baseline is design weights over q projected to design mass, and the stretch multiplier 10 is relative to that baseline, not the dense doctrine's ten-times-design; the plan doc says so and lists it for adjudication, but realized_max_weight_ratio_vs_design is now computed against solve.initial_weights, which on a size run is the HT baseline, so the key name misleads.
5. Question — zero-valued targets in the prior. contribution_initialization uses a unit denominator when the target is zero (initialization.py:327), so raw pound contributions saturate the prior at 0.9. The local parity fixture holds thousands of zero-valued rows (Welsh and Scottish private-rent amounts and renter counts); if any survive onto the compiled surface they dominate the prior. A zero_target_rows count in the size receipt would answer it.
6. Question — two register changes ride along and move the dense surface for every joint build. The PIPR private-rent composition into an annual total (12 × mean monthly rent × the uprated private-renter count, ledger_targets.py:1496) is unconditional, and the two zero-support UC bands become A16 exclusions expiring 2026-12-08 (census counts 49 → 51, 84 → 82). Both are reasonable and both affect comparability with #870's R17 receipts; they deserve their own line in the body, or a split.
Nits
The checkpoint manifest's written_at and absolute directory ride into the candidate manifest (excluded from the identity digest, so harmless, but manifests of identical runs will not byte-match). The parity pin's authoring platform moved from py3.13 to py3.14. Every calibrate() caller's options gains four new keys, which changes the shape of any manifest that embeds them.
Needs the licensed data
Every measured claim (the two 55k candidates, their ESS, the 25% area-support breach, 211 of 650 constituencies below the ESS floor), the frozen_vs_recomputed step — which the receipts say was not measured on either candidate and is the actual test of freezing population-dependent measures from the full pool — any holdout for a size run (all used --skip-holdout), and the incumbent leg of the #731 scorecard, which did not run.
No blocking defects; the machinery is careful and the receipts document the failures honestly. 1 through 3 are the ones I would land before this is used to cut a candidate anyone compares: a resume that can silently run under the wrong bound, a checkpoint that can be lost after the expensive step, and a solver module that is neither controlled nor attested.
…ection-seed moves only the draw (#355) A --dataset-households run replaces its calibration product with the compact refit, but the dense joint solve it was cut from is byte-identical to a standalone dense run on the same inputs, seed and epochs. Keeping it lets a size candidate be compared with its own dense reference without a second full-pool run: - local_rowwise: the evidence labelling (alignment by name, exact target values, local/national diagnostics, past-cap censuses, initial loss) moves into _doctrine_solve_evidence and runs for both results; the solve product carries `dense_reference` (weights, initial weights, diagnostics, losses, censuses). - driver: a size run writes dense_reference_diagnostics.csv (every target's dense estimate, local rows then national, with a `grain` column) and dataset_size_selection.csv (pool row index, household id, clone index, design weight, inclusion probability, certainty, Horvitz–Thompson baseline, refit weight), lists both under outputs with digests, and summarises the reference under solve.dataset_size (losses, fit by family, uk_weight_summary). Dense runs are unchanged; the two files are size-run-only in the publish order. - --selection-seed (requires --dataset-households; defaults to --seed) seeds only the informed L0 search, the exact-count draw and the refit, threaded through the holdout as well, so two selections compare on one pool and one dense reference; recorded as parameters.selection_seed. Tests: the doctrine solve keeps a reference equal to the standalone dense solve and a selection seed leaves it untouched; the CLI size run writes both sidecars, lists them, and records both seeds; --selection-seed without a size is refused. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nd receipt (#355) The first licensed size rehearsal (55,000 of 792,690 at 100 epochs) was refused inside select_exact_k: "degenerate boundary mass … adjust pi_hi or k". With pi_hi=1.0 every gate below one stays in the boundary and its open probability is scaled to the remaining draw size m, so the design is feasible only when m * max(pi_boundary) <= sum(pi_boundary); the L0 budget search stops on the count of not-fully-closed gates, which sits above the open-probability mass while gates are only partly polarised. The refusal carried no numbers. refit_uk_dataset_size now measures selection_feasibility before the draw — certainties and boundary draw at pi_hi=1, boundary mass and largest boundary gate, feasibility, the largest household count feasible at pi_hi=1, the smallest feasible pi_hi on a fixed grid, gate quantiles and counts, the budget search's n_nonzero and lambda — and attaches it to the ValueError on refusal and to the size receipt on success. Nothing is clamped or promoted; the ruling on pi_hi stays a reviewed decision, now made from measured mass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…evaluate_uk_dataset_size steps 00-90, uk_fit_by_family lifted (#355) Every evaluation piece for a --dataset-households candidate now has one name and one place: - uk_runtime/size_evaluation.py — pure measurement over a run directory: load_run (tolerant of pre-#877 dense runs), run_acceptance (the size-run checklist, not_applicable on dense runs), fit_tables (by grain and family), weight_tables (Kish ESS, distinct sources, stretch vs the Horvitz–Thompson baseline and vs pool design from the selection sidecar or a spine, self-checked against the manifest), area_support_tables (per-grain floors and breaches), gate_table (six ids with criticality), paired_targets (join on name; wins/ties/losses; the reference's red rows tracked through family/area/metric), dense_reference_deltas (size-only effect from the run's own dense reference), frozen_vs_recomputed (national rows against the incumbent-surface evaluator), footprint, and summarize with PRE_REGISTERED_OUTCOMES_V1 flags. No subprocess, no engine, no licensed data in tests. - tools/evaluate_uk_dataset_size.py — the one command: steps 00-run-acceptance, 10-dense-reference, 20-vs-reference/<label>, 30-incumbent-score (score_uk_local_candidate), 40-incumbent-surface (evaluate_uk_incumbent_surface --engine-blocks 1 + frozen vs recomputed), 50-downstream (uk-candidate-eval T3/T4/T5 and the #731 scorecard under this venv, each timed with /usr/bin/time -l), 90-summary (EVALUATION.md + JSON with the pre-registered table and a file index); every step writes receipt.json (inputs and outputs with digests, argv, wall, exit) and is skipped with a reason when its inputs are absent; re-running a step rewrites only its folder. - _fit_by_family lifted from the driver into uk_runtime/diagnostics.py::uk_fit_by_family unchanged; the driver imports it. Tests: test_uk_size_evaluation.py (synthetic run dirs in both manifest shapes, table-format H5s, time -l parsing, red-row mapping, stretch self-check, breaches, flags, refusals) and test_uk_evaluate_dataset_size_tool.py (tree, receipts, manifest, summary; skipped steps; a failing downstream stub recorded without aborting; single-step re-run). Implemented by Codex from .codex-work/PLAN.md; verified here: ruff, format, ci_test_groups --verify, 88 tests across the four UK rowwise/evaluation files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…/spine-p, S0, S1/S1b refusals with the feasibility numbers (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t, as the wheels venv is (#355) The wheels lane runs the suite against installed wheels in a venv without pytables; the size CLI test read the exported candidate through pd.HDFStore and failed there (the only failure in 7,963 tests). The rowwise candidate test file's convention is importorskip("tables") and importorskip("h5py") at the top of every CLI test; the size test now follows it, and the two evaluation test files, which write PyTables-format H5 fixtures, carry the module-level importorskip the same lane relies on. With pytables present nothing is skipped (41 tests run); with the import blocked the modules skip instead of erroring. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…b: --selection-pi-hi (#355) refit_uk_dataset_size takes pi_hi (default 1.0, the protected-carriers-only design); the driver exposes it as --selection-pi-hi, candidate-only and bounded to (0, 1], threaded through the holdout, recorded as parameters.selection_pi_hi and in the size receipt (selection_pi_hi, the draw receipt's pi_hi, and the feasibility measurement's requested_pi_hi / feasible_at_requested_pi_hi). The refusal message names the requested threshold. A threshold below one promotes learned near-certain gates; the plan doc records the measured reason and the 2026-09-08 ruling (smoke at the measured feasible count; the 55,000 candidate at pi_hi 0.95, the US exact-k ladder's setting, and 2,000 epochs). Nothing changes for dense runs or for the default. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…355) The 45,800 smoke on spine-p (the tree rebased onto #879) was refused inside contribution_initialization: "nonzero target at row 20648 has no support", a national row whose constraint row is all zeros on the cloned pool. The dense solve tolerates such a row as a miss; a size selection cannot carry it, and the row index alone is not actionable. refit_uk_dataset_size now lists every nonzero target with no supporting household by name before initialisation and refuses with the list, so the binding defect is fixed upstream or the row is excluded with a signed reason, never selected around. unsupported_nonzero_targets() is the reusable check. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…macOS's /usr/bin/time -l (#355) The evaluation command timed each downstream script with `/usr/bin/time -l`, a BSD flag GNU time rejects with exit 125, so on the linux CI runners a failing stub could not surface its own exit code (test_downstream_continues_after_a_failing_stub: 125 != 7). The timed form now runs the script in a child interpreter through a shim that executes it in-process and reports the child's own peak resident set (bytes on every platform) on stderr at exit; wall time is measured by the caller and the exit code is the script's own. The marker line is stripped from the recorded stderr tail. Same receipt shape on macOS and linux. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s above £27,600 (#355, ruling 2026-09-08) Under #879's relationship-based uc_calibration_family_type no benefit unit in the spine is a couple without children with an annual UC award in the 27,600-28,800 or 28,800-30,000 band: both rows sit at -100% on #879's corrected comparison and have no carrier on the K=15 rowwise pool of spine-p, where the #355 size selection refuses them by name. The dense seam tolerated them as capped misses. Signed into the reviewed measure exclusion register on the zero-support-channel precedent (approved by juaristi22, 2026-09-08, expiring 2026-12-08; catalogue and top-band repair tracked in microcosm#736; the sibling 26,400-27,600 band was already excluded). Register census pins move with it: 18 payment-band exclusions, 82 active payment bands. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…aunch (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… smoke4 at pi_hi 0.7 (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t binding defect (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… never write one (#355) score_uk_local_candidate needs the frozen compiled register R14 built separately; --scoring-registry names it, with <run>/ and each reference's scoring_registry_compiled.json as fallbacks, and the skip reason says so. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…t; re-pin the identities it moves (#355, ruling 2026-09-08) The exact-count draw can only draw from the gates' open-probability mass, but the L0 budget search stopped on the count of not-fully-closed weights, which sat 10-13% above that mass in every licensed measurement; the draw then refused, and the "feasible count" moved with every request. calibrate() gains budget_basis ("nonzero_count", the historical default, or "open_probability_mass": each probe is measured by sum(pi), the gates' expected open count) and records it in options; the size refit uses the mass basis and records selection_budget_basis, and the feasibility measurement names its basis. On a 60-record toy problem the mass basis lands sum(pi) 20.2 for a budget of 20 where the count basis gives count 19 with mass 18.5. solve.py is attested, so the identities move again: the am/be/uk country-bundle digests, the loader golden vector, the seed-protocol and seed-map digests with the regenerated US coverage report, the H1 calibrate parity fixture (regenerated on the authoring platform; direct bytes unchanged), and the US spec digest pinned in the multispine pool-tool test. 245 tests across the pin and parity files pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…onthly rent x A17-uprated private-renter households (#355, ruling 2026-09-08) ons.rent.private_rent (314 local-authority rows, ONS PIPR, active since #874's re-pin) bound a mean monthly rent to rent/private_rent, a weighted annual total, so every row sat at a relative error of 1e5-1e6 and at the loss cap on the rowwise pool. The calibration is linear in the weights, so the mean's linear form is a total: uk_private_rent_mean_to_total, applied in uk_local_target_surface after the A15/A17 uprating, composes each row's value as 12 x mean x the same authority's bound tenure/private_rent count, keeps the mean and the count in the row's metadata, refuses by area when the count is missing or non-positive, and records every cell under cross_grain.private_rent_mean_to_total. The metric is unchanged. The census rationale for the PIPR source no longer claims the feed carries only 2026-06 (it carries the 2025 months the reference averages); the committed census artifact is regenerated. Implemented by Codex from .codex-work/PLAN-rent.md; verified here: ruff clean, 137 tests across the ledger-target, local rowwise, rowwise candidate and census files. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… on 2026-09-08 (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…un, the S2 launch (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e ±5% band diagnosis, options (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… checkpoint the solve before the draw (#355) S2 (55,000 at pi_hi 0.95, 2,000 epochs) was refused at the exact-count draw after 4.8 hours: the mass-basis budget search stopped inside its +/-5% band 166 rows under the request, the draw's condition is one-sided, and nothing was persisted, so the dense solve was lost with the refusal. Fix A. exact_k_design_feasibility(pi, k, pi_hi) is the draw's inequality without the draw (verdicts feasible / certainties_exceed_k / boundary_short_of_draw / boundary_mass_short; random polarised designs agree with select_exact_k on every one). calibrate(..., feasible_draw_pi_hi=h) on the mass basis makes the budget search accept a probe only when a draw of target_records at h is feasible on its gate probabilities, steers an infeasible probe like a count miss, prefers feasible probes for the returned run, and records every probe under options["budget_search"]. The UK size selection passes its threshold; the size receipt carries the search receipt and each scan threshold's verdict. Fix C. refit_uk_dataset_size is split into select_uk_dataset_size (the search) and the draw + refit, which accepts an existing selection. uk_runtime/size_checkpoint.py persists the dense solve and the selection with the identity of the pool, the target surface and the solve settings; load rebuilds both through the new calibrate.rebuild_calibration_result on the resumed run's compiled pool and refuses by name on identity, pool or surface drift. The doctrine solve and the candidate driver write the checkpoint into --out by default on size runs (--no-size-checkpoint) and --resume-size-checkpoint DIR continues at the draw, at any threshold, with both thresholds and Logbook phases recorded. Attested calibrate modules moved: country-bundle digests, seed protocol and map, loader golden vector, US spec digest (multispine pool-tool test), the regenerated coverage report and the H1 calibrate parity fixture. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…to the pre-registered table; P95b launched on the fixed code (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…et probes with their drawability verdict, the search stop (#355) A size run was silent between "solving ... under the doctrine..." and its manifest, hours later. The budget search now emits one budget_probe event per finished probe (penalty, measure, certainties, boundary draw and mass, verdict) and a budget_search_done event beside the per-epoch stream, on the calibrator's existing progress_callback seam. The UK doctrine solve takes a progress line sink (uk_runtime/solve_progress.py formats timestamped lines: a loss every hundred epochs and at the last epoch of the dense solve, of each probe and of the refit; one line per probe; one when the search stops), the size search and refit are tagged by phase, and the candidate driver writes the lines to stderr so they land in the run log. solve.py is attested: the country-bundle digests, seed protocol and map, loader golden vector, US spec digest, coverage report and H1 calibrate parity fixture are re-cut. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…selection comparison (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ted and downstream findings, the mass-loss mechanism (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…est-iterate oracle's gates attestation for the rebased tree (#355) Rebased onto main after #881 and #883. The country-bundle digests, the seed protocol and map, the loader golden vector, the US spec digest in the multispine pool-tool test, the regenerated coverage report and the H1 calibrate parity fixture are re-cut on the combined tree. Main's new pre-best-iterate oracle attests the gates module's bytes; #355's gates changes (per-record initial probabilities and the protected mask) move that digest legitimately, so the attestation is re-pinned and the oracle's byte-identity checks on the excluded paths still pass. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…nsequence for later size runs (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… receipts: one-engine scorecard, incumbent-score finding, exclusion audit (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…chine (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…6 replays against the enhanced FRS (#355) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…oint guard, attested and frozen gates, honest draw and stretch keys (#355) 1. The size-checkpoint identity carries the solve doctrine and the doctrine solve asserts the restored max_weight_ratio, mass and target_loss_cap against today's doctrine after a resume; the writing run's code pin and build id ride in the checkpoint's provenance and are reported, not compared. 2. An --out that already holds a size checkpoint is refused before the solve. 3. microcosm.calibrate.gates and microcosm.calibrate.initialization join the seed-protocol implementation digest, and the pre-best-iterate oracle runs with a frozen copy of the gate module loaded as pre_best_iterate_gates, so a gate-behaviour change surfaces as a numeric mismatch on the gated control path instead of being absorbed on both sides. 4. The size receipt reports certainty_share, boundary_draws and zero_target_rows; the manifest distinguishes the realized stretch against the refit's reference from the stretch against the pool design weights. 5. The written-checkpoint receipt carries no timestamp and no absolute path. Rebased over #891. The attestation change moved the seed protocol, the pointer inventory, the field and mode counts and the resolved_seed_protocol claim, the country-bundle digests, the loader golden vector and the US spec digest; all re-cut, the coverage report regenerated. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2c1db98 to
c2ee134
Compare
…tialization (#355) Attesting microcosm.calibrate.gates and microcosm.calibrate.initialization in seeds.py added two resolved-binding fields (9,770 -> 9,772; ledger 42,154 -> 42,156; compiler_semantic 27,715 -> 27,717; no_generation0_effect 3,678 -> 3,680). field_usage.py and the coverage tool test were re-pinned in c2ee134; this sibling test only runs in the rest, engine-shared and wheels lanes and was missed. Values recomputed from the ledger, not transcribed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
Response at Thank you for the A/B run on the default paths; that is the check I could not do from inside the PR. Everything below is on the branch, rebased over #891, with every identity re-cut on the combined tree. 1. Doctrine drift on resume — fixed, two locks. The checkpoint identity now carries the solve doctrine ( 2. Stale checkpoint refused after the solve — fixed. The driver now refuses an 3. 4. How deterministic the draw was — now stated in the receipt. The size receipt carries 5. Zero-valued targets — counted. 6. The two register changes. Both are now their own paragraph in the PR body, with the effect on comparability with R17 stated; splitting them would leave this branch unable to run (the composed rent rows are what makes the 314 PIPR cells bindable and the two UC bands are what the size path refuses by name), so they stay, flagged. Nits. The checkpoint receipt that rides into the candidate manifest no longer carries Measured since your pass (receipts |
vahid-ahmadi
left a comment
There was a problem hiding this comment.
Second pass at 1bdd6447 (Claude Code, high effort; worktree checkout; the six commits since the reviewed head read against the dispositions — four more than the two the reply names; the round-one battery: 901 passed, 3 skipped, 0 failed; on the old head exactly the three new tests fail; ruff check clean; CI run 34405953724 green on all 23 jobs).
1. Verified, two locks. _size_checkpoint_identity now carries "doctrine": _doctrine_bounds() (loss cap, stretch, scale rule, weight rule, epochs, clone count; build_uk_rowwise_candidate.py:555) and the load compares it by key; independently local_rowwise.py:1218-1239 asserts the restored max_weight_ratio, mass and target_loss_cap against today's doctrine. code_pin and build_id ride in provenance and are reported, not compared. Both tests fail on the old head (KeyError: 'doctrine') and pass here.
2. Verified. _refuse_stale_size_checkpoint runs right after the output-path validation and before any ladder load or solve, names the files and the --resume-size-checkpoint way out; the test asserts no manifest is written. Fails on the old head.
3. Verified, with one thing to say plainly. gates.py and initialization.py join _DIRECT_KERNEL_MODULES (seeds.py:349-350), so the attested identity now moves with them. The oracle imports a frozen gate module (gates_14608a5e.py), the control asserts the oracle's HardConcrete is the frozen class and not the live one, and the mechanism works: I mutated the live clamp from 1.0 to 0.999 and all three excluded-path controls failed on weight bytes. One observation: the frozen copy is byte-identical to this PR's gates.py (14608a5e…), not main's (379e4adb…), so the control cannot adjudicate this PR's own gate change — the evidence for that is that the control's numeric values did not move when only the module sha did. Fine going forward; worth one sentence in the receipt.
4. Implemented; the design-ratio numbers are only in the comment. certainty_share, boundary_draws (dataset_size.py:348-349) and both realized_max_weight_ratio_* keys (driver :2496-2513) exist, and the receipts carry the certainty counts (54,595 / 405 and 54,844 / 156) and the >100× design shares. The vs_design values themselves (1,383 and 1,679) and the 10.0 stretch-reference ratio appear nowhere in the tree — the receipts md names the keys at lines 724-725 but not the values, and no manifest with the new keys is committed. Write them into the receipt.
5. Verified. zero_target_rows is counted and the receipt records 0 on the licensed surface, consistent with the zero-valued parity rows being deferred cells.
6. Partial — the disposition says more than the body does. The two register changes are a bullet in the changes list, not a paragraph, and the body contains no comparability statement against R17 (no match for "R17" or "comparab"). The reasoning for keeping them in this PR is sound; the sentence just is not there. Also unnamed in the reply: ad519c26 changes the PIPR census notes from "all 361 remain deferred" to "314 bind, 47 deferred", which is a register-facing edit that deserves a mention.
Nits. written_at and the directory are out of the candidate manifest and stay in the checkpoint's own JSON; the options keys are additive. The parity pin replaces the darwin py3.13 entry with py3.14 rather than keeping both, and there are no linux entries in that file, so "the linux entries are untouched" is vacuous. test_spec_engine_field_usage.py, touched in 1bdd6447, would be reformatted by ruff format; CI does not enforce it, but "changed-file formatting passes" is not true of the head.
Approving: the three should-fixes are closed with discriminating tests and a working frozen control. The residuals are all text — the two design-ratio numbers into the receipt, the R17 sentence into the body, one line on the frozen gates being the post-PR module.
The UK rowwise driver currently exports every cloned household. This adds
--dataset-householdsto request a compact candidate after the dense solve, using contribution-informed L0, exact-count sampling, and a frozen-support refit, plus the machinery a licensed 55,000-household run turned out to need and the evaluation that measures such a candidate.Based on
main(after #883). Refs #355 and #665; this does not close #355's certification and default-switch requirements.Behavior
--epochsis free outside--release-candidate.calibrate(..., budget_basis="open_probability_mass", feasible_draw_pi_hi=h);exact_k_design_feasibilityis the draw's own inequality). Every probe and the stop reason ride the size receipt.--selection-pi-hi(default 1.0; candidate-only) and refit from the normalized Horvitz–Thompson baseline with the stretch multiplier 10 on that inclusion-adjusted reference; the manifest records the reference. A refused draw carries the measured gate mass and the feasible alternatives.size_selection_checkpoint.{npz,json}in--out;--no-size-checkpointopts out);--resume-size-checkpoint DIRre-derives and verifies the pool and target surface, rebuilds both results throughrebuild_calibration_result, and continues at the draw, at any threshold.--selection-seedre-draws on one pool and one dense reference.dense_reference_diagnostics.csv, a summary undersolve.dataset_size.dense_reference) and the selection itself (dataset_size_selection.csv).tools/evaluate_uk_dataset_size.py(libraryuk_runtime/size_evaluation.py): run acceptance, size-only deltas against the run's dense reference, comparison with a reference run, incumbent surface re-resolution with the frozen-versus-recomputed check, downstream T3/T4/T5 and the UK scorecard: populace_uk_2023 vs enhanced_frs_2024_25 vs admin benchmarks (2026) #731 scorecard, a summary with the pre-registered outcomes, every step with a receipt.Measured
Two licensed 55,000-household candidates from the K=15 pool on spine-p and feed 6fb700e (thresholds 0.5 and 0.95, 2,000 epochs) and the refusal that preceded them are in
experiments/355-uk-dataset-size-receipts.md, with the evaluation trees under each run; the summary is in the PR comment below.Review boundary
These are candidate artifacts. Size requests refuse
--release-candidateand remain unreleasable until matched comparisons and the promotion scorecard are adjudicated. No dataset registry, production pointer or downstream default changes. Full builds still require the dense build's peak memory and add selection/refit work; savings apply to the exported dataset and downstream use. The operating instructions are indocs/uk-dataset-size-plan-355.md.Validation