Skip to content

0009: Uniqueness Coexists with Contestation

Date: 2026-06-28

Accepted — implemented. The reload-time uniqueness validator and the dent8 contradict verb both treat an explicitly contested set as a single flagged conflict, not a uniqueness violation.

The coding-agent predicate registry marks facts like repo.database unique: at most one believed fact per subject+predicate (registry). Independently, dent8’s belief-revision identity is paraconsistent: a fact.contradicted moves the incumbent to Contested and preserves both the fact and its contradicted_by edge — “localize the contradiction, keep the store non-trivial, surface it” (ADR 0005, belief-revision.md).

These collide. The sanctioned way to flag a conflict — dent8 contradict — asserts an opposing fact and contests the incumbent, leaving two believed facts (the Contested incumbent and its Active contradictor) for one unique subject+predicate. A naïve uniqueness rule (“at most one believed fact, full stop”) would either forbid contradiction entirely or reject a legitimately-contested log on reload (the same false-positive class as the ADR 0008 SupersededByInvalidated regression).

Uniqueness is over mutually-consistent believed facts, and contestation is the explicit exception. Concretely:

  • A unique predicate is violated only when more than one fresh believed fact exists and none of them is Contested — i.e. a silent duplication, the corruption the invariant exists to catch.
  • When at least one believed fact is Contested, the set is a surfaced conflict, not a violation. The firewall has done its job (the disagreement is visible and auditable); resolving it is a separate, deliberate act (supersede installs a winner; retract removes one side).
  • Contradiction is dissent, so it is not authority-gated (a low-authority source may contest a high-authority fact), with the one exception that a contradiction against a Canonical fact is a hard alarm, not a soft contest (ADR 0007). This is the deliberate asymmetry: dissent (contradict) is cheap; override (supersede) and removal (retract) must out-rank the incumbent.

Positive:

  • dent8 contradict is runnable without weakening uniqueness: a low-privilege actor can flag a wrong fact (forcing it Contested) but still cannot override or delete it — completing the assert / supersede / retract / contradict surface.
  • The reload validator stays sound: silent duplication is still rejected; a flagged contestation reloads cleanly.

Negative:

  • “At least one Contested” is a coarse exemption: it permits a believed set larger than two if multiple contradictors pile on. That is acceptable (every member is an audited part of the surfaced conflict) but means uniqueness no longer implies “≤2 believed”.
  • A plain assert into a contested predicate is still blocked by registry uniqueness (the believed set is non-empty); the user must resolve the contest (supersede/retract) first. This is intended — you do not silently add a third opinion.
  • [DONE] dent8 contradict (asserts the opposing fact + a Contradicted event on the incumbent, atomically; a Canonical incumbent hard-alarms).
  • [DONE] validate_unique_log exempts a set containing a Contested fact.
  • Future: a dent8 resolve shortcut (supersede that also clears the contest), and surfacing the full contradictor list in explain rather than just a count.
  • Grounded in ADR 0005 (paraconsistent contested state) and ADR 0007 (dissent is not authority-gated; canonical is the exception).