A small reitit-ring web browser over a KB:
/ the upper ontology (contexts, types, core predicates, disjointness) /stats KB-wide counts, contexts by size, and the reasoning-health ledgers /find?q=<pattern> the terms whose name matches, from the index's term roster /term?q=<term> every sentex containing the term, grouped by the index root that reaches it (functor / argument-position / context / term-index) /sentex/:id a sentex (literal or rule): its belief state (IN, or the why-not reason — superseded / defeated / unsupported), supports, dependents /justification/:id a justification: its supports (arguments) and dependent sentex /levels?q=<goal> the lookup-to-query stack: what each of the 8 levels answers /edit the multi-sentex editor (GET seeds it, POST saves) — a fragment /{term,find,levels}/rows one more page of a capped list, as bare rows
Run it with lein run -m vaelii.browser.web (serves a starter-loaded KB on :3000).
Handlers are pure request -> response, so they are testable without a server.
Every page is answered twice over: as a whole document, and — when htmx asks, which
is every navigation and search — as the #main fragment that actually lands. What a
page costs in KB reads is part of what this demonstrates, since the browser reads the
public surface alone and each read is a round-trip under --attach; see the view
section below and docs/web.md.
A small reitit-ring web browser over a KB:
/ the upper ontology (contexts, types, core predicates, disjointness)
/stats KB-wide counts, contexts by size, and the reasoning-health ledgers
/find?q=<pattern> the terms whose name matches, from the index's term roster
/term?q=<term> every sentex containing the term, grouped by the index root that
reaches it (functor / argument-position / context / term-index)
/sentex/:id a sentex (literal or rule): its belief state (IN, or the why-not
reason — superseded / defeated / unsupported), supports, dependents
/justification/:id a justification: its supports (arguments) and dependent sentex
/levels?q=<goal> the lookup-to-query stack: what each of the 8 levels answers
/edit the multi-sentex editor (GET seeds it, POST saves) — a fragment
/{term,find,levels}/rows one more page of a capped list, as bare rows
Run it with `lein run -m vaelii.browser.web` (serves a starter-loaded KB on :3000).
Handlers are pure `request -> response`, so they are testable without a server.
Every page is answered twice over: as a whole document, and — when htmx asks, which
is every navigation and search — as the `#main` fragment that actually lands. What a
page costs in KB reads is part of what this demonstrates, since the browser reads the
public surface alone and each read is a round-trip under `--attach`; see the `view`
section below and docs/web.md.(->form s)Read a ?q= / ?ctx= query param as EDN, or nil when it is not readable. Every
route that takes a term or a goal parses through this: the value is whatever a URL
carried, so ( is as likely as (dog Muffet) and an unguarded read throws a 500
rather than rendering a page.
Throwable, not Exception, for the reason the daemon's reader carries: a deeply
nested form overflows the reader's stack with a StackOverflowError, which is an
Error — and one that escapes here is a 500 from Jetty rather than the nil this
exists to return. A URL is long enough to carry the nesting.
Read a `?q=` / `?ctx=` query param as EDN, or nil when it is not readable. Every route that takes a term or a goal parses through this: the value is whatever a URL carried, so `(` is as likely as `(dog Muffet)` and an unguarded read throws a 500 rather than rendering a page. `Throwable`, not `Exception`, for the reason the daemon's reader carries: a deeply nested form overflows the reader's stack with a `StackOverflowError`, which is an `Error` — and one that escapes here is a 500 from Jetty rather than the nil this exists to return. A URL is long enough to carry the nesting.
(-main & args)Serve the browser.
lein run -m vaelii.browser.web ; a fresh starter-loaded in-process KB lein run -m vaelii.browser.web --port 8080 lein run -m vaelii.browser.web --listen 0.0.0.0 ; reachable off-machine (opt-in) lein run -m vaelii.browser.web --attach HOST PORT [WEBPORT]
--attach points the browser at a running daemon (vaelii.host.serve) and renders
the KB it owns over the API — the way to inspect a live daemon whose single-writer
lock forbids opening its store directly (docs/operations.md). Every page reads the
same, since app is written against the access facade (v), which dispatches each
read to the local KB or the remote daemon.
The KB it reads and the network interface it binds are independent axes: --listen says who
may reach the browser, --attach says whose KB it shows. The default is loopback,
and what it binds decides what it requires — the daemon's rule, on the daemon's
reasoning (guard/require-token!):
--listen names a non-loopback address ⇒ VAELII_API_TOKEN is required,
and every request then presents it as Authorization: Bearer <token>. Without one
it is a line on stderr and exit 2, a code of its own so a supervisor tells a
missing credential from the configuration typos above.--listen 127.0.0.1 said out loud — is unchanged:
no token, no header, no 401.Whichever KB it starts on is registered with the catalog and made active, so it
appears in /kbs beside the ones that can be loaded — the starter it opens with is not
a special case, it is entry number one.
Serve the browser. lein run -m vaelii.browser.web ; a fresh starter-loaded in-process KB lein run -m vaelii.browser.web --port 8080 lein run -m vaelii.browser.web --listen 0.0.0.0 ; reachable off-machine (opt-in) lein run -m vaelii.browser.web --attach HOST PORT [WEBPORT] `--attach` points the browser at a running daemon (`vaelii.host.serve`) and renders the KB it owns *over the API* — the way to inspect a live daemon whose single-writer lock forbids opening its store directly (docs/operations.md). Every page reads the same, since `app` is written against the access facade (`v`), which dispatches each read to the local KB or the remote daemon. The KB it reads and the network interface it binds are independent axes: `--listen` says who may reach the browser, `--attach` says whose KB it shows. The default is loopback, and what it binds decides what it requires — the daemon's rule, on the daemon's reasoning (`guard/require-token!`): - `--listen` names a **non-loopback** address ⇒ `VAELII_API_TOKEN` is **required**, and every request then presents it as `Authorization: Bearer <token>`. Without one it is a line on stderr and exit **2**, a code of its own so a supervisor tells a missing credential from the configuration typos above. - **Loopback** — the default, and `--listen 127.0.0.1` said out loud — is unchanged: no token, no header, no 401. Whichever KB it starts on is **registered with the catalog** and made active, so it appears in `/kbs` beside the ones that can be loaded — the starter it opens with is not a special case, it is entry number one.
(app target)The ring handler for a KB. Pure request -> response.
target is what each page reads: a KB, a remote access (v/remote), or a
holder — anything deref-able, yielding whichever of those is current
(vaelii.browser.catalog/holder). A holder is what makes the KB switchable: every
handler resolves it per request, so activating another entry re-points the whole
browser without rebuilding the handler.
This is the routing half only. What gets served is handler, which adds the
Host allowlist — a test drives app directly and supplies no Host at all.
The ring handler for a KB. Pure `request -> response`. `target` is what each page reads: a KB, a remote access (`v/remote`), or a **holder** — anything deref-able, yielding whichever of those is current (`vaelii.browser.catalog/holder`). A holder is what makes the KB switchable: every handler resolves it per request, so activating another entry re-points the whole browser without rebuilding the handler. This is the routing half only. What gets *served* is `handler`, which adds the `Host` allowlist — a test drives `app` directly and supplies no `Host` at all.
(assert-page view)(assert-page {:keys [kb sandbox] :as view} state result)The new-sentex page: the form, and — after a save — what it stored.
The new-sentex page: the form, and — after a save — what it stored.
(assert-post {:keys [kb sandbox] :as view}
{:keys [text ctx monotonic?] :as state})Assert what the new-sentex form holds: read the lines, check them all against the
KB, and — only when every one is admissible — apply them in one edit. Nothing
partial is ever written: a form with one bad line stores none of it, which is what
makes the page safe to retry.
A form addressed to the session's sandbox before the sandbox exists opens it first,
once the lines have read cleanly and before they are checked: the checks are
context-scoped, so a sandbox with no genlCx edge yet would see none of the shipped
vocabulary they are checked against. When the check then refuses the form, the edge
this call wrote is taken out again (sandbox/reset! over the empty extent), so a
refused form leaves the KB as it found it.
Assert what the new-sentex form holds: read the lines, check them all against the KB, and — only when every one is admissible — apply them in one `edit`. Nothing partial is ever written: a form with one bad line stores none of it, which is what makes the page safe to retry. A form addressed to the session's sandbox before the sandbox exists opens it first, once the lines have read cleanly and before they are checked: the checks are context-scoped, so a sandbox with no `genlCx` edge yet would see none of the shipped vocabulary they are checked against. When the check then refuses the form, the edge this call wrote is taken out again (`sandbox/reset!` over the empty extent), so a refused form leaves the KB as it found it.
(completions-page {:keys [kb] :as view} q)The terms a prefix could become, as the list the editor drops under the caret. It is
v/find-terms' prefix match over the term roster, so a keystroke costs the size of
the vocabulary and never a scan of the KB, and each hit carries the role colour its
term page and every sentence on the page already give it.
A blank prefix answers nothing rather than the first twelve terms in the KB, and one
past complete-q-cap answers nothing rather than scanning on behalf of whoever sent
it — the route is reachable per keystroke and, through the daemon, by anyone who can
reach the daemon.
The terms a prefix could become, as the list the editor drops under the caret. It is `v/find-terms`' **prefix** match over the term roster, so a keystroke costs the size of the vocabulary and never a scan of the KB, and each hit carries the role colour its term page and every sentence on the page already give it. A blank prefix answers nothing rather than the first twelve terms in the KB, and one past `complete-q-cap` answers nothing rather than scanning on behalf of whoever sent it — the route is reachable per keystroke and, through the daemon, by anyone who can reach the daemon.
(consequences {:keys [kb] :as view} heading batch)The consequence panel for batch ({:add [[sentence context] …] :remove [handle …]})
over the view's KB: v/preview capped at preview-max-results per group, rendered
under heading. A read — preview stores nothing and hands the KB back at the same
handles — but it asserts and rolls back to get there, so a route calling it is a
writer for the duration (an extension's :write route).
The consequence panel for `batch` (`{:add [[sentence context] …] :remove [handle …]}`)
over the view's KB: `v/preview` capped at `preview-max-results` per group, rendered
under `heading`. A read — `preview` stores nothing and hands the KB back at the same
handles — but it asserts and rolls back to get there, so a route calling it is a
writer for the duration (an extension's `:write` route).(current target)The KB a request reads. A holder (anything deref-able —
vaelii.browser.catalog/holder) yields whichever KB is active right now; a KB or an
access value is itself. Every handler goes through here, which is what lets the
browser switch KBs under a running server.
The KB a request reads. A **holder** (anything deref-able — `vaelii.browser.catalog/holder`) yields whichever KB is active right now; a KB or an access value is itself. Every handler goes through here, which is what lets the browser switch KBs under a running server.
(demo-apply kb sandbox op first-h)Do one step's write, and answer the first-handle to carry forward.
Split from the rendering because the page has to be built from a view taken after the write: whether the sandbox exists is a per-request read, and step 1 is the request that brings it into being.
Both adding steps open the sandbox first. Without its genlCx edge the sandbox
sees no shipped context, so CxBiology's flight rule would not be visible from it
and the write would derive nothing at all — the demo would quietly do nothing rather
than fail.
Do one step's write, and answer the `first`-handle to carry forward. Split from the rendering because the page has to be built from a view taken *after* the write: whether the sandbox exists is a per-request read, and step 1 is the request that brings it into being. Both adding steps open the sandbox first. Without its `genlCx` edge the sandbox sees no shipped context, so CxBiology's flight rule would not be visible from it and the write would derive nothing at all — the demo would quietly do nothing rather than fail.
(demo-page view)(demo-page {:keys [sandbox] :as view} first-h)The walkthrough: the script, the evidence for the conclusion under test, the next button, and what the KB currently holds about Pingu. Everything on it is read back out of the KB after the write, so the page cannot claim a state the engine is not in.
The walkthrough: the script, the evidence for the conclusion under test, the next button, and what the KB currently holds about Pingu. Everything on it is read back out of the KB *after* the write, so the page cannot claim a state the engine is not in.
(dev-repl)Start the browser for a REPL session and hand the prompt straight back.
What lein browser calls, and the only thing project.clj names. Port from
VAELII_WEB_PORT, else 3000 — the same read -main does; loopback only. A port
already in use is reported, not thrown — you asked for a REPL and you get one
either way, which is the difference between a busy port being an inconvenience and
being a failed startup.
Start the browser for a REPL session and hand the prompt straight back. What `lein browser` calls, and the only thing `project.clj` names. Port from `VAELII_WEB_PORT`, else 3000 — the same read `-main` does; loopback only. A port already in use is **reported, not thrown** — you asked for a REPL and you get one either way, which is the difference between a busy port being an inconvenience and being a failed startup.
(dev-stop)Stop the server dev-repl started. No !: it takes down a socket, not knowledge —
the KB is untouched and still at the prompt.
Stop the server `dev-repl` started. No `!`: it takes down a socket, not knowledge — the KB is untouched and still at the prompt.
(edit-preview-post {:keys [kb] :as view} handles text)What this save would do, without doing it: the same diff edit-post computes, read
through v/preview instead of v/edit!. preview hands the KB back at the same
handles, so this is a read and can run on a pause in the typing rather than behind a
confirmation.
A form that does not read is reported here too, which is what makes the panel a lookahead rather than a second opinion: the reader is told while the caret is still in the form that caused it, instead of on the far side of a save that did not go through. A named handle that holds no sentex is reported the way the save would refuse it.
The heading counts a changed handle as retracted only when retraction-plan says it
goes; one derived from what stays is counted as staying, since the save leaves it
stored. The plan reads the KB as it stands, before the save's own adds.
What this save would do, without doing it: the same diff `edit-post` computes, read through `v/preview` instead of `v/edit!`. `preview` hands the KB back at the same handles, so this is a read and can run on a pause in the typing rather than behind a confirmation. A form that does not read is reported here too, which is what makes the panel a lookahead rather than a second opinion: the reader is told while the caret is still in the form that caused it, instead of on the far side of a save that did not go through. A named handle that holds no sentex is reported the way the save would refuse it. The heading counts a changed handle as retracted only when `retraction-plan` says it goes; one derived from what stays is counted as staying, since the save leaves it stored. The plan reads the KB as it stands, before the save's own adds.
(find-page {:keys [kb] :as view} q)Term search over the KB's vocabulary: list every term whose name matches q, each
linking to its term page. q reads as re-find does — a bare dog finds every term
containing it, ^parent anchors — and it filters the index's term roster, so the cost
is the number of distinct terms rather than the number of sentexes.
A pattern that resolves to a single term jumps straight to that term's page —
either because it is the only match, or because the query names a term exactly
(so parentOf jumps even though it is a substring of grandparentOf). The jump
renders the term page and sets HX-Push-Url so the address bar reflects it. An
unusable pattern or an empty query reports gently.
Term search over the KB's vocabulary: list every term whose name matches `q`, each linking to its term page. `q` reads as `re-find` does — a bare `dog` finds every term containing it, `^parent` anchors — and it filters the index's term roster, so the cost is the number of distinct terms rather than the number of sentexes. **A pattern that resolves to a single term jumps straight to that term's page** — either because it is the only match, or because the query names a term *exactly* (so `parentOf` jumps even though it is a substring of `grandparentOf`). The jump renders the term page and sets `HX-Push-Url` so the address bar reflects it. An unusable pattern or an empty query reports gently.
(find-rows-page {:keys [kb] :as view} q offset)One more page of search hits — what the result list's continuation sentinel fetches.
One more page of search hits — what the result list's continuation sentinel fetches.
(fresh-starter-kb!)(fresh-starter-kb! opts)A KB freshly loaded with the starter ontology. Flushes the record + index
stores first, so a repeated run (or one over data from an earlier code version)
starts from a clean, deterministic state rather than re-asserting over stale
handles. For a persistent KB, construct one and call core/recover instead.
A KB freshly loaded with the starter ontology. Flushes the record + index stores first, so a repeated run (or one over data from an earlier code version) starts from a clean, deterministic state rather than re-asserting over stale handles. For a persistent KB, construct one and call `core/recover` instead.
(front-rows-page view section offset)One more page of a front-page list.
One more page of a front-page list.
(funnel-page {:keys [kb] :as view})Every forward rule and what chaining did with it — placed, refused (and why), or silent
— ranked by what is wrong (funnel-ranked), one page of cards at a time. A run form on
32's job registry populates it live.
Every forward rule and what chaining did with it — placed, refused (and why), or silent — ranked by what is wrong (`funnel-ranked`), one page of cards at a time. A run form on `32`'s job registry populates it live.
(funnel-rows-page {:keys [kb] :as view} offset)One more page of the funnel — what its continuation sentinel fetches.
One more page of the funnel — what its continuation sentinel fetches.
(handler target)(handler target {:keys [host] :or {host loopback}})What the browser actually serves: app behind the Host allowlist.
What the browser actually serves: `app` behind the `Host` allowlist.
(inference-page {:keys [kb] :as view} goal ctx depth)The search stepped through — a goal, a context and a depth in; the tree the node engine
builds out, plus the same goal raced across tacticians. Sits beside /levels: a goal
typed at either is answerable at both.
A depth is required (the node engine's termination is the bound and nothing else), so the form always carries one. A malformed goal, or one the search cannot run, is rendered rather than thrown — the page has no exception middleware.
The search stepped through — a goal, a context and a depth in; the tree the node engine builds out, plus the same goal raced across tacticians. Sits beside `/levels`: a goal typed at either is answerable at both. A depth is required (the node engine's termination is the bound and nothing else), so the form always carries one. A malformed goal, or one the search cannot run, is rendered rather than thrown — the page has no exception middleware.
(kbs-load id params)Start loading source id with the options the form submitted. An id the catalog
holds no source for reaches load-source all the same, so its :unknown-source
refusal — which names the ids there are — is the note kbs-post puts on the page.
Start loading source `id` with the options the form submitted. An id the catalog holds no source for reaches `load-source` all the same, so its `:unknown-source` refusal — which names the ids there are — is the note `kbs-post` puts on the page.
(kbs-page view)(kbs-page view note)The knowledge bases page: what is loaded, and what can be. note is what the catalog
said about the action that led here — a refusal is a state to show, not an error
status, since the page is still the right answer.
The knowledge bases page: what is loaded, and what can be. `note` is what the catalog said about the action that led here — a refusal is a state to show, not an error status, since the page is still the right answer.
(kbs-post act make-view)Perform a catalog action and answer with the page it changed.
The view is built after the action, not before: activating changes which KB the page reads, and rendering the one it was reading a moment ago would show the switch as not having happened. What the catalog refuses — a second concurrent load, a source already loaded, an entry whose loader has not yet stopped — comes back as a note on the page.
Perform a catalog action and answer with the page it changed. The view is built **after** the action, not before: activating changes which KB the page reads, and rendering the one it was reading a moment ago would show the switch as not having happened. What the catalog refuses — a second concurrent load, a source already loaded, an entry whose loader has not yet stopped — comes back as a note on the page.
(levels-page {:keys [kb] :as view} goal ctx)The lookup-to-query stack over a goal: what each of the eight levels answers, so the level at which results first appear is the mechanism the answer depends on. With no goal, the stack itself.
A vector goal is the conjunctive query prove takes, and the levels do not take
one — they answer about a literal. So a conjunction gets the join plan and stops
there, rather than being rendered through eight sections that cannot address it.
The lookup-to-query stack over a goal: what each of the eight levels answers, so the level at which results first appear is the mechanism the answer depends on. With no goal, the stack itself. A **vector** goal is the conjunctive query `prove` takes, and the levels do not take one — they answer about a literal. So a conjunction gets the join plan and stops there, rather than being rendered through eight sections that cannot address it.
(levels-rows-page view goal ctx lvl offset)One more page of results for a single level — what a level's continuation sentinel fetches.
One more page of results for a single level — what a level's continuation sentinel fetches.
(local-kb view)The in-process KB behind view, or nil when the browser reads a remote daemon
(--attach). What an extension checks before work that needs the KB in this process
— a preview, a write, dozens of reads a round-trip each would make slow.
The in-process KB behind `view`, or nil when the browser reads a remote daemon (`--attach`). What an extension checks before work that needs the KB in this process — a preview, a write, dozens of reads a round-trip each would make slow.
(network-page {:keys [kb] :as view} ctx calc)The constraint network a calculus computes over one context: which terms it relates, what still holds of every pair, whether the believed facts are satisfiable at all, and one concrete arrangement consistent with them.
Every calculus is offered whether or not its prover is registered — a network is a
property of the stored facts, and add-prover only decides whether ask consults it.
The constraint network a calculus computes over one context: which terms it relates, what still holds of every pair, whether the believed facts are satisfiable at all, and one concrete arrangement consistent with them. Every calculus is offered whether or not its prover is registered — a network is a property of the stored facts, and `add-prover` only decides whether `ask` consults it.
(reasoning-page {:keys [kb sandbox] :as view})The gallery. Every card is computed from the live KB on render; the ones with premises are computed from the sandbox once the reader has established them, and show a button until then.
The gallery. Every card is computed from the live KB on render; the ones with premises are computed from the sandbox once the reader has established them, and show a button until then.
(reasoning-run kb sandbox id)Establish one example's premises in the sandbox. A write, so a POST — and the
sandbox is opened first, exactly as the demo does: without its genlCx edge it
would see no shipped rule and the example would quietly derive nothing.
Establish one example's premises in the sandbox. A write, so a POST — and the sandbox is opened first, exactly as the demo does: without its `genlCx` edge it would see no shipped rule and the example would quietly derive nothing.
(register-extension ext-name ext)File ext under ext-name (a lower-case keyword), replacing any extension of that
name, and answer the name. Every key is optional:
:routes [["/ext/<name>/…" {:get f :post f :write f}] …] — each f is
(fn [view req] …) answering hiccup, which the browser sends as a
fragment, or a ring response map. :get runs as is; :post is refused
cross-origin; :write is a POST that runs under the browser's write
guard, with view over the KB the guard judged.
:term-panel (fn [view term] hiccup) — drawn last on every term page.
:on-start (fn []) — run when -main or dev-repl starts the server, before it
serves; for work that must not delay startup, start a thread.
:stylesheet a classpath resource, served at /ext/<name>.css and linked from every
page.
:script a classpath resource, served at /ext/<name>.js and loaded (deferred) by
every page.
File `ext` under `ext-name` (a lower-case keyword), replacing any extension of that
name, and answer the name. Every key is optional:
:routes [["/ext/<name>/…" {:get f :post f :write f}] …] — each `f` is
`(fn [view req] …)` answering hiccup, which the browser sends as a
fragment, or a ring response map. `:get` runs as is; `:post` is refused
cross-origin; `:write` is a POST that runs under the browser's write
guard, with `view` over the KB the guard judged.
:term-panel (fn [view term] hiccup) — drawn last on every term page.
:on-start (fn []) — run when `-main` or `dev-repl` starts the server, before it
serves; for work that must not delay startup, start a thread.
:stylesheet a classpath resource, served at /ext/<name>.css and linked from every
page.
:script a classpath resource, served at /ext/<name>.js and loaded (deferred) by
every page.(render-form view form)(render-form view form seen)(render-form view form seen depth)Render a sentence (or subterm) with every atomic subterm an individually role-colored link, structure shown with parentheses.
A (sentexHandle N) subterm renders as the sentence N holds, linked, rather than
as the integer: a reader shown (except (sentexHandle 41)) has been told a sentex is
hidden and not which one, and the handle is the one thing on the page they cannot look
up without leaving it. One branch covers every surface that prints a meta-sentex — a
term-page row, the sentex page, a preview's excepts line.
The expansion carries the ids already on the path, so a stored sentence naming a
handle that reaches back to it renders the back-edge rather than overflowing the
stack. seen holds terms for the reified-term walk, so a handle is marked with a
vector, which no term is.
Render a sentence (or subterm) with every atomic subterm an individually role-colored link, structure shown with parentheses. A `(sentexHandle N)` subterm renders as **the sentence N holds**, linked, rather than as the integer: a reader shown `(except (sentexHandle 41))` has been told a sentex is hidden and not which one, and the handle is the one thing on the page they cannot look up without leaving it. One branch covers every surface that prints a meta-sentex — a term-page row, the sentex page, a preview's `excepts` line. The expansion carries the ids already on the path, so a stored sentence naming a handle that reaches back to it renders the back-edge rather than overflowing the stack. `seen` holds terms for the reified-term walk, so a handle is marked with a vector, which no term is.
(retract-post {:keys [kb] :as view} handles)Retract the named handles through edit — one settle for the whole batch, the same
write path the editor's save takes. The answer deletes every row that is actually
gone out of band (the named handles and whatever the dependency-directed sweep took
with them), so the page corrects itself instead of reloading.
The write is preceded by the check-edit round-trip every other write post makes
(docs/operations.md): a stale handle — retracted out from under the page since it
rendered — comes back as the problem panel rather than reaching edit, which
refuses an unknown :remove handle outright.
Retract the named handles through `edit` — one settle for the whole batch, the same write path the editor's save takes. The answer deletes every row that is actually gone out of band (the named handles *and* whatever the dependency-directed sweep took with them), so the page corrects itself instead of reloading. The write is preceded by the `check-edit` round-trip every other write post makes (docs/operations.md): a stale handle — retracted out from under the page since it rendered — comes back as the problem panel rather than reaching `edit`, which refuses an unknown `:remove` handle outright.
(start target {:keys [port host] :or {port 3000 host loopback} :as opts})Start a Jetty server for target (a KB, an access value, or a catalog holder).
Returns the server (non-blocking). :host defaults to loopback; pass an address
("0.0.0.0") to bind publicly, which requires a token: :token, or
VAELII_API_TOKEN when the key is absent, as -main requires it
(guard/require-token!). It serves app as built: a reload does not reach
it (dev-repl is the server that follows one), and :reload? is refused.
Start a Jetty server for `target` (a KB, an access value, or a catalog holder). Returns the server (non-blocking). `:host` defaults to loopback; pass an address (`"0.0.0.0"`) to bind publicly, which requires a token: `:token`, or `VAELII_API_TOKEN` when the key is absent, as `-main` requires it (`guard/require-token!`). It serves `app` as built: a reload does not reach it (`dev-repl` is the server that follows one), and `:reload?` is refused.
(start-profiler)Start the sampling profiler's UI when the operator asked for one (VAELII_PROFILER)
and the class resolves. A no-op otherwise, and a logged line when the operator asked
and it is absent — a switch that reads as set and does nothing is the failure the
config namespace exists to prevent.
One UI, whoever asks. The claim is a compare-and-set! onto ::starting, so the
two ways a second one could be started are both closed: a namespace reload calling this
again (the defonce remembers the running server across it) and two threads calling it
at once (a test-then-act on the same state would let both past the test and race for the
port). A start that fails puts the state back, since nothing then holds the port and a
later call should be free to try again.
Bare, not !: it starts a server and destroys nothing. Called by both entry points,
so the variable means the same thing to lein browser as to lein run -m vaelii.browser.web; only the first has the dependency, which is what the second one's
log line says.
Start the sampling profiler's UI when the operator asked for one (`VAELII_PROFILER`) and the class resolves. A no-op otherwise, and a logged line when the operator asked and it is absent — a switch that reads as set and does nothing is the failure the `config` namespace exists to prevent. **One UI, whoever asks.** The claim is a `compare-and-set!` onto `::starting`, so the two ways a second one could be started are both closed: a namespace reload calling this again (the `defonce` remembers the running server across it) and two threads calling it at once (a test-then-act on the same state would let both past the test and race for the port). A start that *fails* puts the state back, since nothing then holds the port and a later call should be free to try again. Bare, not `!`: it starts a server and destroys nothing. Called by both entry points, so the variable means the same thing to `lein browser` as to `lein run -m vaelii.browser.web`; only the first has the dependency, which is what the second one's log line says.
(stats-page view)(stats-page view note)(stats-page {:keys [kb types] :as view} note clashes?)KB-wide statistics: the headline counts (contexts, types, stored sentexes, and the reasoning-health tallies), what the last chaining run did and a control to run another, a contexts-by-size table, and — when non-empty — the actual contradictions, conflicts, and dropped-derivation violations.
clashes? asks the standing disjointness question, which is computed rather than
filed and so is not asked unless the reader asks for it.
note is what a just-finished forward-chaining run reported, shown above the
numbers it changed.
KB-wide statistics: the headline counts (contexts, types, stored sentexes, and the reasoning-health tallies), what the last chaining run did and a control to run another, a contexts-by-size table, and — when non-empty — the actual contradictions, conflicts, and dropped-derivation violations. `clashes?` asks the standing disjointness question, which is computed rather than filed and so is not asked unless the reader asks for it. `note` is what a just-finished forward-chaining run reported, shown above the numbers it changed.
(stats-rows-page {:keys [kb] :as view} section offset)One more page of a stats-page list — what its scroll sentinel fetches. Every section is recomputed rather than carried: each is a function of the KB, so a continuation asks the same question the page asked and gets the same order.
One more page of a stats-page list — what its scroll sentinel fetches. Every section is recomputed rather than carried: each is a function of the KB, so a continuation asks the same question the page asked and gets the same order.
(stored-sentexes {:keys [kb] :as view} result)What a write stored, as the assert form shows it: a row per stored sentex, then the
callout of what followed from them (derived-callout). result is
v/edit-with-consequences!'s answer.
What a write stored, as the assert form shows it: a row per stored sentex, then the callout of what followed from them (`derived-callout`). `result` is `v/edit-with-consequences!`'s answer.
The browser's stylesheet, on the classpath (resources/public/vaelii.css).
The browser's stylesheet, on the classpath (resources/public/vaelii.css).
(term-link view t)(term-link view t seen)A role-colored link to a term's page (variables are not links; a reified term is its
expression — nat-ref).
A role-colored link to a term's page (variables are not links; a reified term is its expression — `nat-ref`).
(term-page {:keys [kb] :as view} term)A term's page: the concept graph, the three type lines, the sentexes grouped by the
index root that reaches them, and the panels a registered extension adds
(extension-panels).
What a term is, the page says by listing what the KB was told — the index groups —
and by drawing it, not by restating a closure in prose. A supertype line is a rendering
of genl sentexes the argument groups already hold, and on an imported ontology the
closures behind it run to six figures; the one reading of them a reader cannot get from
the rows is position, and that is the picture. vaelii.core/describe still answers
all six readings for a caller that wants them (docs/api.md).
Every part of the page is bounded, and each by its own budget: the index groups in rows
(group-cap), their root extents deferred to a reveal (group-sentexes), and the graph
in reads (graph-side-budget).
A term's page: the concept graph, the three type lines, the sentexes grouped by the index root that reaches them, and the panels a registered extension adds (`extension-panels`). **What a term is, the page says by listing what the KB was told** — the index groups — and by drawing it, not by restating a closure in prose. A supertype line is a rendering of `genl` sentexes the argument groups already hold, and on an imported ontology the closures behind it run to six figures; the one reading of them a reader cannot get from the rows is *position*, and that is the picture. `vaelii.core/describe` still answers all six readings for a caller that wants them (docs/api.md). Every part of the page is bounded, and each by its own budget: the index groups in rows (`group-cap`), their root extents deferred to a reveal (`group-sentexes`), and the graph in reads (`graph-side-budget`).
(term-rows-page {:keys [kb] :as view} term g offset)One more page of rows for index group g of term — what a group's continuation
sentinel fetches. The groups are recomputed and indexed the same way the page built
them, so g names the same group it did then.
One more page of rows for index group `g` of `term` — what a group's continuation sentinel fetches. The groups are recomputed and indexed the same way the page built them, so `g` names the same group it did then.
(tree-rows-page view pred node offset)One node's children, as bare rows — what a disclosure fetches when it is opened, and
what its show more sentinel fetches to extend it.
One node's children, as bare rows — what a disclosure fetches when it is opened, and what its `show more` sentinel fetches to extend it.
(unregister-extension ext-name)Take the extension filed under ext-name out of the browser; its routes, panel and
assets are gone from the next request. Answers the name.
Take the extension filed under `ext-name` out of the browser; its routes, panel and assets are gone from the next request. Answers the name.
(view kb req)What one request's rendering reads that does not vary row to row — built once per request and threaded through every render fn in place of a bare KB.
What one request's rendering reads that does not vary row to row — built once per request and threaded through every render fn in place of a bare KB.
(why-page {:keys [kb] :as view} h)The whole proof tree for a handle — vaelii.core/why rendered, collapsible. Linked
from the sentex page, which shows only the first hop.
The whole proof tree for a handle — `vaelii.core/why` rendered, collapsible. Linked from the sentex page, which shows only the first hop.
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 |