solvi.core.knowledge.store¶
The knowledge store: a hash-chained journal of facts, rules, skills, actions and episodes, with provenance, versions, the source check, disputes to a person, the retraction cascade, staleness flags and snapshots for decisions.
The knowledge store: what a system has learned, from whom, and what rests on it — a hash-chained journal of items.
from solvi.core.knowledge import KnowledgeStore
ks = KnowledgeStore("knowledge.jsonl") # any TraceStorage backend (a path, a TraceStorage) or None
a = ks.add("fact", {"s": "abt:123", "r": "same_as", "o": "buy:456"}, source="person", by="ann")
b = ks.add("fact", {"s": "abt:123", "r": "brand", "o": "acme"}, source="outcome", derived_from=[a])
ks.retract(a, by="bob", why="wrong label") # b goes with it; what a refuted or disputed comes back
ks.verify(); ks.fingerprint(); ks.rebuild(skip={a}).fingerprint() # equal: a retraction is exact
ks.snapshot(about="abt:123") # what a decision is given: facts, hints, the fingerprint
An item is one of five kinds — fact (subject, relation, object), rule, skill, action (an action model's preconditions
and effects), episode (one finished case) — with a source: "person", "outcome" (an observation: what really happened),
"spec" (a written specification) or "verified" (a System 2 answer given alone under its guarantee, named by its stored
decision of=). The system's own unverified answers are never admitted: the source check is part of the store, not a
setting (SourceGate; solvi.core.sources.check_source).
State is a function of the live journal entries (JTMS-style): an item is present while it has a live assertion whose
premises (derived_from) are present and not refuted. Per key (scope, subject, relation) the live assertions are walked
in time order: the same value confirms; an outcome refutes the current value (the world changed); a higher-ranked source
(outcome > person > spec > verified) refutes a lower one; supersedes (a producer's own new version) refutes the version
it names; any other contradiction makes every side "disputed" and asks a person — one question per dispute EVENT (the
journal position it opened at): the same two items disputed again after a resolution are asked again. resolve(key,
value, by=) is the person's answer. A disputed item is never a fact.
Statuses: "active" (a fact System 1 may answer on), "hypothesis" (a hint: a behaviour-changing item not yet promoted by the write gates, a derived item on a premise that is not active, or an item under a pending flag), "disputed", "refuted", "expired" (its reconfirm_after ran out on the store's clock, or retired) and "retracted".
Staleness. flag(scope=..., why=...) (a drift or open-set flag) or reconfirm(id) marks items for re-confirmation: an
item learned before the flag is a hint, not a fact, until a newer observation or person confirms it or the flag ends
(end_flag). A flag is read where staleness is asked (stale(id)), not inferred from the item's status. rollback(id)
(supervision undoing an update) restores the previous version as a hint, never as a fact, while a flag covering the
rolled-back version or its scope is pending (a rollback during a pending drift flag once restored a stale threshold as
a fact on a shifted stream, and a stale check that read the item status missed it). reconfirm_after per
(kind, source) (RECONFIRM_DEFAULTS, the store's clock advanced by tick) expires items that weaker evidence keeps.
Every write — add, promote, refuse, retract, flag, resolve, tick, use — is a journal entry: in a TraceStorage (records of
kind "knowledge", in the same hash chain as the decisions when it is the decisions' store) or in memory with its own hash
chain. verify() checks the chain and that the state is what the journal gives; rebuild(upto=n, skip=ids) gives the
store as it was at entry n, or as if ids had never been written; a store opened on a backend is replayed from its
journal (an entry edited by hand breaks the chain). snapshot(...) returns what a decision reads, with the store's
fingerprint and journal position, so every decision that is given it records the knowledge it used and replays;
redecide(storage, retracted, decide) re-runs the decisions that rested on retracted items on their re-built snapshots
and splits them into "answer changes" (to a reviewer) and "justification only" (recorded).
Measured by benchmarks/knowledge/retraction.py: 1,000 of 1,000 random retractions exact on a 10,000-item synthetic store (the store after a retraction has the fingerprint of the store rebuilt without it). Cost grows with the connected component a write touches (premise edges and shared keys); the store has been measured to 10,000 items, not 10⁵–10⁶.
Verdict
dataclass
¶
A write gate's answer about one proposed item: admitted or not, why, and what it measured (recorded).
SelfDefeating ¶
Bases: ValueError
A derived item whose key is a key of one of its own premises with another value: it would refute its support.
KnowledgeStore ¶
See the module docstring.
storage: where the journal is kept — None (in memory), a path (solvi.core.store.open_storage: .jsonl, .db, .duckdb, postgresql://) or a TraceStorage (the decisions' store itself, so knowledge and decisions share one hash chain); an existing journal there is replayed. gates: the write gates (solvi.core.knowledge.gates; default SourceGate and ConsistencyGate); the source check runs first whatever is given. defaults: reconfirm_after per (kind, source).
verify ¶
Is the journal's hash chain whole (in memory: its own chain; on a backend: the backend's verify()), and is the state the one the journal gives (the store rebuilt from it has the same fingerprint)?
rebuild ¶
The store the journal gives, in memory: entries applied in order (upto: the first upto — the store as it
was then); skip: item ids whose own entries (assertions, promotions, retractions) are left out — the store as if
they had never been written. Premises naming a skipped item stay in the entries derived from it (dead).
proposal ¶
proposal(kind, body, scope=None, *, source, by=None, evidence=None, derived_from=(), supersedes=None, reconfirm_after=None, valid=None, level=None, of=None)
A proposed item as the write gates see it (a dict with the record's fields; nothing is written).
add ¶
add(kind, body, scope=None, *, source, by=None, evidence=None, derived_from=(), supersedes=None, reconfirm_after=None, valid=None, level=None, of=None, shadow=None)
Propose an item → its id, or None when a gate refused it (a "refused" entry in the journal says why).
kind: one of KINDS; body: plain JSON (a fact: {"s", "r", "o"}); scope: a dict (a question, an environment); source: "person" | "outcome" | "spec" | "verified" (anything else is refused: never the system's own answers); by: who; evidence: stored ids, quotes, steps; derived_from: premise item ids (the retraction cascade follows them); supersedes: the id of the producer's previous version; reconfirm_after: clock units until it needs re-confirmation (default RECONFIRM_DEFAULTS); valid: (since, until) in the world, as you count time; level: a guarantee level (for "verified"); of: the stored decision a "verified" item is (checked in the store's TraceStorage); shadow: passed to the write gates (a shadow measurement for a behaviour-changing item).
A fact or an episode the gates admit is present at once; a rule, skill or action the gates admit is promoted (its verdicts recorded); one a later gate holds stays a hypothesis (a "held" entry says why).
promote ¶
A behaviour-changing item passed its gates (or a person promotes it): it becomes a fact (measurements kept).
retract ¶
Take an item back, with everything derived from it (the cascade over derived_from); what it refuted or disputed comes back. Nothing is deleted: the journal keeps the entry and the chain stays whole. → {id: (status before, status after)} of every item whose status changed.
rollback ¶
Supervision undoes an update: retract iid; the version it superseded or refuted comes back — as a fact, or
only as a hint while a flag covering iid (or its scope) is pending: a stale version is never restored as a fact.
→ the status changes (as retract).
retire ¶
The item's producer no longer stands behind it (no longer compiled, no longer offered): expired.
reconfirm ¶
Mark one item for re-confirmation (a flag on it alone) → the flag's id.
flag ¶
A drift / open-set flag: the items it covers — ids, every item whose scope falls under scope, or the
items on key — learned before it are hints, not facts, until a newer observation or a person confirms each
(or end_flag). → the flag's id (its journal position).
end_flag ¶
The flag is resolved (re-confirmation done, a person cleared it): its items are facts again if nothing else holds them back.
resolve ¶
A person's answer to a dispute on key (an item's key, as disputes() lists it): value wins, the other
sides are refuted.
tick ¶
The store's clock moved by k (decisions on a stream, moves in an environment): reconfirm_after counts it.
used ¶
Decisions used these items (wrong=True: and were found wrong): counts kept in each item's confidence.
note ¶
A journal entry that changes nothing (a gate's rejected measurement, a reason): recorded and chained.
upstream ¶
Items whose state can change the state of ids: premises (transitively) and same-key competitors.
component ¶
The connected component(s) of ids: premise edges both ways and shared keys.
status ¶
The item's status (STATUSES); "retracted" for an item with no live support (retracted, or derived from one).
stale ¶
Must this item be re-confirmed before System 1 answers on it alone? Reads the pending flags (and the clock's expiry) — not the status, which a later write could have set back.
find ¶
Records of the items that match every filter given (status: one or a tuple of STATUSES).
disputes ¶
The open disputes (person questions not resolved yet) → [{"question", "key", "items", "opened_at"}].
snapshot ¶
What a decision is given, as one plain fact: the items that match (about: a subject or a list of them;
relation; scope; kinds, default every kind) — "facts" (active and not stale) and "hints" (hypotheses,
expired or stale items, with why) — the ids they rest on, the store's fingerprint and journal position, and the
query (so redecide can rebuild it). Disputed, refuted and retracted items are not given.
fingerprint ¶
A hash of what the store believes: every present item with its status, rank, support and time range.
report ¶
What was learned and from whom, what is refuted, retracted, expired, disputed, flagged → a dict.
redecide ¶
The stored decisions that rested on retracted items, re-run on their re-built snapshots.
storage: the decisions' TraceStorage; retracted: the retracted item ids; decide: init_state → {question: answer} (a function, or a System: its ask, not stored); fact: the given fact the snapshot was passed as. A decision is listed when its recorded snapshot changes once the retracted items' entries are left out of the journal up to its position; each is re-run on the old and the new snapshot. → (answer_changes, justification_only): lists of {"id", "old", "new"} — the first goes to a reviewer, the second is recorded.
key_of ¶
Items whose body has a subject "s" and a relation "r" have a key: one value per (scope, s, r) at a time.
item_id ¶
The content id of an item: the same knowledge written twice is one item.
scope_matches ¶
Does an item's scope fall under a flag's scope (every key of pattern has the same value in scope)?