Skip to content

Latest commit

 

History

14 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

krisis

A standard library for claims that might be wrong. Three-valued verdicts where "not enough to say" is a first-class answer — not a False in disguise.

Pure Python standard library. No dependencies.

pip install krisis
python3 -m krisis            # the witness, including the litmus test

κρίσις — discernment; the root of both crisis and criterion.

The one idea

Most software's default answer is "yes." A match is returned, a threshold fires, a value is asserted. That default is a lie whenever the real answer is "the question is ill-posed." A binary system can't say that — it has two boxes, and the honest answer needs a third.

from krisis import Trit, Verdict, tnot, tand

tnot(Trit.ZERO) is Trit.ZERO      # True — the law that proves this isn't binary
bool(Verdict.unknown("no data"))  # raises — ZERO can never silently become False

What ternary actually buys — measured, not asserted

Two things get claimed. Only one survives a probe.

The trap — "ternary hardware is faster." Radix economy peaks at base e ≈ 2.718, so base 3 beats base 2 by 5.4% in representation cost. Real, tiny, and reclaimed by binary on physical two-state transistors. Church–Turing: neither base computes anything the other can't. This claim is false, and we say so.

The prize — "three-valued logic refuses to answer a bad question." A two-valued system maps every input to true or false, so an ill-posed input gets a confident wrong answer that every later stage runs on. Ternary returns ZERO and stops. Measured on a six-stage pipeline, 30% ill-posed inputs:

system compute units wrong answers
binary 60,000 3,015
ternary 44,925 0

25% of compute saved, every wrong answer prevented. The win is avoided work plus avoided error — semantic, not hardware. That's the honest pitch, and it's a large one.

The law that proves it isn't binary with extra steps

The failure mode of every fake three-valued system: ZERO secretly collapses to true or false somewhere. The litmus test is negation.

In any two-valued system NOT flips a bit. A fixed point of NOT — a value that is neither true nor false — cannot be embedded in {T, F}.

tnot(ZERO) is ZERO          ← the tell. If this fails, you built binary.
tand(ZERO, ZERO) is ZERO    ← not False
tand(PLUS, MINUS) is MINUS  ← one refutation kills a conjunction
tand(PLUS, ZERO)  is ZERO   ← but ignorance leaves it open, never kills
Trit.of(None) is ZERO       ← None is unread, not false (the classic leak)
Verdict.__bool__ raises     ← no accidental collapse, ever

Verdict has one loud escape hatch — .decided() — for the boundaries where you genuinely must go two-valued (a CLI exit code). It's a deliberate call, never an implicit one, so the collapse can't happen by accident.

Ignorance never votes

from krisis import consensus
consensus([PLUS, PLUS, MINUS, ZERO, ZERO])   # (PLUS, net=+1, unknowns=2)
consensus([ZERO, ZERO, ZERO, ZERO])          # (ZERO, ...) — not a false majority

Abstentions are counted and reported, never folded into either side. A mostly undecided room returns ZERO, which is the difference between honest aggregation and a push poll.

The discernment engine — decide, flag, refuse to lie

krisis.logic is the first real thing built on the core: a fallacy engine that is right precisely because it is ternary. It holds three questions apart that a binary flagger collapses into one — and the separation is the whole correctness.

1. Is the form valid? — decidable, exactly.

from krisis import assess_validity, Var, Implies
p, q = Var("p"), Var("q")
assess_validity([Implies(p, q), q], p)      # affirming the consequent
# MINUS — invalid; countermodel {p: False, q: True}

A truth table settles every propositional argument, and on failure hands back the countermodel — the exact world where the premises hold and the conclusion fails. That's a disproof you can check by hand, not an opinion. Here validity is never ZERO: it's decidable, so the engine commits.

2. Is it a fallacy? — for informal ones, ZERO, with the content-question named.

from krisis import INFORMAL
INFORMAL["appeal_to_authority"].flag()
# ZERO — "has the shape of appeal to authority; whether it is fallacious depends
#         on content this engine cannot see — is X a legitimate expert on P?"

