Skip to content
← Documentation

docs/truth-kinds.md


What kinds of truths exist?

⚠️ Superseded in part by truth-reduction.md. Constraint was subsequently reduced to a state on a policy subject, and interpolability was reduced to absent-evidence semantics. The classification of the ledger below stands; the three-kind result does not.

Identity failed as a universal function. The question underneath it: what kind of truth is being represented? Identity should follow from that.

Derived from the phenomenon ledger, not from the fact families. The four families are treated here as hypotheses, and two of them do not survive as truth-kinds.


1. Deriving the distinction — without circularity

The level/occurrence split cannot be derived from separation semantics, because separation is what we are trying to explain. A prior, independent discriminator is needed.

Interpolability. Take two observations with nothing observed between them. Does the truth hold in the gap?

  • Temperature: between a reading at 09:00 and one at 09:05, the temperature had some value. It never stopped being true.
  • Payment: between a payment at 09:00 and one at 09:05, there is no payment. The gap is empty, not unobserved.

That is a claim about reality, testable per phenomenon, and it makes no reference to identity. And separation then falls out:

Holds in the gap? Therefore two equal adjacent observations are…
State yes — it persisted one continuing truth — episode separation
Occurrence no — the gap is empty two truths — always separate

The separation semantics are not a design choice and not an implementation detail. They are entailed by whether the truth exists between its observations. That is the derivation.


2. The ledger, classified by semantic behaviour

Phenomenon Holds between observations? Class
temperature yes state
concentration yes state
inventory yes state
location yes state
employment yes state (2-ary)
ownership yes state (2-ary)
shipment ambiguous both — see below
payment no occurrence
heartbeat no occurrence
commit no occurrence
package delivery no occurrence
chemical reaction no occurrence

Three things fall out that the fact families obscure.

Heartbeat is decisive. It is an occurrence that changes no state at all. Nothing rises, falls, or moves. So occurrences cannot be modelled as state-transitions — there is no transition. Together with the earlier result (two simultaneous transfers a→b and c→b of 5 give the same net levels as one of 10), occurrence is irreducible to state on two independent grounds: one where the deltas collide, one where there are no deltas.

Occurrences become subjects. A commit, a payment and a delivery each acquire properties after they occur — a commit has an author, a payment has a status. So an occurrence can be promoted to a subject that then bears states. The classes are not disjoint over things; they are disjoint over truths.

"Shipment" names two truths at once — the parcel (a state-bearer with a location) and the act of shipping (an occurrence). This is a warning about method: phenomenon names do not map one-to-one onto truth kinds, so any classification that starts from vocabulary rather than from the interpolability test will inherit natural language's conflations.


3. Are there only two classes?

The six candidates, tested rather than assumed.

Eliminated: relation

Employment and ownership are interpolable, so they are states. What distinguishes them is that their subject-tuple has arity 2. Arity is not a truth kind. exchange already demonstrates a 3-ary tuple without anyone proposing a class for it. Relation is a state over a tuple.

Eliminated: measurement — a category error

Temperature is a state. Measurement is how we come to know it. Putting measurement in a list of truth kinds confuses what is true with how it is known, which is precisely the layer the evidence field occupies.

This matters because the family is named measure. The name records the observation method, not the kind of truth — and that is why MeasureFact ended up carrying limit and enforced (below).

Unsettled: capability

⚠️ Retracted by semantic-typing.md. capability → state matches algebra and layer and mismatches role — modal versus actual. That is the over-collapse pattern, committed here before the pattern was known.

"This machine can produce 100 units/hour" is interpolable, so by the test it is a state whose dimension is dispositional. But it differs from every other state in one respect: non-exercise is not evidence of absence. A machine idle all day does not thereby lack the capability, whereas a thermometer reading nothing does mean the temperature is unobserved.

Recorded as state, least settled. It may need a modal treatment; that has not been demonstrated, and one unusual property is not a class.

Survives: constraint — a third class

"Inventory must not exceed 100." Two discriminators, either sufficient:

  1. It is not observed. It is stipulated. No observer reports it; it is adopted by an authority. The evidence field is meaningless for it — and evidence is otherwise mandatory on every fact.
  2. It can be violated. This is the sharp one. A state cannot be violated; it simply is. A temperature of 200° does not violate anything. But a constraint can be true as a rule and false in fact at the same instant — a truth mode no state or occurrence has.

Violability is not a property of anything else in the ledger. Constraint earns its class.

