The page-scoped prompt: the unit of work is the term the reader is looking at.
vaelii.impl.llm.selection prompts about lines the reader picked and asks for them
back edited. This namespace prompts about a term page — /term?q=penguin — and asks
for knowledge the KB does not have yet:
genl neighbourhood licenses
(vaelii.impl.llm.inventory) — arity and argument types included,Three things differ from the edit path, each because it was measured:
output-schema, Ollama's format). On generation this
rescues models that otherwise answer in markdown prose; on the edit path the same
parameter silently drops lines, so the two contracts are deliberately different and
are not unified.genl edge or a
rule, not a fact about an individual, so the prompt asks for those shapes and shows
them.The prompt's one job beyond the shape is to stop the model coining vocabulary — see
vaelii.impl.llm.inventory, which is where both guards against that live.
The page-scoped prompt: **the unit of work is the term the reader is looking at.**
`vaelii.impl.llm.selection` prompts about lines the reader picked and asks for them
back edited. This namespace prompts about a *term page* — `/term?q=penguin` — and asks
for knowledge the KB does not have yet:
1. what the page already says about the term, as bare sentences,
2. the vocabulary that term's `genl` neighbourhood licenses
(`vaelii.impl.llm.inventory`) — arity and argument types included,
3. the reader's free-text instruction ("flesh out the capabilities of this").
Three things differ from the edit path, each because it was measured:
* **The context is dropped.** A page is already about one context, so the caller
supplies it and the model writes bare sentences. That removes a whole class of
answer the model gets wrong for no gain — and it shortens every line it writes.
* **Decoding is constrained** (`output-schema`, Ollama's `format`). On generation this
*rescues* models that otherwise answer in markdown prose; on the edit path the same
parameter silently drops lines, so the two contracts are deliberately different and
are not unified.
* **The content is type-level.** Common sense about a *kind* is a `genl` edge or a
rule, not a fact about an individual, so the prompt asks for those shapes and shows
them.
The prompt's one job beyond the shape is to stop the model coining vocabulary — see
`vaelii.impl.llm.inventory`, which is where both guards against that live.(assertion-entry sentence context strength)One read sentence -> the [sentence context opts?] entry vaelii.core/edit takes,
with the caller's context supplied. strength rides across as
{:strength :monotonic} when the model claimed the assertion is known-true; a default
needs no opts, since that is assert's own default.
One read sentence -> the `[sentence context opts?]` entry `vaelii.core/edit` takes,
with the caller's context supplied. `strength` rides across as
`{:strength :monotonic}` when the model claimed the assertion is known-true; a default
needs no opts, since that is `assert`'s own default.The JSON schema Ollama's format constrains decoding to — the contract on this
path, unlike the edit path where it is an opt-in optimization.
Measured: constrained decoding is what makes generation work at all on a local model.
Models that answered a generation request with a markdown essay produce clean
s-expressions under this schema, and the strongest coder model went from nothing usable
to a full answer. An object per assertion, never a bare string, so the sampler
cannot choose its own line shape; sentence is one s-expression and carries no
context — the caller supplies that.
The JSON schema Ollama's `format` constrains decoding to — **the contract on this path**, unlike the edit path where it is an opt-in optimization. Measured: constrained decoding is what makes generation work at all on a local model. Models that answered a generation request with a markdown essay produce clean s-expressions under this schema, and the strongest coder model went from nothing usable to a full answer. An **object per assertion**, never a bare string, so the sampler cannot choose its own line shape; `sentence` is one s-expression and carries **no context** — the caller supplies that.
(page-context rows given)The context new assertions are filed in: the caller's :context when given, else the
context most of the page's own sentexes are in, else UniverseContext.
A modal context is the honest default — a page about penguin whose sentexes sit in
OrganismContext is a page about OrganismContext — and ties break on the context name so
the choice cannot depend on arrival order. The vocabulary head is never chosen: a term
carries derived bookkeeping there ((arity penguin 1), (unaryPredicate penguin)) which can
outnumber its definitional sentexes, and new domain knowledge does not belong in the
microtheory that defines the vocabulary. Reported back by
vaelii.impl.llm.session/propose-page, because which context knowledge lands in is a
decision a reviewer must see.
The context new assertions are filed in: the caller's `:context` when given, else the context most of the page's own sentexes are in, else `UniverseContext`. A modal context is the honest default — a page about `penguin` whose sentexes sit in `OrganismContext` is a page about `OrganismContext` — and ties break on the context name so the choice cannot depend on arrival order. The **vocabulary head is never chosen**: a term carries derived bookkeeping there (`(arity penguin 1)`, `(unaryPredicate penguin)`) which can outnumber its definitional sentexes, and new domain knowledge does not belong in the microtheory that defines the vocabulary. Reported back by `vaelii.impl.llm.session/propose-page`, because which context knowledge lands in is a decision a reviewer must see.
(stored-lines kb term)(stored-lines kb term {:keys [max-lines] :or {max-lines 40}})What the term page shows, as [{:handle :sentence :context :line} …] — every stored
sentex mentioning the term, bounded by :max-lines (40) and sorted by content so the
prompt is a function of the KB rather than of index order.
Rendered as bare sentences: the context is deliberately absent, because the answer
shape has no context in it either and showing one invites the model to write one. A
rule keeps its set/*Rule wrappers, since that is how its direction and defeasibility
are written. An exceptWhen meta-sentex is left out — it names the rule it qualifies by
raw handle, which is engine bookkeeping and not something to show a model, let alone ask
it to imitate.
The read is the inverted term index walked lazily, so a term mentioned by a million
sentexes costs max-lines record fetches.
What the term page shows, as `[{:handle :sentence :context :line} …]` — every stored
sentex mentioning the term, bounded by `:max-lines` (40) and sorted by content so the
prompt is a function of the KB rather than of index order.
Rendered as **bare sentences**: the context is deliberately absent, because the answer
shape has no context in it either and showing one invites the model to write one. A
rule keeps its `set/*Rule` wrappers, since that is how its direction and defeasibility
are written. An `exceptWhen` meta-sentex is left out — it names the rule it qualifies by
raw handle, which is engine bookkeeping and not something to show a model, let alone ask
it to imitate.
The read is the inverted term index walked lazily, so a term mentioned by a million
sentexes costs `max-lines` record fetches.The instruction half of the page-scoped turn — static, because everything KB-specific rides in the user turn.
It carries four things the model gets wrong without them: that a claim about a kind
is a rule or a genl edge rather than a sentence with a loose variable, that the
context is not the model's to write, that detail belongs in arguments and not in
predicate names, and that the vocabulary on the card is there to be reused.
The instruction half of the page-scoped turn — static, because everything KB-specific rides in the user turn. It carries four things the model gets wrong without them: that a claim about a *kind* is a rule or a `genl` edge rather than a sentence with a loose variable, that the context is not the model's to write, that detail belongs in **arguments** and not in predicate names, and that the vocabulary on the card is there to be reused.
(user-turn kb term rows context instruction)(user-turn kb
term
rows
context
instruction
{:keys [max-assertions] :or {max-assertions 24} :as opts})The volatile half: the page's term, its own stored sentences, the vocabulary card, the context new assertions land in, and the reader's instruction — instruction last, so it is the newest thing in the window.
opts is passed through to vaelii.impl.llm.inventory/inventory and render
(:max-predicates, :max-types, :max-tokens, …) and to stored-lines
(:max-lines). :max-assertions (24) caps what is asked for, which is what bounds
the answer's length and so its latency.
The volatile half: the page's term, its own stored sentences, the vocabulary card, the context new assertions land in, and the reader's instruction — instruction last, so it is the newest thing in the window. `opts` is passed through to `vaelii.impl.llm.inventory/inventory` and `render` (`:max-predicates`, `:max-types`, `:max-tokens`, …) and to `stored-lines` (`:max-lines`). `:max-assertions` (24) caps what is asked for, which is what bounds the answer's length and so its latency.
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 |