Liking cljdoc? Tell your friends :D

vaelii.koinii.adjudication

Koinii adjudication — the DEFAULT policy: leave-open-and-notify, plus the lifecycle that keeps disputes from piling up, plus the two escalations (a named arbiter's ruling, and a counted majority). A thin CLIENT wrapper over the dispute reads (vaelii.koinii.dispute) — it touches no engine internals and changes belief only through ordinary asserts / retracts.

koinii's first answer to a disagreement is NOT to pick a winner. When two agents assert P and ¬P at :default, the KB stays paraconsistent — both coexist, argue reports :contradiction (Priest's LP) — and this layer just records the dispute open, pushes it to whoever is watching, and manages its life. Automatic resolution by source trust is a harder, engine-side policy; do not reach for it here.

Three policies, one default (koinii.md, Adjudication: split by policy), and all three are here:

  • Leave-open-and-notify (the default) — record open, notify, change no belief. Correct for a ground truth people curate.
  • Arbiter escalation — a designated arbiter's ruling is an ordinary :monotonic assertion of the upheld side; its strength defeats the losing :default side, so the clash clears, why explains who ruled, and retracting the ruling reopens the dispute (cascading).
  • Majority vote — the ballots cast on the disputed claim are counted and the side with strictly more is upheld, through that same reversible ruling; a tie upholds nothing, so an evenly-split house stays open.

Trust-resolve — automatic resolution by source trust — is out of scope for this layer: it is engine-side reputation work, and reaching for it here would resolve disagreements by weighing spoofable identities.

