Dispute & revision policy — sign or strike, line by line
This is the last thing blocking the Ion Aurora plan. Everything else in both tracks is built. B6b is the one item the plan says not to start:
B6b — Dispute & revision. Do not start until the policy is signed — the ten rules are the schema.
That sentence is why this file exists rather than a migration. Each rule below becomes a database constraint, and a constraint is expensive to reverse once reports have been issued under it. So: strike, amend, or sign each line. Reply in this PR, or just tell me the numbers you want changed.
The rules are the design's own defaults, quoted verbatim from Ion Aurora Dispute.dc.html. The design states plainly that it cannot decide them — "Design cannot decide them, but it can put a defensible default on the table."
Three of them are already load-bearing elsewhere in the plan, marked ⚠ below.
The ten rules, and what each one becomes
01 · Queries are free and unlimited
Charging to question a valuation converts a quality process into a revenue one, and the incentive rots immediately.
Becomes: nothing. No fee column on valuation_queries, deliberately — absence is the enforcement. If struck: a fee model, and a decision about who is billed (owner? bank?).
02 · 5 working days, written, always
Same SLA as a fresh valuation. Every query gets a written answer even when the report stands — the answer is the product.
Becomes: an SLA clock of kind response (B2b already separates response from sla, so "you have 2 hours" and "the file breaches Thursday" are never confused). Working days come from public_holidays, which exists. The number to sign: 5.If struck: name the number. The mechanism is unaffected.
03 · Answered by someone who didn't sign ⚠
Internal, but independent of the original signature.
Becomes: a trigger — reviewer_user_id <> signer_user_id, refused at write time rather than hidden in the UI. If struck: the trigger comes out and self-review becomes possible. This is the rule I would push back hardest on: the design calls self-review "the fastest way to make a dispute process worthless."Also settles Q-14 — the design resolves arbitration internally at this tier, treating external arbitration as a contractual escalation rather than a product feature.
04 · Evidence only — never sentiment ⚠
"I believe it's worth more" has no form field, because giving it one would make pressure a valid input.
Becomes: query_basis enum with exactly three values — fact_wrong · comparable_not_comparable · new_evidence. The absence of a fourth is the design. An enum is the right shape here precisely because adding a value later is a deliberate, visible act. If struck: name the fourth basis. Be aware it becomes a permanent, valid input to every future valuation challenge.
05 · 5% materiality threshold ⚠
Above it, a revision is issued; below it, a written note and the report stands. Set at 5% so ordinary measurement noise never forces a re-issue.
Becomes: a system_settings row, not a constant — the plan is explicit that this value "has already moved once." Storing it as a row means changing it later is an update, not a migration. The number to sign: 5%.If struck: name the number. Note the worked example in the design is +10.28%, which clears 5% comfortably — the threshold only bites on smaller corrections.
06 · Revisions recompute, never restate
Correct the fact and run the same arithmetic. No screen anywhere offers a free-text value field.
Becomes: recomputed_value writable only through a SECURITY DEFINER RPC, with direct UPDATE revoked. That is what makes "no screen anywhere offers a free-text value field" structurally true rather than a UI convention someone breaks in six months. If struck: a reviewer can type a value. I would want that in writing.
07 · R0 is superseded, never revoked
Revoked is for withdrawal — fraud, wrong property, a report that should not exist. A corrected report is not a withdrawn one, and conflating them tells banks their files were worthless.
Becomes: revision_state enum = current | superseded. No revoked value, same technique as B3b's disclosure_status, which deliberately lacks dismissed. If struck: add revoked — but then decide separately what a bank holding R0 sees. The design's answer is "authentic · superseded by R1", never "invalid."
08 · Revision resets validity
R1 gets a fresh 90 days from its own issue date — it is a current opinion, not a patch on an old one.
Becomes: valid_until as a generated column, issued_at + 90 days. The number to sign: 90.Note: B2c (#786) already ships valuations_base.valid_until as a plain, underived column specifically because this rule was unsigned. Signing it here is what lets that column become derived.
09 · A corrected fact propagates
If the parcel's area was wrong here, it is wrong in every open file citing it. Hermes flags them; a human confirms each.
Becomes: a flagging query over parcel_identity_id — the shared key B3b already relies on. Flag only; a human confirms each. No automatic cross-file mutation. If struck: corrections stay file-local, and two open files can carry contradictory areas for the same parcel.
10 · The query rate is published internally
A dispute process nobody measures becomes a dispute process nobody runs.
Becomes: a report-dashboard instance (A4b's pattern, already built) showing rate and upheld-share. Context for reading it: the design calls 31% upheld a healthy number — "Near 0% would mean queries are being deflected. Near 100% would mean the first pass is careless."If struck: no dashboard. Cheapest rule to defer; also the one that tells you whether the other nine are working.
What I need back
Minimum to unblock: rules 03, 04, 05, 07, 08. Those five are the DB constraints. The rest are surfaces and can follow.
If you sign all ten as they stand, say so and B6b ships against these defaults.
One thing this file does not decide
Whether the numbers are right for your regulatory exposure. 5% and 5 working days are the design's proposals, not MoCI requirements — I found no decree text fixing either. If Legal has a view, it overrides the design.
