dontopaper

Cycle contradictions: the conflicts pairwise edges cannot see

donto papers · original research · 2026-06-13 · theory + census, working draft v1

Abstract. Contradiction in a knowledge base is almost always modeled as a binary relation: claim A rebuts claim B, stored as one edge. donto stores exactly this — donto_argument holds 2,525 such edges, 2,282 of them rebuts (2,150 concentrated in ctx:epistemic-sweep/contradictions). But many of the contested-knowledge errors that matter in our corpus are not two claims that explicitly negate. They are cycles of individually-defensible claims whose composition around a loop is impossible — a person recorded as both the daughter of and the spouse of the same generational position, where no single claim is wrong and no single pair contradicts, yet the loop cannot close. A pairwise edge model is structurally blind to these: there is no privileged source→target pair to attach a rebuts edge to, so none is ever written, so the conflict is invisible to every consumer that reads donto_argument. We make the claim precise, prove why the blindness is structural (a product of positive scalar maps around any loop is a positive scalar — a d=1 scalar restriction map cannot carry a non-trivial 1-cocycle, ever), and show that cellular-sheaf cohomology with d≥2 sign-carrying maps detects and localizes the loop as a non-zero holonomy ‖H_cyc − I‖_F. The detector math is built and unit-tested (packages/donto-sheaf, Case-A/Case-B fixtures green, no DB). What is not done — and is the honest center of this paper — is the census: how many real cycle-contradictions live in the genealogy corpus that no pairwise method flags. We give the worked Kitty example from live ex:kitty rows, the exact census procedure, the lift metric that makes a result honest, and a negative we already expect (most of the live conflict frontier is single-(subject,predicate) polarity clashes that pairwise methods do catch — the cohomological upgrade pays off precisely on the long tail it adds, and the paper's job is to measure how long that tail is).


1. The shape of the error pairwise edges miss

A pairwise contradiction edge encodes "these two claims cannot both hold." It is the right tool for a polarity clash: bornAt Coen vs bornAt McIvor, same subject, same predicate, two incompatible objects. donto already detects these — donto_paraconsistency_density materializes 235,032 (subject, predicate) rows with distinct_polarities ≥ 2, and the rebuts edges in donto_argument are the explicit pairwise record of that family.

But consider three claims, each individually attested and individually fine (all are live ex:kitty rows):

# claim predicate object
A Kitty is the mother of Caroline isMotherOf ex:caroline-rose-davis
B Kitty is the daughter of the Duke of York daughterOf ex:duke-of-york
C Kitty is the 1907 wife of Mick is1907WifeOf ex:mick

No two of these contradict. There is no (subject, predicate) polarity clash — each predicate is distinct. There is no pair to which a rebuts edge attaches. Yet add the generational and kinship constraints the predicates carry — a daughter is one generation below her father; a mother is one above her child; a spouse is the same generation — plus a loop-closing chord from a second source (Caroline's father is the same Mick that Kitty married, or the Duke-of-York father line and another attested father line resolve to one person), and the loop closes into an impossibility: Kitty would sit in two incompatible generational positions at once. This is the real disambiguation problem behind the live ex:kitty junk-drawer URI, which holds — simultaneously, all as live upper(tx_time) IS NULL rows — isMotherOf ex:caroline-rose-davis (×7), is1907WifeOf ex:mick (×2), daughterOf ex:duke-of-york, and two distinct fathers, hasFather ex:bobbie and hasFather ex:buiku-buiku: a single symbol that cannot be one person.

The error is a cycle, not an edge. It lives in the composition of typed relations around a loop, not in any pair. That is the conflict class this paper is about.

The claim. A material share of high-value contested-knowledge errors in a contradiction-preserving store are cycle-inconsistencies of individually-fine claims, not pairwise negations. Pairwise donto_argument cannot represent them (a cycle has no privileged source→target pair); the sheaf 1-cocycle ( around the loop) detects and localizes them. The value of the upgrade is exactly the count of such loops a pairwise method misses — the census this paper specifies and has not yet run.


2. Why the blindness is structural, not an implementation gap

It is tempting to think a smarter pairwise pass — transitive closure over rebuts, or a rule deriving an edge from daughterOf + spouse — would catch the loop. It would not, for two distinct reasons.

2.1 There is no edge to write. donto_argument is binary by constraint: CHECK (source_statement_id <> target_statement_id), open-uniqueness on (source, target, relation, context). A cycle conflict over {A, B, C} has no privileged ordered pair — picking any one (say A→B) is arbitrary and lossy: it asserts "A rebuts B," which is false (A and B are individually compatible; only the loop is bad). A faithful pairwise encoding therefore does not exist. The N-ary conflict's only honest home is a cluster record — exactly the donto_sheaf_cocycle + donto_sheaf_cocycle_member tables in migration 0179, with an optional, off-by-default, explicitly-lossy cycle_inconsistent star shadow (migration 0180) for consumers that can only read pairwise. That shadow is intentionally invisible: every live pressure consumer filters relation IN ('rebuts','undercuts'), so cycle_inconsistent never leaks into a binary-shaped reader.

2.2 The one hard correctness fact: d=1 maps cannot carry a cocycle. Even if you tried to detect the loop by propagating a value around it (a transport/holonomy view), a scalar model is provably blind. Model each typed relation as a restriction map between the two claims' stalks. If the stalks are one-dimensional (d=1) and the maps are positive scalars σ_e > 0, the holonomy around any cycle is

H_cyc = σ_{e_k} · … · σ_{e_2} · σ_{e_1}   ∈  ℝ_{>0}

— a product of positive scalars is a positive scalar, conjugate to the identity in the scaling group: there is no non-trivial 1-cocycle, ever, regardless of the loop. A d=1 detector reports H¹ = 0 on the Kitty loop. This is not a tuning failure; it is the algebra. To make a loop's holonomy able to be non-identity you need (i) d ≥ 2 stalks so the maps live in a non-abelian group, and (ii) sign- or orientation-carrying maps, so a disjointness relation (daughterOf ⊥ spouseOf) contributes a reflection/sign-flip that does not cancel around the loop.

This is why donto's Stage-0 sheaf math (packages/donto-sheaf/src/lib.rs) ships RestrictionMap::identity(d, w) as the default d≥2 path and RestrictionMap::scalar_fallback(w) as a never-flagged d=1 fallback whose doc comment states the reason verbatim: "By construction its loop holonomy is a positive scalar ⇒ never a cocycle." The crate's Case-B test asserts both directions on the same loop — the signed d=2 path gives residual_norm > 1e-3, the d=1 scalar path gives obstruction 0. A Stage-0 that shipped d=1 as primary would not recover the very Kitty cycle it claims as its headline. The blind spot is in the representation, and only a d≥2 sign-carrying representation removes it.


3. The detector, concretely

The mechanism (specified in the sheaf build spec, Stage-0; implemented in packages/donto-sheaf):

  1. Scope a bounded subgraph (≤ ~500 statement-nodes) around a contested entity or the high-conflict frontier. Never the global graph (donto_statement ≈ 42,018,816 rows — sheaf Laplacians are heavier than graph Laplacians; the global sheaf is an open problem, not attempted here).
  2. Assign d=2 value-indexed stalks: distinct attested object values index orthogonal basis axes (the report's Coen=(1,0), McIvor=(0,1) construction), polarity-signed.
  3. Build restriction maps from learned signals onlydonto_predicate_closure.confidence, donto_argument.strength, donto_identity_edge.confidence. The relation value only caps magnitude and assigns the orientation sign (a disjointness/inverse relation contributes the flip). No hand-maintained predicate→weight table, no synonym list, no if/elif over predicate names — that would be exactly the brittle logic the canon forbids.
  4. Spanning-forest cycle basis. Each non-tree edge closes one fundamental cycle; there are |E| − |V| + #components of them — a minimal independent generating set of . We never enumerate all simple cycles (exponential). For each, compose the signed maps around the loop and measure ‖H_cyc − I‖_F (holonomy_frobenius in the crate). Non-zero ⇒ a localized 1-cocycle; the member set is the loop's statements — the localization the pairwise layer cannot give.
  5. Filter before flagging: stalk_dim ≥ 2 (never flag the d=1 fallback), obstruction above an empirical floor (a fixed cold-start until enough prior runs calibrate it), a max_cycle_len cap, and — critically for the census — skip any loop already covered by a single pairwise rebuts/undercuts edge among its members, because that conflict is already visible to the pairwise layer. The sheaf's contribution is exactly the loops that survive this filter.

That last filter is the empirical question of this paper made operational: a cycle-contradiction "counts" toward the cohomological upgrade only if no pairwise edge already fires inside it.


4. The census: the to-be-done part (stated honestly)

The detector math exists; the census does not. The Stage-0 migrations are written and committed — 0178_sheaf_pressure.sql, 0179_sheaf_cocycle.sql, 0180_sheaf_argument_relation.sql, 0181_standing_sheaf_pressure.sql, all under packages/sql/migrations/ — but not yet applied to live donto-pg: SELECT tablename FROM pg_tables WHERE tablename LIKE 'donto_sheaf%' returns zero rows today, and the analyzer driver (donto analyze sheaf-h1, analyzer_sheaf) is still in build. So everything in this section is a specified experiment, not a result. We refuse to report a census number we have not measured (cf. the answer-shaping note on measuring the plumbing before the hypothesis).

4.1 The procedure

  1. Apply migrations 0178–0181 — the pressure table, the cocycle cluster + member tables (with the donto_assert_sheaf_cocycle function), the optional cycle_inconsistent relation, and the dark-by-construction donto_standing re-point (sheaf-first contradiction pressure with the live paraconsistency value as COALESCE fallback, so it is inert while the sheaf table is empty).
  2. Run donto analyze sheaf-h1 over a battery of scopes: each contested-entity neighbourhood in the genealogy corpus (Kitty, Caroline, the EKY apical set), plus the HighConflictFrontier seed.
  3. For every flagged cocycle, record (member statement_ids, residual_norm, member_count) and the boolean pairwise_visible = "does any rebuts/undercuts/supersedes edge in donto_argument connect two members?"
  4. The census number is |{ cocycles : pairwise_visible = false }| — cycle-contradictions that no pairwise method flags — with the residual-norm distribution and the per-entity breakdown.

4.2 What a result would establish — and the metric that makes it honest

The headline metric is the cohomological lift ratio:

lift = (# cycle-conflicts with pairwise_visible = false)
       ─────────────────────────────────────────────────
       (# pairwise contradiction edges, donto_argument rebuts/undercuts)

A lift materially above 0 quantifies the upgrade: that fraction of real conflict is only visible cohomologically. A lift ≈ 0 would be an honest negative — the corpus's contestation is overwhelmingly pairwise-shaped and the sheaf buys little on this corpus (while remaining the only correct representation for whatever loops do exist). Either way the number is the contribution.

4.3 The negative we already expect

We will not pretend the census will be flattering everywhere. The live high-conflict frontier is dominated by single-(subject,predicate) polarity clashes — the 235,032 donto_paraconsistency_density rows with distinct_polarities ≥ 2 are pairwise-shaped by construction, and the skip-if-pairwise-rebutted filter will correctly discard them. So the census's real yield should be the genealogy junk-drawer entities — the ex:kitty-class symbols that have accreted dozens of incompatible kinship roles (isMotherOf ×7, is1907WifeOf ×2, daughterOf, two distinct hasFather) and carry no rebuts edge anywhere. The honest prediction: cycle-conflicts will be rare relative to polarity clashes, but concentrated exactly where pairwise methods are blind and disambiguation matters most — the contested-identity entities the genealogy consumer exists to resolve. Measuring that concentration, not maximizing a count, is the point.

4.4 A second honest risk

There is a real chance the diagonal d=2 maps do not fire on the live corpus even though the fixture passes, if the daughter-of⊥spouse-of disjointness is fundamentally off-diagonal (a permutation / O(d) structure the diagonal family cannot express). The crate's Case-B fixture proves the math on a constructed loop; the real-corpus run is the true gate, and if diagonal fails we promote orthogonal/connection maps before claiming recovery. We do not ship the claim on the fixture alone.


5. Worked example: the Kitty loop, end to end

Using live ex:kitty rows:

  • A = ex:kitty isMotherOf ex:caroline-rose-davis — implies Kitty is generation g, Caroline g+1.
  • B = ex:kitty daughterOf ex:duke-of-york — implies Kitty is g, her father g−1.
  • C = ex:kitty is1907WifeOf ex:mick — implies Kitty same generation as Mick.
  • Closing chord (supplied by a second source or an identity hypothesis): ex:caroline-rose-davis hasFather ex:mick, placing Mick simultaneously at g (Kitty's spouse) and at Caroline's-father position — which, folded against the daughter/mother chain, forces Kitty into two incompatible generational slots at once.

Pairwise view: zero rebuts edges among {A, B, C, chord}. Each is individually attested and individually consistent. donto_argument is silent. donto_paraconsistency_density shows no (subject,predicate) clash because every predicate differs. The error is invisible.

Sheaf view: with d=2 stalks (generation axes) and signed restriction maps (the spouse/daughter/mother relations carry the generational offset; the disjointness daughterOf ⊥ spouseOf carries the sign flip), the composed holonomy around A→B→C→chord→A is not the identity: ‖H_cyc − I‖_F > floor. The detector returns one Cocycle whose member set localizes the conflict to exactly {A, B, C, chord}, and donto_assert_sheaf_cocycle records it as an N-ary cluster — never a fake pairwise edge. This is the crate's Case-B fixture; running it on these real rows is the corpus gate of §4.4, not yet done.

The payoff is operational: the genealogy researcher gets "these four claims cannot all describe one person — here are the four" automatically, where today that loop is hand-detected (the live notes already flag ex:kitty as a junk-drawer URI that may split into two people). The sheaf turns hand-detection into a localizable computation.


6. Why only donto can run this census

The census needs three things at once — donto's three foundational invariants:

census requirement donto provides it as
a pairwise contradiction layer to be compared against (and shown blind) donto_argument — 2,525 edges, 2,282 rebuts; the live baseline
a dense claim graph with typed relations to find real loops in ~42M donto_statement rows, freely-minted kinship predicates, contested-entity neighbourhoods (ex:kitty et al.)
held contradictions, never resolved — so the loop's members all coexist on disk invariant I3 (no destructive overwrite): A, B, C, and the chord are all live upper(tx_time) IS NULL rows simultaneously

A collapse-on-conflict KB cannot run this census at all: it would have deduped or winner-picked the incompatible kinship roles at ingest, deleting the very loop the census counts. donto holds all of them — ex:kitty carries seven isMotherOf and two is1907WifeOf rows at once — which is precisely what makes the cycle detectable later. The census is a measurement only a paraconsistent, non-deleting, abundance-native store can produce.

And the comparison is fair and adversarial: donto runs the pairwise detector and the cohomological detector over the same scoped subgraph, and reports the loops the pairwise one missed. It is donto demonstrating its own blind spot and then closing it — the honest way to quantify an upgrade.


7. Status: proven / conjectured / speculative

  • Proven (built + tested, no DB). The d=1-cannot-carry-a-cocycle correctness fact (§2.2) and its consequence that d≥2 sign-carrying maps are mandatory; the holonomy detector and fundamental-cycle localization (packages/donto-sheaf, holonomy_frobenius + analyze); the Case-A ( norm √2) and Case-B (Kitty loop residual_norm > 1e-3, localized; d=1 scalar path → 0) fixtures pass as pure unit tests independent of Postgres. The structural argument that a cycle conflict has no faithful pairwise encoding (§2.1) follows from the donto_argument binary constraint. The cluster tables and assert function exist as committed migrations 0178–0181 (written, not yet applied to live).
  • Conjectured (open, failure mode named). That cycle-contradictions are a material fraction of real contested-knowledge error in the genealogy corpus. Failure mode: the census returns lift ≈ 0 because contestation is overwhelmingly single-(subject,predicate) polarity clashes that pairwise methods already catch (§4.3) — an honest negative we'd report as "the sheaf is the correct representation but the corpus rarely needs it." Resolving the conjecture requires the deployed run; we will not assert a census number before measuring it.
  • Speculative (flagged). That diagonal d=2 maps suffice on the live corpus (§4.4); the disjointness structure may demand orthogonal maps — fixture-pass does not imply corpus-pass. Also speculative: that the per-entity cocycle count is itself a useful disambiguation signal (an entity whose neighbourhood carries many independent cocycles is a candidate to split into multiple people — the ex:kitty→two-people hypothesis as a query, not a hand-judgment). Worth measuring once the census exists; no claim yet.

The detector is Stage-0 of the sheaf program. The census is the paper — and it is the part still to do.


See also: the theory companion The Bitemporal Sheaf (the cohomology, generalized over both time axes); the build spec and literature grounding in sheaf neural networks for donto; the empirical sibling Answer-Shaping on measuring before claiming; Standing dynamics (which consumes the contradiction pressure this detector feeds); the full program in the donto research agenda.