The dispute module owns the reads, the state vocabulary, and the dispute id; THIS module owns the policy the dispute module deliberately left out — the clock, the timeout, and the notify sinks. The clock is the engine clock (v/*clock*), so a lifecycle time and its assertion's :created provenance agree.

Additive, like the sibling koinii modules: only the public core API — including sort-by-content for the two content orders it reports (contested-premises, standing-rulings) — plus koinii dispute, identity and types. Nothing in core loads it.

Koinii adjudication — the DEFAULT policy: leave-open-and-notify, plus the
lifecycle that keeps disputes from piling up, plus the two escalations (a named
arbiter's ruling, and a counted majority).  A thin CLIENT
wrapper over the dispute reads (`vaelii.koinii.dispute`) — it touches no
engine internals and changes belief only through ordinary asserts / retracts.

koinii's first answer to a disagreement is NOT to pick a winner.  When two agents
assert P and ¬P at `:default`, the KB stays **paraconsistent** — both coexist, `argue`
reports `:contradiction` (Priest's LP) — and this layer just records the dispute open,
pushes it to whoever is watching, and manages its life.  Automatic resolution by source
trust is a harder, engine-side policy; do not reach for it here.

Three policies, one default (koinii.md, *Adjudication: split by policy*), and all three
are here:

- **Leave-open-and-notify** *(the default)* — record open, notify, change no
  belief.  Correct for a ground truth people curate.
- **Arbiter escalation** — a designated arbiter's ruling is an
  ordinary `:monotonic` assertion of the upheld side; its strength defeats the losing
  `:default` side, so the clash clears, `why` explains who ruled, and retracting the
  ruling reopens the dispute (cascading).
- **Majority vote** — the ballots cast on the disputed claim are counted and the side
  with strictly more is upheld, through that same reversible ruling; a tie upholds
  nothing, so an evenly-split house stays open.

**Trust-resolve** — automatic resolution by source trust — is out of scope for this
layer: it is engine-side reputation work, and reaching for it here would resolve
disagreements by weighing spoofable identities.

The dispute module owns the reads, the state vocabulary, and the dispute id; THIS module owns the policy
the dispute module deliberately left out — the **clock**, the **timeout**, and the **notify sinks**.  The
clock is the engine clock (`v/*clock*`), so a lifecycle time and its assertion's
`:created` provenance agree.

Additive, like the sibling koinii modules: only the public core API — including
`sort-by-content` for the two content orders it reports (`contested-premises`,
`standing-rulings`) — plus koinii `dispute`, `identity` and `types`.  Nothing in core loads it.
raw docstring

*notify-sink*clj

Where a newly-opened dispute is pushed: (fn [dispute-entry] …), called once per dispute as it transitions open -> notified. This is the extension point the channel's feed subscribers and a configured human sink wire into; nil ships no push (the lifecycle mark is still recorded, so nothing is lost — a later notify-disputes with a sink still finds it un-pushed only if the mark was cleared). Idempotency does not live here — it lives in the stored mark — so a sink need not dedupe.

Where a newly-opened dispute is pushed: `(fn [dispute-entry] …)`, called once per
dispute as it transitions `open -> notified`.  This is the extension point the channel's feed
subscribers and a configured human sink wire into; nil ships no push (the
lifecycle mark is still recorded, so nothing is lost — a later `notify-disputes` with a
sink still finds it un-pushed only if the mark was cleared).  Idempotency does not live
here — it lives in the stored mark — so a sink need not dedupe.
sourceraw docstring

*stale-sink*clj

The operator sink for sweep-stale: (fn [dispute-entry] …), called once per dispute swept to :stale. An aged-out dispute is re-surfaced to a human, never silently dropped. nil ships no push.

The operator sink for `sweep-stale`: `(fn [dispute-entry] …)`, called once per dispute
swept to `:stale`.  An aged-out dispute is re-surfaced to a human, never silently
dropped.  nil ships no push.
sourceraw docstring

*timeout-ms*clj

How long a dispute may stay live with no ruling before sweep-stale flags it (and re-surfaces it to a human). A judgement call — a curated ground truth wants it long enough that a real disagreement is not swept before anyone looks. Default 24h.

How long a dispute may stay live with no ruling before `sweep-stale` flags it (and
re-surfaces it to a human).  A judgement call — a curated ground truth wants it long
enough that a real disagreement is not swept before anyone looks.  Default 24h.
sourceraw docstring

cast-ballotclj

(cast-ballot kb principal stance claim-handle)

Cast principal's stance (:for / :against) ballot on the claim at claim-handle through identity/ingest: (votesFor id (sentexHandle claim)) in the principal's own context, attested when principal is a :proof-tier one authenticate minted. The in-process ballot resolve-by-majority counts; channel/vote writes the same sentence unattested. An unknown stance is refused (:koinii/no-such-stance). Returns the ballot's handle.

Cast `principal`'s `stance` (`:for` / `:against`) ballot on the claim at
`claim-handle` through `identity/ingest`: `(votesFor id (sentexHandle claim))` in the
principal's own context, attested when `principal` is a `:proof-tier` one
`authenticate` minted.  The in-process ballot `resolve-by-majority` counts;
`channel/vote` writes the same sentence unattested.  An unknown stance is refused
(`:koinii/no-such-stance`).  Returns the ballot's handle.
sourceraw docstring

contested-premisesclj

(contested-premises kb S ctx)

The disputed premises the conclusion S rests on in ctx: the handles in S's support closure that are a side of an open dispute ctx observes. Empty if S rests on nothing contested. A pure read that changes no belief (unlike quarantine): an open dispute does not block dependent reasoning, so a conclusion resting on a contested premise should be visible as such.

Scoped to the ANCESTOR SET. S is every believed sentex of S in a context ctx sees (v/sees?), the scoping disputes-in and ask? use: forward chaining places a conclusion in the most specific context that sees its premises, an AGENT's context rather than the channel's, so an exact-context lookup would answer 'nothing contested' for a conclusion built on a disputed claim. Every visible derivation: where more than one context holds S, their support closures are UNIONED, so no tie-break depends on seq order or handles. Belief-filtered: a defeated stored sentex holds up no answer. Content-ordered by the premise's [sentence context] (v/sort-by-content); the context is required since the union can hold one sentence in two agents' contexts.

The disputed premises the conclusion `S` rests on in `ctx`: the handles in S's support
closure that are a side of an open dispute `ctx` observes.  Empty if S rests on nothing
contested.  A pure read that changes no belief (unlike `quarantine`): an open dispute does
not block dependent reasoning, so a conclusion resting on a contested premise should be
*visible as such*.

**Scoped to the ANCESTOR SET.**  `S` is every believed sentex of `S` in a context `ctx`
sees (`v/sees?`), the scoping `disputes-in` and `ask?` use: forward chaining places a
conclusion in the most specific context that sees its premises, an AGENT's context
rather than the channel's, so an exact-context lookup would answer 'nothing contested' for
a conclusion built on a disputed claim.  **Every visible derivation**: where more than one
context holds `S`, their support closures are UNIONED, so no tie-break depends on seq
order or handles.  **Belief-filtered**: a defeated stored sentex holds up no answer.
**Content-ordered** by the premise's `[sentence context]` (`v/sort-by-content`); the
context is required since the union can hold one sentence in two agents' contexts.
sourceraw docstring

majority-arbiterclj

The principal recorded as ruler of a majority-vote resolution — not a real agent but the stand-in 'the house majority', so who-ruled tells a counted vote apart from a named arbiter's decree.

The principal recorded as ruler of a majority-vote resolution — not a real agent but
the stand-in 'the house majority', so `who-ruled` tells a counted vote apart from a named
arbiter's decree.
sourceraw docstring

notify-disputesclj

(notify-disputes kb channel)

The default policy's core move: announce every not-yet-announced dispute channel observes and record it notified. For each :open dispute (pending-disputes), record a notified mark (open -> notified) and push the entry to *notify-sink*. Changes NO belief: both sides stay in? at :default. Fires once per dispute: the stored mark is the idempotency key, so a redelivery or a catch-up re-run does not re-push it. Returns the disputes newly notified.

The default policy's core move: announce every not-yet-announced dispute `channel`
observes and record it `notified`.  For each `:open` dispute (`pending-disputes`), record
a `notified` mark (`open -> notified`) and push the entry to `*notify-sink*`.  Changes NO
belief: both sides stay `in?` at `:default`.  **Fires once per dispute**: the stored mark
is the idempotency key, so a redelivery or a catch-up re-run does not re-push it.  Returns
the disputes newly notified.
sourceraw docstring

pollclj

(poll kb channel)

One driver tick over channel: notify the fresh disputes, then sweep the aged ones. Returns {:notified [...] :stale [...]}. A subscribe loop or a timer calls this; the two halves are also usable apart.

One driver tick over `channel`: notify the fresh disputes, then sweep the aged ones.
Returns `{:notified [...] :stale [...]}`.  A subscribe loop or a timer calls
this; the two halves are also usable apart.
sourceraw docstring

quarantineclj

(quarantine kb channel target-handle)

OPTIONAL, off by default: hide the contested sentex target-handle from channel's reads and derivations, reversibly, via an index-layer except asserted in channel, for a high-stakes channel that must never let a conclusion rest silently on a contested premise. Scoped to channel: the claim stays believed in its OWN context. It OVER-SUPPRESSES: channel can no longer see the dispute (argue there reads the lone surviving side), and except interacts with the TMS and contexts. Prefer contested-premises / rests-on-contested? unless a channel must exclude contested claims from derivation. Returns the mask's handle; unquarantine! retracts it (cascading derivations back).

OPTIONAL, off by default: hide the contested sentex `target-handle` from `channel`'s reads
and derivations, reversibly, via an index-layer `except` asserted in `channel`, for a
high-stakes channel that must never let a conclusion rest silently on a contested premise.
Scoped to `channel`: the claim stays believed in its OWN context.  It OVER-SUPPRESSES:
`channel` can no longer see the dispute (`argue` there reads the lone surviving side), and
`except` interacts with the TMS and contexts.  Prefer `contested-premises` /
`rests-on-contested?` unless a channel must exclude contested claims from derivation.
Returns the mask's handle; `unquarantine!` retracts it (cascading derivations back).
sourceraw docstring

quarantinedclj

(quarantined kb channel)

The sentex handles channel is currently quarantining — the targets of its (except (sentexHandle ?h)) masks. 'What has this channel screened out' as a plain read.

The sentex handles `channel` is currently quarantining — the targets of its
`(except (sentexHandle ?h))` masks.  'What has this channel screened out' as a plain read.
sourceraw docstring

resolve-by-majorityclj

(resolve-by-majority kb id claim-handle channel)

Resolve dispute id over the claim at claim-handle by MAJORITY VOTE, within channel. Count the ballots (tally); if one side has strictly more, uphold it as a reversible ruling (rule, arbiter majority-arbiter): the claim for a :for majority, its negation for :against. A tie upholds nothing: the dispute stays open.

The count is the authority, every time: a ruling that no longer matches the count is withdrawn before the new one lands, so a swing retracts the standing ruling and rules the other side, and a majority that dissolves into a tie retracts it and leaves the dispute open. Returns {:for n :against n :outcome :for/:against/:tie :ruling handle-or-nil :withdrawn [handle …]}. Idempotent: re-running on an unchanged count withdraws nothing, so a driver may poll it.

Requires the :proof-tier identity policy, and a proven voter on every ballot. A count by claimed voter name is spoofable, so this refuses (:koinii/identity-unverified) under any other policy, and when any ballot on the claim, spoiled ones included, proves no voter (proven-voter?), naming them in :unattested. cast-ballot under a minted :proof-tier principal attests one, and a daemon with a token table records the :principal of a wire ballot (docs/koinii.md, Identity and the write boundary). tally is unrestricted.

Resolve dispute `id` over the claim at `claim-handle` by MAJORITY VOTE, within `channel`.
Count the ballots (`tally`); if one side has strictly more, uphold it as a reversible
ruling (`rule`, arbiter `majority-arbiter`): the claim for a `:for` majority, its negation
for `:against`.  **A tie upholds nothing**: the dispute stays open.

**The count is the authority, every time**: a ruling that no longer matches the count is
withdrawn before the new one lands, so a swing retracts the standing ruling and rules the
other side, and a majority that dissolves into a tie retracts it and leaves the dispute
open.  Returns `{:for n :against n :outcome :for/:against/:tie :ruling handle-or-nil
:withdrawn [handle …]}`.  Idempotent: re-running on an unchanged count withdraws nothing,
so a driver may poll it.

**Requires the `:proof-tier` identity policy, and a proven voter on every ballot.**  A
count by claimed voter name is spoofable, so this refuses (`:koinii/identity-unverified`)
under any other policy, and when any ballot on the claim, spoiled ones included, proves no
voter (`proven-voter?`), naming them in `:unattested`.  `cast-ballot` under a minted
`:proof-tier` principal attests one, and a daemon with a token table records the
`:principal` of a wire ballot (docs/koinii.md, *Identity and the write boundary*).  `tally`
is unrestricted.
sourceraw docstring

rests-on-contested?clj

(rests-on-contested? kb S ctx)

Does the conclusion S, as ctx sees it, rest on any premise that is currently disputed there? The boolean over contested-premises — the flag a high-stakes reader checks before trusting a derived answer, and it reads S up the genlCx ancestor set for exactly that reason: an answer ask? gives at ctx off a premise stored below it is the case a safety flag exists to catch, not the case it may miss.

Does the conclusion `S`, as `ctx` sees it, rest on any premise that is currently disputed
there?  The boolean over `contested-premises` — the flag a high-stakes reader checks before
trusting a derived answer, and it reads `S` up the genlCx ancestor set for exactly that reason: an
answer `ask?` gives at `ctx` off a premise stored below it is the case a safety flag exists
to catch, not the case it may miss.
sourceraw docstring

ruleclj

(rule kb arbiter id upheld channel)

Arbiter escalation: arbiter (an agent id, e.g. AgentArbiter) rules dispute id within channel for upheld, a side or its negation; any other is refused :koinii/not-a-side.

The ruling is an ordinary assertion: upheld at :monotonic strength in the arbiter's OWN context (id/context-for), lifted under channel, with creator arbiter and tagged :adjudication id in provenance. Monotonic strength defeats the losing :default side, so the dispute reads :resolved and argue collapses to :true/:false.

One ruling per arbiter per dispute: a ruling for the other side is retracted first; ruling the same side again is a belief no-op that returns the standing handle. Reversible: retracting the returned handle reopens the dispute through the JTMS. The open/notified/stale marks are cleared once the ruling has LANDED, so a reopen re-notifies; a REFUSED ruling clears nothing. Returns the ruling handle. It resolves a :default coexisting dilemma only: a :monotonic :conflict needs a human to retract a premise.

An arbiter who is a party to the dispute is refused (:arbiter-is-party): the arbiter's context already holds one of the two sentences, so ruling their own way would re-record their claim and ruling the other way would retract it, deleting the claim instead of settling the dispute.

Arbiter escalation: `arbiter` (an agent id, e.g. `AgentArbiter`) rules dispute `id` within
`channel` for `upheld`, a side or its negation; any other is refused `:koinii/not-a-side`.

The ruling is an ordinary assertion: `upheld` at `:monotonic` strength in the arbiter's OWN
context (`id/context-for`), lifted under `channel`, with creator `arbiter` and tagged
`:adjudication id` in provenance.  Monotonic strength defeats the losing `:default` side,
so the dispute reads `:resolved` and `argue` collapses to `:true`/`:false`.

**One ruling per arbiter per dispute**: a ruling for the *other* side is retracted first;
ruling the same side again is a belief no-op that returns the standing handle.
**Reversible**: retracting the returned handle reopens the dispute through the JTMS.  The
open/notified/stale marks are cleared once the ruling has LANDED, so a reopen re-notifies;
a REFUSED ruling clears nothing.  Returns the ruling handle.  It resolves a `:default`
coexisting dilemma only: a `:monotonic` `:conflict` needs a human to retract a premise.

**An arbiter who is a party to the dispute is refused** (`:arbiter-is-party`): the
arbiter's context already holds one of the two sentences, so ruling their own way would
re-record their claim and ruling the other way would *retract* it, deleting the claim
instead of settling the dispute.
sourceraw docstring

standing-rulingsclj

(standing-rulings kb arbiter id)

The rulings arbiter currently holds on dispute id: the handles in the arbiter's own context whose provenance rule tagged with id. Believed rulings only ({:believed? true}), since rule's caller retracts what this returns and a defeated ruling must not be withdrawn twice. Ranked by the ruling's sentence with v/sort-by-content, not by handle (assertion order would make resolve-by-majority's :withdrawn list a fact about how the KB was loaded) and not by a printed key (an ambient *print-* var could elide two rulings to one key; a ruling of 9 precedes one of 10). Canonical dedup gives one sentex per (sentence, context), so the sentence is a total order.

The rulings `arbiter` currently holds on dispute `id`: the handles in the arbiter's own
context whose provenance `rule` tagged with `id`.  **Believed rulings only**
(`{:believed? true}`), since `rule`'s caller retracts what this returns and a defeated
ruling must not be withdrawn twice.  Ranked by the ruling's **sentence** with
`v/sort-by-content`, not by handle (assertion order would make `resolve-by-majority`'s
`:withdrawn` list a fact about how the KB was loaded) and not by a printed key (an ambient
`*print-*` var could elide two rulings to one key; a ruling of 9 precedes one of 10).
Canonical dedup gives one sentex per (sentence, context), so the sentence is a total
order.
sourceraw docstring

sweep-staleclj

(sweep-stale kb channel)

Sweep every dispute channel observes that has stayed live past *timeout-ms* with no ruling to :stale, pushing each to *stale-sink*. A stale dispute is STILL live (both sides coexist, argue still reports :contradiction); :stale flags that it aged out unaddressed. Idempotent. Returns the disputes swept. One whole-KB scan for the sweep: the skip reads the stored :stale mark (dispute/stale?), since every entry disputes-in hands back is live and dispute-state would re-scan per entry.

Sweep every dispute `channel` observes that has stayed live past `*timeout-ms*` with no
ruling to `:stale`, pushing each to `*stale-sink*`.  A stale dispute is STILL live (both
sides coexist, `argue` still reports `:contradiction`); `:stale` flags that it aged out
unaddressed.  Idempotent.  Returns the disputes swept.  **One whole-KB scan for the
sweep**: the skip reads the stored `:stale` mark (`dispute/stale?`), since every entry
`disputes-in` hands back is live and `dispute-state` would re-scan per entry.
sourceraw docstring

tallyclj

(tally kb claim-handle)

Count the ballots cast on the claim at claim-handle: {:for n :against n}, each a count of DISTINCT voters (ballots).

A voter who cast BOTH stances (without retracting the first, against vote's contract) has SPOILED their ballot — counted on neither side — so one self-contradicting voter can neither manufacture a tie nor swing a majority; their confusion abstains rather than double-voting.

Count the ballots cast on the claim at `claim-handle`: `{:for n :against n}`, each a
count of DISTINCT voters (`ballots`).

A voter who cast BOTH stances (without retracting the first, against `vote`'s contract)
has SPOILED their ballot — counted on neither side — so one self-contradicting voter can
neither manufacture a tie nor swing a majority; their confusion abstains rather than
double-voting.
sourceraw docstring

unquarantine!clj

(unquarantine! kb handle)

Undo a quarantine: retract the except mask at handle, so the claim and anything it fed count again in the channel. Returns retract!'s counts.

Undo a `quarantine`: retract the `except` mask at `handle`, so the claim and anything it
fed count again in the channel.  Returns `retract!`'s counts.
sourceraw docstring

who-ruledclj

(who-ruled kb ruling-handle)

Read a ruling off its handle: {:arbiter :dispute-ids :at} from the provenance rule recorded, or nil if ruling-handle is not an adjudication assertion. :dispute-ids is a set: canonical dedup gives one sentex per (sentence, context), so an arbiter who rules two disputes the same way records an adjudication on one handle twice, and a single-valued tag would leave the earlier dispute with no standing ruling and let a second monotonic ruling land beside the first (a :conflict no ruling can settle).

Read a ruling off its handle: `{:arbiter :dispute-ids :at}` from the provenance `rule`
recorded, or nil if `ruling-handle` is not an adjudication assertion.  `:dispute-ids` is a
**set**: canonical dedup gives one sentex per (sentence, context), so an arbiter who rules
two disputes the same way records an adjudication on one handle twice, and a single-valued
tag would leave the earlier dispute with no standing ruling and let a second monotonic
ruling land beside the first (a `:conflict` no ruling can settle).
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
←Move to previous article
→Move to next article
Ctrl+/Jump to the search field
× close