And it is already here, unclassified, in two places:

  • MeasureFact.limit + enforced — a constraint riding inside a state fact. enforced exists to distinguish a real constraint from a decorative one, which is a constraint-kind question being answered by a boolean flag on a measure.
  • constitution.ts CONSTANTS, each with assumed: true | false — a constraint table with the same shape and the same flag, in a different subsystem.

Two independent subsystems grew the same structure, neither named it, and both needed a flag for is this constraint real. That is convergent evidence for the class, found rather than invented.


4. Identity follows from truth kind

The payoff. Separation is not one rule with exceptions; it is one rule per truth kind, each entailed by that kind's relationship to observation:

Class Exists between observations? Separates on Third identity component
state yes a change of value episode ordinal
occurrence no always occurrence ordinal
constraint not observed at all amendment version ordinal

A constraint has no observation series, so it cannot have an episode or an occurrence index. It has a validity period running from adoption to repeal, and it separates when it is amended — a third rule, derived the same way as the first two, from the kind's relation to observation.

Identity is not universal, and it does not need to be. It is a function of truth kind, and truth kind is derivable from a single test. That is a stronger result than a universal identity function would have been: it explains why no universal function exists.

The four fact families are not four truth kinds. condition, measure and placement are three states differing only in value type; exchange is an occurrence. The families encode value type and observation method, and the truth-kind distinction is nowhere in the type system.


5. PlacementFact.since — the partial discovery, confirmed

Placement is a state. since is its episode start. So one family already carries interval semantics — and the suspicion that the distinction was "partially discovered but never generalized" holds, with a mechanism:

  • It is derivable, not primitive. Under correct episode identity, since is the validAt of the first observation in the run. It is a materialized cache of what identity should compute, which is exactly why it can go stale and disagree with its own fact.
  • It is required at ingest (ingest.ts:30since: Instant, not optional). So every connector is asked to compute episode boundaries. That is the same layering error as id below: canonicalization work pushed onto the observer, who cannot see the other observers' facts and therefore cannot know where an episode begins.
  • Why placement got it and the others did not: location change is the most perceptually salient episode — a thing visibly moves. The field was added under rendering pressure, not derived, so it never generalised to temperature or employment, which are episodic in exactly the same way.

Window in core/time.ts remains unused because the one place that needed interval semantics hand-rolled half of them.


6. The id field — which layer?

Measured, not reasoned.

ingest.ts:94 idOf() is byte-for-byte identical to fact.ts:92 factIdentity() — same four cases, same string formats, same order.

Against the five candidates:

Candidate Verdict
connector identity no — no connector value enters it. ConnectorManifest.id is documented "Provenance only. Never enters an identity."
observation identity no — by construction two observers of one fact produce one id; an observation identity would distinguish them
evidence identity no — evidence carries its own observer and citation
provenance identity no — it records nothing about origin
semantic identity yes — a pure function of subjects and dimension

Same layer. The dual-ownership diagnosis stands — and is worse than stated: this is not merely a competing identity, it is a duplicated implementation of the same function. That is the exact defect fact.ts already documents having fixed once, when lib/hq/findings.ts re-implemented conditionIdentity byte-identically. The duplicate was removed there and left here, in the module the comment was written in.

Two further measurements sharpen it:

  • Nothing reads fact.id. collapse keys on factIdentity, not on id. The field is dead weight that is also authoritative-looking.
  • A test asserts the duplication. core-invariants.test.ts:232 asserts merged.facts[0].id === "stalled:" + urn(shared). So divergence is currently caught — for the condition family, in one case. The other three families are unguarded, and the guard tests the duplicate rather than removing it.

And when collapse merges, the surviving id is whichever fact was encountered first — the same order-dependence already recorded for validAt.


Classification

Question Result
Is the level/occurrence distinction fundamental? yes — derived from interpolability, independent of identity
Do separation semantics emerge automatically? yes — entailed, not chosen
Are there only two classes? no — three. state, occurrence, constraint
relation eliminated — a state over a tuple; arity is not a truth kind
measurement eliminated — a category error; it is the evidence layer
capability state, least settled; non-exercise ≠ absence
PlacementFact.since partial discovery confirmed; derivable, and demanded of connectors
id semantic identity — same layer; dual ownership stands, as a duplicated implementation

Nothing implemented. The constraint class is derived from the ledger and from two subsystems that independently grew its shape; whether it warrants a representation is a separate question, not answered here.