Turnover · money · ADR-0121

Turnover money decisions: a dispatch ask is not a charge, and money is decided by code, not sampled

ADR-0121 Status Accepted Decided verbally by Fede, 2026-07-30 Supersedes ADR-0034 temp-0 clause

Context

The turnover surface deducts money from real tenants' deposits. Two things about how it decides those amounts turned out to be wrong, and they are the same wrong thing at two levels.

A PM saying "call Cardenas for trash removal" was being read as an instruction to charge a tenant. On unit 612 that produced attribution: tenant, chargeable: true, and a damage line for an amount the PM never said. In production, mined pricing would have filled that amount in.

And the thing making that call is not reproducible. ADR-0034 promised the projection was "deterministic (temp 0, pinned model version)" and that the frozen artifact was defensible because it was never a live re-extraction "which would replay differently and is worthless in a dispute." Since #4688 flipped the model to claude-opus-5 — which rejects temperatureno temperature has been sent. #4948 made provenance honest; the policy was left open. Measured: 0 of 3 scenarios reproducible across repeat runs, with attribution/chargeable — the two fields that decide whether a tenant is billed — flipping between runs on identical dictation.

charge_correctness scored 53 across 52 replayed calls, against capture_completeness 97 and vendor_identification 100. The money dimension was the weak seam by a wide margin.

Decision 1 — A dispatch ask mints work, not a charge

A PM naming a vendor is an instruction to dispatch. It is never an instruction to charge.

Two supporting requirements, because a charge decision that cannot be reconciled is not a decision:

Decision 2 — Money is decided by code first, by a model only where code cannot

Fede, 2026-07-30, verbatim: "preferred i think is 1. deterministic 2. strong model to judge when ambiguous 3. panel if the first model cant figure it out."

The model's jurisdiction is the residue, not the input.

Tier 1 — deterministic code decides every confident case. No draw can move these: dispatch intent (Decision 1), quote-validated explicit attribution, PM-stated amounts and WO actuals, deterministic vendor match. Tier-1 rules run per-item, before any consolidation — see the note below on why that is not a detail.

Tier 2 — a strong model (claude-opus-5) judges only what Tier 1 declined, with Tier-1 facts supplied rather than re-inferred. Judging a narrowed question is a much easier task than open extraction.

Tier 3 — a unanimity panel on low-confidence verdicts. Sample 3; require unanimity; any money-field disagreement fails closed to unclear / PM review. Tier 3 is a disagreement detector, not a vote — it catches that the model is unsure, and never picks a winner among its guesses. It panels the judge's discrete fields on a fixed extracted item, never the extraction itself.

The evidence that shaped this

Temperature-0 is gone across the whole Claude 5 generation. claude-sonnet-5 returns the identical 400 ("temperature is deprecated for this model") as claude-opus-5, through the same client path the projection uses. No model swap within the generation restores ADR-0034's contract, so determinism had to be answered structurally rather than by picking a model. (claude-sonnet-4-6 still accepts it and was considered — see Alternatives.)

Majority voting was the original Tier-3 spec and it is refuted. Measured n=9 per scenario: the Cardenas defect appeared in 4/9 raw draws, and at k=3 2 of 3 triplets voted the wrong answer — voting amplified a mode that is only ~56% correct. Money-field flips went 11.7% → 10.5%; ties were 2/57, so "fail closed on ties" was never the safety net. Independent published evidence agrees: extraction errors are correlated across samples, and voting worsened 79% of model×dataset pairs in one benchmark. Self-consistency voting presumes independent errors that extraction does not have. Hence unanimity.

And panelling the raw projection is unimplementable anyway: strict-identity matching found 0 cross-draw keys in 3 of 4 scenarios. Independent draws do not produce comparable item sets, so there is nothing to vote on until the extraction is fixed.

The ladder measures well. The implementation (PR #5002) puts 94.5% of decisions in Tier 1 and moves charge_correctness from 78 → 94 on the replay corpus.

One finding that shaped Tier 1's shape. The interim guard shipped as #4965 downgrades an unpriced vendor-named task to unclear. On 1 of 9 draws it folded the Cardenas item into a consolidated housekeeping subgroup, downgraded the whole subgroup, and erased the PM's legitimate cleaning-deposit charge — money lost in the opposite direction. That is why Tier-1 rules run per-item, pre-consolidation: a dispatch ask suppresses its own line and nothing else. #4965 stays until Decision 1 makes it unreachable.

Consequences

Alternatives considered

  1. Pin claude-sonnet-4-6 (the last temperature-accepting tier) to restore ADR-0034 as written. Not chosen — it is a generation downgrade whose sufficiency rests on an n=4 single-scenario control, and the ladder addresses the defect where it is decidable rather than making the guess repeatable. Recorded because it remains the lever if the ladder underdelivers.
  2. Switch to claude-sonnet-5. Rejected on measurement — same 400 on temperature, drifts more than opus-5, throws on 1/29, leaves 51% more items unclear, and drops pmNamedVendor on 2/6 draws, which is the field #4965's guard is gated on.
  3. Keep #4965's downgrade guard as the answer. Rejected — its own commit body calls it defence in depth, it suppresses a bad draw after the fact rather than removing the case, and it has now been measured erasing a legitimate charge.
  4. Price dispatch asks from mined chargeKnowledge. Rejected — invents a number the PM never stated and attributes it to a tenant.
  5. Majority voting at Tier 3. Refuted by measurement; see above.

Appendix — implementation notes from the turnover audit

Not decisions. These are engineering fixes from the same audit that nobody would decide against; they are recorded here so they are not lost, and the full evidence with file:line is in TURNOVER-AUDIT.md §5 (local). Each wants its own PR.

Source: turnover production-readiness audit + measurement runs, 2026-07-30 · Accepted 2026-07-30 · Record in propflowai#4988 (held for review) · Corpus evidence documents are local only (PII); numbers summarised here. Published 2026-07-30.
PropFlow Docs