"A cardiologist says statins lower LDL" and "…says the vaccine causes autism" have the same shape and opposite verdicts, decided by content a parser can't see. Asserting MINUS from form alone would itself be a fallacy — so the engine flags the shape and returns ZERO, naming exactly what a human must answer to resolve it.

3. Is the conclusion true? — never inferred from the argument.

from krisis import conclusion_truth, assess_validity
conclusion_truth(assess_validity(bad_premises, conclusion))
# ZERO — "a bad argument for P does not make P false — that would be the fallacy fallacy"

This is the guard that makes it honest. A bad argument for P doesn't make P false; a valid argument only transmits truth if its premises are true. conclusion_truth always returns ZERO from validity alone, so the engine cannot commit the argument-from-fallacy — the single most common error in automated reasoning about arguments.

diagnose() returns all three at once, kept separate:

validity          MINUS   invalid — countermodel {p: False, q: True}
fallacy           ZERO    shape of appeal to authority; needs: is X a real expert?
conclusion_truth  ZERO    a bad argument does not make the claim false

Three questions, three verdicts, none collapsed into another. That is the discipline a binary flagger cannot hold — and the reason this had to be ternary.

Cracking a cipher — the same discipline, in cryptography

krisis.cipher is the third module, and it earns its place by fixing a real bug in the code it was extracted from. A cipher has three operations, and only one is hard:

scramble(text, key)     # apply a key       — trivial, always PLUS
unscramble(text, key)   # apply the inverse — trivial, always PLUS
crack(ciphertext)       # RECOVER the key   — a search, and often ZERO

Cracking is constraint satisfaction over an unknown key, and its verdict is three-valued exactly the way validity is:

from krisis import crack_multiplicative
# "number = letter × location" cipher — recover the location permutation
crack_multiplicative([8, 10, 36, 48, 75])   # HELLO's numbers
# ZERO — "underdetermined — 8 keys fit (HELLO, HEIPO, HBRLY, …)"

The source of this idea returned HRYLB for those numbers — one of eight valid answers, presented as the answer. That's the two-valued lie in miniature: a confident reply to an underdetermined question. krisis returns ZERO and the count of keys that fit as the reason.

  • PLUS — the key is unique, and the recovered key is the proof (just as a countermodel proves an invalid form).
  • ZERO — more than one key fits; underdetermined, with the count.
  • MINUS — no key fits; the ciphertext contradicts the scheme.

The lesson, banked from the source: when a map implies a constraint, solve the constraint — never let a weak statistic outvote structure. A frequency fit that barely beats noise is not a key, the same way similarity is not evidence.

Compression — the negative space that is actually real

