Notable changes to vaelii, newest first. Versions follow
semantic versioning; pre-1.0, a Breaking
entry raises the minor. What each class means, and why a Refusal is patch-eligible,
is CONTRIBUTING.md §3.
Releases before 0.17.0 are summarized rather than reproduced. Each one keeps its
title, its class census and every *Breaks:* token, so an upgrade across several
releases is still a grep for the name you call. The full entry prose for a released
version is in this file's git history, at the tag of the release that shipped it —
git show v0.16.0:CHANGELOG.md.
Under :refuse, a declaration arriving after the content it convicts decides the
clash. A disjoint, disjoint_metatype, genl-edge, functional, asymmetric,
anti_transitive or functionalInArg declaration landing over stored facts it convicts
now defeats the weaker side, or reports an equal-strength set in contradictions, under
the default :refuse policy as under :arbitrate. :refuse filed such a clash in
violations and kept both sides believed, while a recover of the same records decided
it, so a KB believed one thing live and another after a restart. A clash only a common
descendant context sees is still reported, not decided, under :refuse.
Class: Breaking (a :refuse KB whose schema arrives last disbelieves the weaker
member, and reports the pair in contradictions or conflicts rather than
violations). Migration: read a late-declaration clash off contradictions /
conflicts rather than violations; state both sides at equal strength to keep both
believed. docs/nmtms.md, docs/contexts.md
Breaks: :refuse, violations
A rule map has no :sentence; its :antecedent and :consequent are the rule. A
rule record held its whole (implies (and …) …) form beside the antecedent vector and
the consequent it was split into, and about half the engine's rule readers re-split the
form rather than reading the fields. The record drops the sentence slot, and every
reader takes the fields; sentence-of (new, public) builds the canonical implies
form from them, and readable-sentence the same form in the author's variable names.
The daemon serves sentence-of as the :sentence-of op, which takes no KB.
The trie key is built from that same form, so an index written before this change reads
unchanged. A disk frame drops the field (new rule tags; older frames decode by reading
past it): a rule frame on the plain codec is 132–143 B where it was 219–238 B on the
three corpora measured, and a RuleSentex is 72 B on the heap where it was 80 B, before
counting the implies form it no longer holds. An export dump's rule frame still
carries :sentence, so the dump format is unchanged. A negated rule
(not (implies …)), which assert already refuses, is now refused by the constructor
too, since a record with no sentence has no place for the sign. Class: Breaking (sentex, sentexes-matching, canonical-sentex and the
extent readers return rule maps without :sentence, and the daemon's wire records lose
the key). Migration: a caller that read a rule's (:sentence s) calls (sentence-of s), or (readable-sentence s) for display; a caller that split the sentence reads
:antecedent and :consequent. docs/api.md,
docs/storage.md
Breaks: sentex, sentexes-matching, canonical-sentex, :sentence
A sentex map has no :polarity key; a negative literal's :sentence is its sign.
Every literal carried :positive / :negative beside a sentence whose head not
already said the same, and every rule carried :positive. The records drop the slot,
and a disk frame drops the field: 10 B off every literal frame on the plain codec (53 to
91 B before), and no heap change, the 48 B LiteralSentex being aligned either way. A
store written with the polarity field reads unchanged. The index fingerprint and the
koinii locator digest the same sign keyword as before, so an index dump and a locator
stay valid. Class: Breaking (sentex, sentexes-matching, canonical-sentex
and the extent readers return maps without :polarity, and the daemon's wire records
lose the key). Migration: a caller that read (:polarity s) tests the sentence
instead — (= 'not (first (:sentence s))) is :negative — and a rule has no sign of
its own. docs/api.md, docs/storage.md
Breaks: sentex, sentexes-matching, canonical-sentex, :polarity
bravely and cautiously classify the dilemmas without an ASP backend. With no
backend reachable, the :brave-cautious reasoner reported every contested datum
:supportable, so bravely held for each and cautiously for none. It now reads
label/classify-local, which enumerates the dilemmas' minimum resolutions from the JTMS
dependency graph and classifies each believed datum a resolution moves: :true when
every resolution keeps it, :supportable when some do, :false when none do. So a
conclusion drawn from both sides of one dilemma is cautiously true, and a member that
two coupled dilemmas both rebut is neither brave nor cautious. Three new switches cap the
enumeration — VAELII_CLASSIFY_MAX_CLUSTER_MEMBERS (default 12),
VAELII_CLASSIFY_RESOLUTION_BUDGET (20000) and VAELII_CLASSIFY_MAX_JOINT_OPTIMA
(1024) — and a datum past any cap stays :supportable. The classification reads the
justification graph and never re-evaluates an unknown antecedent, so a conclusion an
unknown condition decides is read from current belief. With a backend reachable the
prover still reads classify-program, whose program holds each member as an independent
choice, so on coupled dilemmas it reports every member :supportable.
Class: Breaking (without a backend, cautiously now answers true and bravely
false where the documented degradation answered false and true). Migration: a caller that read
bravely / cautiously without a backend as "every contested datum is one of several
options" reads the classification instead; with a backend reachable the answers are
unchanged. docs/labeling.md, docs/operations.md
Breaks: bravely, cautiously
A justification names its rule once, as :informant, and carries no :out. A
rule firing's justification listed the rule handle both as :informant and among
:antecedents, and every justification carried an :out set nothing ever filled.
:antecedents now holds only what the firing matched and the edges it read; the TMS
treats a rule-handle informant as an implicit antecedent, so validity, retraction and
defeat of the rule withdraw its conclusions exactly as before, and why-not's
:missing still names an OUT rule. A justification frame on disk is six fields where
it was seven, 2.6–3.0 B smaller on the three corpora measured; a store or dump written
with seven-field frames reads unchanged, the rule stored once. Class: Breaking
(justification, supporting-justifications and dependent-justifications return
records whose :antecedents no longer contain the rule handle and which have no :out
key). Migration: a caller that looked for the rule among :antecedents reads
:informant, which is the rule's handle whenever it is an integer; a caller that read
:out drops the read. docs/nmtms.md, docs/naf.md
Breaks: justification, supporting-justifications, dependent-justifications
A :disk-snapshot KB installs a belief image in place of recover. After a full
recover, and at close when the records moved, a :disk-snapshot KB on the dense network
writes its whole belief state — the network, the taxonomy and the KB atoms recovery
fills — to <dir>/belief/. The next open installs that image instead of recovering when
its stamp equals the KB's: the records' fingerprint, the source identity (a digest of the
engine source that derives belief, comments and docstrings excluded) and the belief
policies. A KB with a registered prover or evaluatable takes no image. export! writes
the image into the dump's belief/ directory by default (:belief? false omits it), and
import! with {:belief? true} installs it in place of the recover when the import kept
every handle; the import summary's :belief-image reports which happened. The belief
certificate and its switch are gone.
Class: Refusal (vaelii.belief.snapshot is refused at every spelling).
Migration: unset vaelii.belief.snapshot; a store opened as {:backend :disk-snapshot}
writes and installs the image with no switch.
docs/storage.md, docs/api.md,
docs/defenses.md
Breaks: vaelii.belief.snapshot
A genlCx cycle is refused at assert, like a genl cycle. A cycle between two
contexts that see each other was admitted before — genlCx-problems checked only the
self-edge — so an edge whose super already saw its sub closed a mutually-visible
component. genlCx-problems now reads the global genlCx closure (tax/genlCx?-global,
the twin of genl?-global) and refuses that edge with :not-well-formed, so the context
hierarchy is a partial order like the type hierarchy. A cycle still reaches the taxonomy
another way and is still condensed: recovery/recover replays a stored edge past the
assert checks, so a store an older or foreign writer left with a genlCx cycle loads and
ranks over its condensation as before. Class: Refusal (a cycle-closing genlCx edge
that asserted before now throws). Migration: an ontology stating mutual visibility
between two contexts through a genlCx cycle models it another way — a context is where a
sentex is stored, and the two stay distinct records — while a recovered or foreign store
holding such a cycle is unaffected. docs/contexts.md,
docs/taxonomy.md
Breaks: genlCx
Three write paths stored a record no belief-filtered read could find — an inert NAT, a
bulk symmetric mirror, and canonical-sentex's key — and a NAT-shaped type node threw
the disjointness audit. A reifiable compound reached the store unresolved on a path
below assert, leaving a record reachable by its handle and by a CxEverything read and
by nothing a query reifies to. assert-inert stored (likes Rex (FruitFn Apple)) as
written, so assert of the same sentence minted (likes Rex nat/…) at a second handle,
count-with-functor answered 2 for one proposition, and the reads split across two
spellings; it now resolves a ground reifiable NAT to its stored constant first (dedup,
never mint), as handle-of and sentexes-matching do, and refuses a NAT this KB never
minted (:unminted-nat), since minting a termOfUnit is a belief-carrying side effect
the entry point never has. bulk-assert-facts! under (symmetric P) stored the mirror of
a stored literal as a second record, because the fast path skips the dedup probe and the
caller who wrote (siblingOf Bob Ann) cannot know it canonicalizes onto a stored
(siblingOf Ann Bob); a symmetric functor now keeps the probe (one taxonomy read per row
for a rare mark), so the bulk result is again identical to loading the facts one-by-one.
canonical-sentex returned the compound for a NAT sentence though its docstring promises
the key assert stored, and now reifies for read and agrees with handle-of, documenting
that a NAT with no minted constant has no canonical stored form yet. disjointness-audit
sorted (types kb) with bare sort, and compare throws on a list, so a KB with a NAT
type node threw a bare ClassCastException; it orders by by-print-key now, as
disjoint-line already does. Class: Refusal (assert-inert turns a previously-
stored unminted-NAT compound into :unminted-nat; the bulk dedup, the canonical-sentex
agreement and the audit ordering are fixes). Migration: nothing for a caller whose inert
NATs already have a stored constant; a caller storing a not-yet-minted reifiable compound
inert asserts the NAT-bearing fact first, which mints it, then stores it inert.
docs/nat.md, docs/canonicalization.md
Breaks: assert-inert
A constraint rule may not spell an internal solve marker as its consequent.
cardAtMost, cardAtLeast, minimizeCost and softPriority are the consequent markers
the answer-set surfaces normalize into — asp/atMost / asp/atLeast and their soft
twins, asp/minimize, and a priority-tagged set/softConstraint. A hand-written marker
skipped the surface's operand checks, so (set/hardConstraint (implies (pickCity ?a ?c) (cardAtMost ?a ?c))) stored, and do/label then threw a bare ClassCastException
reading ?a's binding as the count. rules/refuse-internal-marker refuses such a rule at
assert with :not-well-formed, names the surface form to write, and check reports the
same problem. Class: Refusal (a hand-written cardAtMost / cardAtLeast constraint
consequent that asserted before now throws). Migration: write the surface form —
(asp/atMost k ?counted pattern) in place of (set/hardConstraint (implies pattern (cardAtMost k ?counted))), and the soft twins in place of set/softConstraint; the surface
normalizes into the same stored rule, so the handle is unchanged, and a KB exported with
export-text! already spells the surface. docs/solving.md
Breaks: cardAtMost, cardAtLeast
asp/minimize and a priority on set/softConstraint give a solve a weighted,
prioritized objective. (asp/minimize priority ?weight body) adds ?weight to the
objective at level priority for every binding of body, whose choice literal names
the chosen head and whose background literal binds the weight — clingo's
#minimize{ W@P, … }. (set/softConstraint priority (implies …)) places an ordinary
soft constraint at a level other than 1. Distinct priorities are distinct lexicographic
minimize levels above the keep-belief and tiebreak levels, so a lower priority breaks
ties among the higher level's optima and never trades against it. assert refuses a
priority that is not a positive integer, a weight slot that is not a variable the body
binds, and a priority on set/hardConstraint, as :not-well-formed, and check reports
each. Grounding refuses a weight a background fact binds to anything but an integer
inside the solver's 32-bit range, naming the weight. export-text! writes both forms as
authored. Class: Additive. docs/solving.md
A :disk-snapshot open declines an image of records a clear! removed. The index
image and the belief image are stamped with a fingerprint of the record store's slots
(handle, offset, length), which reads no content. clear! truncates the logs, so
records of the same byte lengths written after it refilled the old slots exactly, and
the next open mapped the old index image or installed the old belief image over the new
records. clear! now mints a random epoch into the store's counters blob, and both
fingerprints carry it. A store no clear! has emptied carries no epoch, so the images
already on disk stay valid. Class: Fix. docs/storage.md
A defeat that releases an unknown antecedent or an exceptWhen exception
re-derives the conclusion it had blocked. Under (pp ?x) ∧ (unknown (happy ?x)) → (rr ?x), asserting (pp Zed), then a default (happy Zed), then a monotonic (not (happy Zed)) left (rr Zed) underived, while every order that asserted the negation
earlier derived it. The firing was placed, then blocked and swept when (happy Zed)
arrived. The defeat moves (happy Zed) OUT without removing it, and the swept firing had
left no blocked justification and no refusal record to re-ask. A settle pass now
re-chains every rule watching the predicate of a datum it newly defeated
(settle/released-by-defeat). Class: Fix (the belief docs/naf.md promises
order-independent). Migration: none. docs/naf.md
A genlCx edge arriving last exposes the functional, asymmetric,
anti_transitive or functionalInArg clash it reveals. A mark in one context and two
clashing facts together in another form a clash only once a genlCx edge lets the facts'
context see the mark's. With the edge arriving after both, neither the :refuse exposure
pass nor the :arbitrate deciding path found the clash, so belief depended on arrival
order. The exposure pass read the marks visible to the edge's super context, which gains
no new sight; it now reads them from the sub context. The deciding path reached only
disjointness memberships from a genlCx edge, and now reaches the marked facts as well,
within the same budget. Class: Fix (the order independence docs/nmtms.md
promises). Migration: none. docs/nmtms.md,
docs/contexts.md
Retracting one functionalInArg position of a predicate retires the clashes only that
position convicted. The clash memo keyed its vocabulary on the set of predicates
carrying a functionalInArg declaration, and a predicate may carry several positions.
Retracting one position while another remained left the key unchanged, so
contradictions and conflicts kept reporting a pair only the retracted position
convicted. The key is now the table from each predicate to its positions.
Class: Fix. Migration: none. docs/nmtms.md
assert of (disjoint a b) refuses a genl-related pair only where the asserting
context sees the edge. The overlap check read the global genl closure, so the refusal
fired in a context where an except hid the bridging edge and the scoped (genl a b)
query answered empty. The check now reads the closure the asserting context sees, and
admits the pair where an except hides the edge. The genl cycle check and disjoint?'s
own genl-relatedness guard stay global. Class: Fix (a disjoint refused before
now stores where the scoped query finds no genl edge between the pair).
Migration: none. docs/taxonomy.md
close! releases a KB's rete alpha memories and its derived RAM index, and a failed
open-kb releases the directory lock it took. The alpha-memory registry held each KB
it tracked by a strong key and released nothing. A disk-backed KB with a derived index
(:disk-dense, :disk-columnar, :disk-memory) kept that index in a process-wide
registry keyed by its directory after close!. A process that opened KBs in a loop
therefore kept one alpha memory and one derived index per KB it had closed. The registry
now keys each KB weakly, and close! drops the KB's alpha memories and its derived
index; both rebuild from the records on the next use. The alpha memories register as the
:rete-alpha cache, which the memory-pressure guard may drop. An open-kb that threw
after its durable stores resolved — a stale-index refusal, a :pg identity mismatch, a
recover over a corrupt store — held the directory's exclusive lock until the JVM exited,
and no later open of that directory succeeded. open-kb now closes the directories the
call opened when construction throws. Class: Fix. Migration: none.
docs/api.md, docs/caches.md
The web /kbs/load route opens a disk store with the backend its layout names. The
route opened every store as :disk-log, so a store with a derived index
(:disk-columnar, :disk-snapshot) opened with 0 sentexes and gained an empty
index/kv.log. The route now reads the store's index/ directory: trie.csr opens
:disk-snapshot, kv.log opens :disk-log, and neither opens :disk-columnar, which
rebuilds its index on open. The open passes :recover? :auto, so a stored belief image
installs when its stamp matches. Class: Fix. Migration: none.
docs/catalog.md, docs/web.md
14 entries — 2 Refusal, 4 Additive, 6 Fix. Every bounded entry point refuses a value
outside its domain by name, reading one shared domain table, and assert-inert refuses an
open sentence. The upper ontology divides thing by space and time, renames
spatial_thing and temporal_thing to spatial and temporal, and adds a CxUniverse
collector context. A process-wide cache profile scales every derived cache's bound, and a
memory-pressure guard the servers install shrinks the caches as the old generation fills
and grows them back as it drains. A reified NAT or context constant is named by the
SHA-256 of its expression, so the same expression reifies to the same constant across
processes, and the one-shot clingo solve injects its ground program through the backend
accessors rather than a temp file.
Breaks: :counters?, :believed?, :max-cost, :max-depth, :max-term-growth, add-evaluatable, assert-inert, describe, why-not, spatial_thing, temporal_thing
15 entries — 2 Breaking, 1 Refusal, 9 Additive, 3 Fix. Assertive argument types become
the default reading: an arg / genlArg / interArg declaration mints the type it
constrains rather than only testing for it. A bare implies rule defaults to :backward
and materializes nothing, and set/forwardRule adds forward chaining to the backward use
rather than replacing it, so a rule forward-chains only where its author asks. The arity
vocabulary gains a runtime floor — a variable-arity application below its arityMin is
refused — and admitsArgnum answers a position query from the declared arity. New
declaration vocabulary types a whole variable-arity tail (args, argsGenl, argAndRest,
argAndRestGenl) and names an intersection kind that derives its taxonomy edges, and new
readers report the brave and cautious status of a labeling dilemma, a cardinality bound over
ASP choice heads, and the subsumption status of every type pair. A state-of-affairs and
causality cluster joins the upper ontology in CxAbstract.
Breaks: VAELII_ASSERTIVE_ARG_TYPES, (implies asserted bare, set/forwardRule,
arityMin, (lessThan, (greaterThan, (termsRelated, (functionCorrespondingPredicate
14 entries — 1 Breaking, 4 Refusal, 4 Additive, 5 Fix. A declaration that restates
what the taxonomy already concludes turns that conclusion into a precondition, so the
arrival order of two assertions decides which facts a KB holds. Four entries retire such a
declaration — on genl, on fifteen unary marks, on six arity marks, and in the predAll
pair's third argument — and the arity vocabulary underneath is rebuilt so relation is
the common parent of predicate and function and every relation lands in exactly one
arity policy. predAllSpecified and predSpecifiedAll go binary and derive the filler
type from the predicate's own slot contract. Three composite function marks — injection,
surjection and bijection — arrive as one declaration each, a genlCx edge's merge
sweep stops growing with the KB, and a late symmetric declaration folds a mirrored pair
no earlier version could fold.
Breaks: (predAllSpecified, (predSpecifiedAll, specified-violations,
all-specified-violations, (binary_predicate P) beside (variable_arity P),
:arg-type, *assertive-arg-types?*, VAELII_ASSERTIVE_ARG_TYPES,
(genlArg genl 1 thing), (arg symmetric 1 predicate), (arg functional 1 predicate)
18 entries — 3 Breaking, 1 Refusal, 7 Additive, 7 Fix. The predAll quantifier
family lands in all eight cells. Three refusals stop answering with the wrong keyword:
an unpinned indeterminate term is not provably different from anything, a missing
adapter is not an unknown backend, and a wrong operand count is not an unknown option.
Declarations arriving after the facts now reach them — a (symmetric P) mark folds
records already stored, a computed genlCx edge runs the reconcilers a stated one runs,
and quotedArg is answered along the genl closure. Every refusal declares what its
ex-data carries, and a throw that drops a key fails the build.
Breaks: (different, indeterminate_term, :unknown-backend, :sqlite, :pg,
:unknown-option, :not-stratified
7 entries — 2 Breaking, 5 Additive. Definitional membership is answered at query
time rather than only by a forward rule. Two renames: the sentex polarity slot is
:polarity, and the AtomicSentex record is LiteralSentex. A unary predicate is
snake_case and assert enforces the spelling in both directions, which retired the
camelCase marks. CxCore names the expression kinds and gains a curation vocabulary.
Breaks: unaryPredicate, reifiableFunction, abduciblePredicate,
closedExtentPredicate, disjointMetatype, siblingDisjoint, warmBlooded, :truth
10 entries — 1 Refusal, 1 Additive, 5 Fix. The mapped index image becomes a backend
of its own, :disk-snapshot, rather than a property of the disk store, and stops
carrying the argument roots into heap. The disk store's live-handle sets become
compressed bitmaps. The writer refreshes a drifted image mid-life and can be told not
to. A functionalInArg declaration arriving after the facts it convicts is reported
rather than silently late. Neither adapter shipped at this version; both stayed at
0.13.0.
Breaks: vaelii.index.snapshot, :argument-family-ceiling
93 entries — 5 Breaking, 12 Refusal, 32 Additive, 22 Fix. The largest release:
calendar time, joined queries and a sweep through the entry points that refuse.
CxChange ships an event calculus, calendar constructors give a date its own endpoints
so it orders itself, and a metric constraint narrows an interval relation. or is
accepted in a rule antecedent, stored as one rule per alternative, and refused as a
goal. Every search entry point takes a bound and the daemon holds them to its ceiling.
Twelve refusals close inputs whose acceptance stored junk, and the :disk and
:pg-disk pairings are renamed to say that both halves are out of core.
Breaks: :disk, :pg-disk, VAELII_TEST_BACKEND=disk, edit!,
edit-with-consequences!, apply-proposal!, contexts, count-in-context,
contextDenotingFunction, lein cli load, prove, provable?, query, argue,
forward-chain, ask, ask?, query-plan, abduce, sentexes-matching,
handle-of, assert, load-text!, lein cli assert, unaryPredicate,
binaryPredicate, ternaryPredicate, /kbs, lein serve --listen <flag>,
vaelii.client/client, :timeout-ms, :token, dereference, resolve-by-locator,
set-trust!, trust-of, display-name-of
99 entries — 3 Breaking, 3 Refusal, 7 Additive, 5 Fix. Query contexts, bulk loading,
and a literal's type. resultIsa and resultGenl become result and genlResult; the
four function marks classify what they mark, and the reifiability criterion is written
down. A records read stays lazy, and a proof's witness is one of its bindings. Three
reads that could not answer the question stop answering empty. First release of the two
adapters, com.vaelii/postgres and com.vaelii/sqlite, each at this version.
Breaks: resultIsa, resultGenl, reifiableFunction, unreifiableFunction,
quotingFunction, contextDenotingFunction, ist, :proof?, ?ctx,
qualitative-network, possible-relations, :arg-type, :quoted-arg-type, result,
genlResult, :arg-genl, character_string, :pg-disk, :dir,
:stale-index-records, register-modal-predicate!
67 entries — 2 Breaking, 4 Additive. Contradiction solving, arrival order, and the
durable log. antiTransitive convicts the chain it forbids rather than being declared
and deferred. Definitional collection relations tie membership to a defining condition,
and sibling disjointness lets a collection's specializations separate themselves, with
an escape hatch for a pair that must overlap. A computed predicate or function is
registered in one line.
9 entries — 4 Additive. Koinii: several agents coordinate over one shared knowledge
base, with belief projection for what each agent holds true. A context can be a reified
function application whose genlCx edges compute themselves. Mention-opacity arrives —
a quoting function reads its argument by spelling — and quotedArg types an argument
against a syntactic type. The argIsa, argGenl and interArgIsa spellings become
arg, genlArg and interArg.
15 entries — 5 Breaking, 8 Additive. The dense truth-maintenance network becomes the
default and gives a concurrent reader a consistent view. Four relation properties are
enforced rather than documented. A subsumption rests on its strongest route rather than
its shortest. An algebraic property becomes one predicate instead of a mark and a twin,
which retired the ...Predicate spellings.
Breaks: defeat-class
50 entries — 1 Breaking, 1 Additive. Predicates inherit down the hierarchy. A KB
whose declared hazards are unresolved refuses writes rather than accepting them
unchecked, and a derived record's teardown is refused where belief was never built.
check and check-edit answer for the entry point they mirror. Five refusals close
recovery paths that believed records the store did not hold.
Breaks: :unrecovered-kb, write-hazards, note-hazards!, contradictions,
violations, :constraint-exposure
2 entries. Contexts get one spelling. A context name is Cx-prefixed rather than
Context-suffixed, and the context-transitivity predicate is genlCx.
22 entries — 2 Breaking, 4 Refusal, 2 Additive. Stored rules become first-class: a
rule can conclude a rule, and a rule carries a handle, TMS support and retraction with
no rule-specific machinery. A capability claim about a kind is capabilityType and
about a member is hasCapability. A NAF guard written as a conjunction now guards, and
the strictest policy stops being the leakiest.
15 entries. Faster writes, more to watch. A settle pays for the region it moved rather than for what the KB holds. The arbitrating half of a bounded pass says when its budget stopped it. Four places where arrival order decided an answer are closed.
23 entries. Operating the engine as a service. The daemon authenticates and refuses
to bind an address without a token. One space number names a KB's stores, :space,
replacing the separate record and index spellings. context-size becomes
count-in-context, different descends into compound arguments, and a name can carry a
sense and a lexeme.
Breaks: :record-space, :index-space, docs/storage.md
33 entries. Correctness fixes against the four invariants. A conjunctive query could
answer nothing while each of its conjuncts answered, and no longer does. assert
refuses a sentence that is not an s-expression, an exceptWhen query's literals are
held to the naming invariants, and an edit! batch key nothing reads is refused.
29 entries. A type on every refusal: every ex-info the engine throws carries a
:type, and the daemon's refusal keywords become plain. Both servers hold one
request-body ceiling, and the browser serializes its writes. An ist form must have
exactly three elements.
17 entries. The public API boundary is drawn — six public namespaces, everything
else vaelii.impl.* and free to change. Every handle-taking function refuses a
non-handle. close! releases a durable KB's directory, an argument-constraint refusal
names its convicting declaration in content order, and the five sweeps start running in
CI.
The first public release.
Twelve dated entries before versioning began, one per day of the initial build: the whole stack on day one (2026-07-19), then order independence made an invariant, equality and a sudoku solved, sound negation as failure, performance fixes and an operational surface, denser storage measured first, OpenCyc in the engine's own format, reads scoped to the asking context, aggregation over query results, the gate (lint, suite and scaling), one entry point for backward chaining, and declarations that re-check what they change (2026-07-30).
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |