Skip to content

fix: sampled claims yield to every pre-walk rule, and a 202 never reads done after dispatch - #127

Merged
jm-rivera merged 3 commits into
devfrom
fix/sampled-claims-yield-to-defaults
Oct 24, 2026
Merged

jm-rivera merged 3 commits into
devfrom
fix/sampled-claims-yield-to-defaults

Conversation

@jm-rivera

@jm-rivera jm-rivera commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Two faults a review of #123 found after it merged.

A sole value claimed from a recall sample (SlotBindingDraft.sampled) is provisional until the member walk judges it, but every rule that runs before the walk read it as an ordinary bound value. A claim therefore blocked the declared or shape-slot default on its slot; the walk then refuted the claim and the slot ended unbound. Birth rate with only the live-birth series recalled answered total births per capita as definite, where dev before #123 answered medicalStatus=LiveBirth. Each pre-walk span in _settle_bindings, _vet_election and _repair_bindings now runs its rules on without_sampled_claims(...) and puts the claims back with with_sampled_claims only on slots the rules left plain unbound, so a binding any rule writes replaces the claim and is authoritative. That covers declared and shape-slot defaults, shared values, member and partition values, the measure election, slot openers, tie vetting and pins; readers that _unbind_refuted_claims re-runs after a refutation (_served, _settle_served_dataset, record_coverage) keep reading the claim, so recorded prompts do not move. The special case b70236e added to bind_shared_values is reverted, and its IDS debt-service test still passes. When a rule binds the value a claim held, the binding's provenance is the rule's (declared_default and its slot_defaulted note, or measure-elected).

A worker that finished during enqueue left the row done before mark_dispatched returned it, and submit_over_budget put that state in the 202, which read done with no manifest. The 202 now comes from the row OperationStore.create_or_get recorded, which is never done; dispatch_if_due runs for its side effect only. LiveOperationStore.create_or_get also ran its reset UPDATE and final SELECT as separate statements, so under READ COMMITTED a claim and completion landing between them could return a done row; the INSERT and UPDATE now RETURNING the row they write, and a write that matches nothing decides again under the same advisory lock, up to three passes, then raises DatasetsStoreUnavailable. C187's wording now holds without exception.

holds_whole_total in _bind_query_places, _settle_direction and _walk_assignment, and _narrow_to_breakdown, now read claim-free bindings, since none is re-run after a refutation.

Testing: CI and the paired eval passed at 8a555d4. Locally the engine, render, eval, datasets_api, dataset_store, live_refresh and platform suites passed (26,072), with new tests that fail on dev: the live-birth default over a sampled claim, a completion during dispatch for the mint and definition doors, a reset whose UPDATE matches nothing (SQLite fake and live Postgres), and three whole-total judgements under a refuted claim. The live-postgres store tests, ruff, ty check and the corpus check passed.

A sole value claimed from a recall sample is provisional until the
walk judges it, but the rules that run before the walk read it as an
ordinary bound value. A claim blocked the declared or shape-slot
default, the walk then refuted it, and the slot ended unbound: birth
rate with only the live-birth series recalled answered total births.

Each pre-walk span in _settle_bindings, _vet_election and
_repair_bindings now runs its rules on without_sampled_claims and puts
the claims back (with_sampled_claims) only on slots the rules left
plain unbound, so a binding a rule writes replaces the claim and is
authoritative. Readers that _unbind_refuted_claims re-runs after a
refutation keep reading the claim. This replaces the special case
b70236e added to bind_shared_values.
A worker that finished during enqueue left the row done before
mark_dispatched returned it, and submit_over_budget put that state in
the 202, which then read done with no manifest. The 202 now comes from
the row create_or_get recorded, which is never done; dispatch_if_due
runs for its side effect only. A completion during dispatch leaves the
202 pending, and the client's first poll serves the manifest.
…hole totals without sampled claims

LiveOperationStore.create_or_get ran its reset UPDATE and final SELECT
as separate statements, so under READ COMMITTED a claim and completion
landing between them returned a done row. The INSERT and the reset
UPDATE now RETURN the row they write; a write that matches nothing
decides again under the same advisory lock, up to three passes, then
raises DatasetsStoreUnavailable.

holds_whole_total and the breakdown decision read sampled claims as
bound and are not re-run after a refutation. _bind_query_places,
_settle_direction and _walk_assignment now judge a whole total on
without_sampled_claims, and _narrow_to_breakdown runs before the claims
are restored. _settle_bindings assigns its bindings once, after the
restore.
@github-actions github-actions Bot removed the run-eval label Oct 24, 2026
@jm-rivera
jm-rivera merged commit 273a270 into dev Oct 24, 2026
24 checks passed
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.

1 participant