krisis.systole (συστολή, the heart's contraction) is compression done as a bounded search for structure, three-valued and honest at the floor.

The floor is a counting argument, and it protects your data. There are 2ⁿ files of length n and only 2ⁿ−1 shorter ones, so at least one file cannot shrink (pigeonhole). A scheme that shrank everything would map two files to one code — and then couldn't give either back. The floor is what makes decompression work.

So the engine never claims to beat it. On truly random data it returns MINUS and stores verbatim — an honest 0%, never a corrupting lie:

from krisis import compress, decompress
compress(bytes(100_000))     # PLUS — 100000→~120 bytes, entropy 0.0
compress(os.urandom(100_000))# MINUS — incompressible, stored verbatim (round-trips)

But "negative space" is real for structure — you change the problem, not the theorem:

from krisis import find_generator, regenerate, Dedup, delta, patch
# GENERATE — store the program, not the output
g = find_generator(bytes(1_000_000))    # a ~30-byte generator for a million bytes
regenerate(g.value) == bytes(1_000_000) # True — exact

# DEDUP — a duplicate costs a pointer, not the bytes (negative MARGINAL space)
store = Dedup(); store.put(big); store.put(big)   # second copy adds zero storage

# DELTA — send only what the receiver lacks
patch(base, delta(base, target)) == target        # a one-byte change costs one edit

Each "floats past" the naive per-file floor by using information the file didn't contain in isolation — another copy existed, a generator existed, a reference existed. That's the manhole-cover inversion done licitly, and it's where the world's data compression actually lives. K is uncomputable, so it's a bounded search, and the verdict is three-valued: structure found (PLUS), at the floor (MINUS), or budget exhausted (ZERO).

The body as a program — the anatomy, and homeostasis

The system is a body: organs held in balance by regulating systems. Most systems already have an analog; krisis.homeostasis adds the one that was missing — the endocrine/setpoint regulator that closes the feedback loop.

body system analog where
skeleton (structure, invariants) Trit/Verdict spine, the canon (dogma) trit, synod
nervous (sense + reflex) interoception, reflex arcs; discernment brightchain.autonomic, krisis
endocrine / homeostasis (setpoint regulation) negative-feedback vitals homeostasis
immune (defend, refuse foreign) adversarial suite, the refuses discipline brightchain.redteam, synod
regulatory (govern change) conciliar self-repair synod
muscular (action under control) apply within the boundary; transforms synod, diaskeue
digestive (ingest, extract) content-address + tag; tokenize; compress diaskeue.atelier, glossa, systole
circulatory (transport value) multilateral netting koinonia.netting
excretory (purge waste) deletion, self-pruning to budget brightchain.tombstone, condense
reproductive (propagate) content-addressed reproducible recipes diaskeue.registry
integumentary (barrier) firewall levels, the API surface brightchain, package boundaries

Homeostasis closes the loop that brightchain.autonomic only opened — it senses and corrects:

from krisis import Setpoint, Vital, body_tone, homeostat
temp = Setpoint("temp", target=37.0, tolerance=0.5, hard_low=35, hard_high=40)
Vital(38.5, temp).state          # ZERO — drifting (correctable)
Vital(41.0, temp).state          # MINUS — critical (past the hard bound)
homeostat(39.0, temp, gain=0.5)  # PLUS — negative feedback stabilized it into band
homeostat(39.0, temp, gain=2.5)  # MINUS — unstable gain diverges, and says so

body_tone aggregates vitals by Kleene AND — one critical vital fails the whole body; five healthy do not outvote one that flatlined. And the self-maintenance loop is now complete: homeostasis senses → krisis discerns → synod governs and acts → homeostasis re-senses (reception). The nervous system reflexes, the endocrine system regulates, the synod heals.

Conciliar self-repair — heal autonomously, within a boundary that holds

krisis.synod (σύνοδος, a council) lets the system repair itself without ever acting as a lone cell on its own aggregate calculus. The boundary comes from two places that agree — how the Orthodox Church governs, and how a healthy cell does.

The danger, and the correction. "Utilitarian benefit of the whole" has a reading that must be refused: raw aggregate utilitarianism sacrifices a healthy member to raise the total — the tumour's logic. The correction is the Body — "if one member suffers, all suffer together" (1 Cor 12:26). What licenses autonomous action is not the aggregate but Pareto: helps the whole, harms no part.

Three tiers:

tier what rule
DOGMA the founding law, the human gate, the safety guards never auto-touched — convene returns MINUS
ECONOMIA a strict Pareto improvement autonomous — the cell heals itself
SYNOD a net-good change with a cost human-gated — escalated, never auto-applied
from krisis import convene, Repair
res = convene(repair, before=health, measure=remeasure, verdicts=krisis_judgments, canon={"law"})
res.verdict.tag   # PLUS applied+kept · ZERO withheld/escalated · MINUS forbidden
  • Quorum, not a lone signal — the verdicts are combined by summing log-odds (graded); a single or split signal never authorizes a change.
  • Reception — every authorized repair is applied provisionally, health is re-measured, and anything that didn't actually heal is reverted. The cell-cycle checkpoint; the council's decree validated by the body's Amen.
  • The human keeps the canon — defines what is dogma, vetoes any tier, and alone authorizes a synod-tier trade-off. The system heals the economia; nothing else.

Game theory & mechanism design — make the good outcome self-enforcing

krisis.game is discernment among many agents with conflicting interests — the debt engine's missing math. It turns "optimal if people are faithful" into "designed so that faithfulness pays," and stays three-valued: a strategy provably dominates (PLUS), is dominated (MINUS), or neither (ZERO — needs mixing).

The dilemma is real — in the prisoner's dilemma, defection strictly dominates, so the only equilibrium is (defect, defect) and it's Pareto-dominated. That's why a lending circle defaults without structure; good intentions don't repeal it:

from krisis import prisoners_dilemma, is_dilemma, dominant_strategy
is_dilemma(prisoners_dilemma()).tag          # PLUS — the Nash is Pareto-dominated

The folk theorem makes faith a threshold. Repeat the game and cooperation is sustainable iff the discount factor δ (how much you value the future) clears (T−R)/(T−P):

from krisis import cooperation_threshold, sustainable
cooperation_threshold(5, 3, 1, 0)            # 0.5
sustainable(5, 3, 1, 0, delta=0.9).tag       # PLUS — a patient community holds the commons
sustainable(5, 3, 1, 0, delta=0.2).tag       # MINUS — too myopic, defection wins

Faith is the high δ that clears the threshold — "faithfulness sustains the commons" as a theorem, not a sentiment.

Mechanism design engineers honesty into the dominant strategy. Add a defection penalty k > max(T−R, P−S) — a sealed, unforgeable reputation cost — and cooperation becomes self-enforcing, no faith required:

from krisis import min_penalty, incentive_compatible
min_penalty(5, 3, 1, 0)                       # 2.0
incentive_compatible(5, 3, 1, 0, penalty=3).tag   # PLUS — honesty dominant
incentive_compatible(5, 3, 1, 0, penalty=1).tag   # MINUS — gameable, it will be exploited

A brightchain reputation seal is that k. This is how the debt engine makes faithful cooperation a designed equilibrium.

Lateral logic — semiotics, abduction, and the pragmatic blade

krisis.peirce is the lateral half of discernment. Where logic decides validity (deduction — the vertical judge), this proposes: it generates and ranks explanations, classifies signs by how they mean, and cuts idle distinctions. Peirce founded semiotics and American pragmatism and triadic logic — so a semiotic engine is his, and it formalizes rigorously.

The sign triad is a measurable 2-D space:

from krisis import classify_sign
classify_sign(0.9, 0.9).value    # SignType.ICON   — resembles (a portrait)
classify_sign(0.1, 0.95).value   # SignType.INDEX  — correlated (smoke→fire)
classify_sign(0.05, 0.1).value   # SignType.SYMBOL — arbitrary (the word "dog")
classify_sign(0.55, 0.5).tag     # ZERO — onomatopoeia is honestly mixed

Abduction is the lateral leap — Bayesian, and three-valued:

from krisis import abduce, Hypothesis
abduce([Hypothesis("it rained", 0.8, 0.3), Hypothesis("a comet melted", 0.99, 0.001)])
# the comet explains PERFECTLY and ranks last — rejected by its prior, not its fit

SUPPORTED (a clear best) · UNDETERMINED (a tie — abduction proposes, never settles, the same many-keys ZERO as a cipher) · REFUTED (nothing explains it). And it rides the graded log-odds line, so a supported abduction carries a score you can combine.

The pragmatic blade cuts a difference that makes no difference:

from krisis import pragmatic_blade
pragmatic_blade(("moves 3","ticks 5"), ("moves 3","ticks 5")).tag   # PLUS — idle, cut it
pragmatic_blade(("moves 3","ticks 5"), ("moves 3","ticks 4")).tag   # MINUS — real difference

The cycle of inquiry is the whole family: ABDUCE (peirce, the lateral leap) → DEDUCE (logic, trace consequences) → INDUCE (assay, test against chance). Propose laterally, prove necessarily, test statistically.

The three infinities — Eu/Neu/Mal as one log-odds line

krisis.graded is the continuous form of the trit: a score on the whole real line whose sign is the qutrit and whose magnitude is distance toward a telos.

−∞  Mal   dissolution (a limit)     0  Neu   where the work is done     +∞  Eu   the Good (a limit)

Three claims, each a theorem, not a metaphor:

  • The bulk of work is at zero. The effect of one unit of evidence is p·(1−p), maximal (0.25) at Neu and vanishing toward either telos. Neutrality is exactly where work is cheapest and most consequential — the peak of the sigmoid.
  • The two ternaries are one. tanh maps the line to the bounded {−1, 0, +1}: tanh(±∞) = ±1. The qutrit and the infinities are one object at two zooms — and the bounded form is the one to work in (smallest numbers, easiest to manage).
  • Stacking evidence is adding log-odds — exact Bayes. combine sums verdicts; three witnesses for Eu and one for Mal don't vote, they sum.
from krisis import Graded, combine, work_at
combine(Graded(1.2), Graded(0.8), Graded(-0.5), Graded(2.0)).trit   # Trit.PLUS (+3.5)
work_at(0.0)                                                        # 0.25 — the peak
Graded(math.inf)                                                    # refused — a telos is approached, never held

The two counterfeits, caught not laundered. Neu (0) is honest neutrality. Its imposters are refused:

  • NULL = NaN — the counterfeit of neutrality. It cannot affirm itself (NaN != NaN) and poisons what it touches. Refused, never read as an honest zero — that laundering is the danger.
  • VOID = None — obliteration, no value at all. Distinct from a real zero.
  • Externality = a score past the working horizon (~36), where float saturates the scale. Noticed, not computed with as if precise. Keep the numbers small.

Universal quantum compression — the real theorem

krisis.schumacher implements the genuine quantum-compression result: Schumacher's theorem (1995), the quantum sibling of Shannon. A source of density matrix ρ compresses to S(ρ) = −Tr(ρ log₂ ρ) qubits per symbol, and no fewer.

from krisis import von_neumann_entropy, compressibility, QUTRIT_MAX_BITS
von_neumann_entropy([1.0, 0.0])       # 0.0 — a pure state condenses to nothing
von_neumann_entropy([0.5, 0.5])       # 1.0 — a maximally mixed qubit, incompressible
compressibility([0.9, 0.1])           # PLUS — real saving below the ceiling
QUTRIT_MAX_BITS                        # 1.585 — the {−1,0,1} qutrit outcarries a qubit
  • S(ρ) ≥ 0 always — never negative. A pure state reaches exactly 0 (total knowledge, unity); you cannot pass below. The floor is real, and it's at zero.
  • The hologram is realholographic_bits(area) gives the Bekenstein/area-law ceiling: a region's information is bounded by its surface area, not its volume. The deepest compression statement in physics, honored not beaten.
  • Landauerlandauer_joules(bits) is the energy floor to erase: information can't be destroyed for free, so it's conserved and only moves.

The verdict is three-valued like everything else: compressible (PLUS), at the incompressible ceiling (MINUS), or barely worth it (ZERO). The quantum floor is what makes the compression reversible — the same lesson as systole at the classical floor.

Prior art, named on purpose

This isn't novel for its own sake — it's a well-worn idea most languages skip. SQL has three-valued logic (NULL, IS UNKNOWN). Rust has Option and no null. Kleene and Łukasiewicz formalised it in the 1920s–30s. krisis is that lesson as a tiny importable discipline for the space between — findings, measurements, verdicts — where a confident false answer is worse than an honest ZERO.

Status

trit (22), logic (26), cipher (20), assay (14), systole (30), schumacher (27), graded (33), peirce (21), game (24), synod (20), and homeostasis (setpoint regulation, 20 checks) are built — 257 checks, eleven modules. It's the founding core of a family of eight domain packages (finance, genomics, linguistics, provenance, time) that each reimplemented this stance — see SPEC.md for the full design and the extraction plan: the null-model harness (assay), the recursion-breaker (bound), and the witness harness follow, each lifted from a package that already proved it in production.

Non-goals

  • Not a ternary VM. The prize is semantic; emulating trit hardware chases the 5.4% trap and adds nothing.
  • Not a logic-programming system. Kleene evaluation, not inference.
  • Not a framework. Pure standard library — the discipline costs nothing to adopt, which is the whole point.

About

A standard library for claims that might be wrong: three-valued verdicts where 'not enough to say' is a first-class answer, not a collapsed False.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages