1796 lines
96 KiB
Org Mode
1796 lines
96 KiB
Org Mode
#+TITLE: Passepartout Neurosymbolic Engine — Design Decisions and Architecture Options
|
||
#+AUTHOR: Agent
|
||
#+FILETAGS: :notes:design-decisions:neurosymbolic:architecture:v3.0.0:
|
||
#+CREATED: [2026-05-08 Fri]
|
||
|
||
* The Hallucination Problem — Why Neurosymbolic
|
||
|
||
An LLM is a statistical engine trained on token sequences. It generates the most
|
||
probable continuation of a prompt. Given sufficient context, that continuation is
|
||
correct. Given novel context, it is often wrong in confident-sounding ways.
|
||
|
||
This is not a training deficiency. Hallucination is a fundamental property of
|
||
probabilistic inference. You can reduce it with better models, longer contexts,
|
||
and clever prompting, but you cannot eliminate it by making the LLM better. You
|
||
eliminate it by not asking the LLM to do things that require certainty.
|
||
|
||
This is the architectural bet at the heart of Passepartout's neurosymbolic design.
|
||
The LLM should not be the reasoning engine. It should be the *creative* engine —
|
||
proposing possibilities, surfacing connections, translating between natural
|
||
language and formal representation. The *reasoning* engine should be symbolic:
|
||
deterministic, verification-grounded, provenance-tracked, and incapable of
|
||
hallucination by construction.
|
||
|
||
This is not a rejection of neural methods. It is a division of labor. The neuro
|
||
is the brain — generative, associative, creative, comfortable with ambiguity. It
|
||
produces hypotheses. The symbolic engine is the education — accumulated, verified,
|
||
provenance-tracked knowledge that the brain draws on and is disciplined by. It
|
||
doesn't think. It remembers, checks, and constrains.
|
||
|
||
The brain is always smarter than the education, but the education prevents the
|
||
brain from being confidently wrong.
|
||
|
||
** See also:
|
||
|
||
- =passepartout/docs/DESIGN_DECISIONS.org=: "The Probabilistic-Deterministic Split"
|
||
for the gate-level version of this argument.
|
||
- =notes/passepartout-whitehead.org=: Whitehead's ramified theory of types as
|
||
the structural guarantee against self-referential contradictions.
|
||
- =notes/passepartout-symbolic-engine-exploration.org=: the full design space and
|
||
the lossiness problem at the neural-symbolic boundary.
|
||
|
||
* The Five Architecture Options
|
||
|
||
The symbolic engine must relate to the human memex. The relationship is not
|
||
obvious because knowledge lives in two incompatible forms: natural language
|
||
prose (what the human reads and writes) and formal facts (what the symbolic
|
||
engine reasons about). The translation between them is lossy by nature. The
|
||
architecture is defined by how it handles that lossiness.
|
||
|
||
=notes/passepartout-symbolic-engine-exploration.org= explores five options. They are
|
||
summarized here to make subsequent decisions legible.
|
||
|
||
** Option 1: The Auto-Formalizer
|
||
|
||
A separate knowledge graph stores symbolic facts. The LLM populates it by
|
||
extracting triples from unstructured data — documentation, manuals, logs,
|
||
session histories. The KG becomes co-authoritative with the human prose.
|
||
|
||
This is the simplest to implement but inherits the dual-representation problem
|
||
in its most acute form. The KG and the prose can disagree, and the architecture
|
||
provides no mechanism for resolving disagreements. It also stores knowledge
|
||
twice — once in the user's Org files, once in the KG — with no guarantee that
|
||
they stay synchronized.
|
||
|
||
** Option 2: Two Intentionally Separate Memexes
|
||
|
||
The human memex contains prose: thoughts, diaries, decisions, documentation.
|
||
The symbolic memex contains formal facts: constraints, rules, relationships,
|
||
deductions. The archivist bridges between them but does not try to keep them
|
||
synchronized. They are allowed to diverge because they serve different purposes.
|
||
The prose captures what the human intended. The symbolic memex captures what
|
||
the symbolic engine has proven.
|
||
|
||
This is philosophically honest — it admits that no lossless translation between
|
||
natural language and formal logic is possible. But it forces the user to reason
|
||
about two separate knowledge stores and understand when to trust each.
|
||
|
||
** Option 3: Tangled Fact Blocks in Org Files
|
||
|
||
The tangle mechanism already handles the dual-representation problem for code.
|
||
Lisp code lives in literate blocks within Org files (=#+begin_src lisp=). The
|
||
tangle mechanism extracts these blocks and generates =.lisp= files. A new block
|
||
type — =#+begin_src knowledge= — would contain symbolic facts in a formal
|
||
language. The tangle mechanism would load these facts into the symbolic engine's
|
||
in-memory store, just as it loads Lisp code into the SBCL image.
|
||
|
||
This is aesthetically appealing because it unifies the format. One toolchain,
|
||
one version control system, one Merkle tree. But the block language itself IS
|
||
the knowledge representation language, and that language is the ontology we
|
||
have not yet defined. The format is unified but the content is unspecified.
|
||
|
||
** Option 4: One Memex, Two Indices
|
||
|
||
The prose remains in human language in Org files. The prose is always the ground
|
||
truth. Two indices sit on top of the prose as derived views:
|
||
|
||
- The *neural index* uses vector embeddings to enable semantic search. The LLM
|
||
navigates the prose through embedding space, retrieving relevant headings.
|
||
- The *symbolic index* stores formal assertions about what the prose says —
|
||
predicates, relations, constraints — each grounded to a specific heading or
|
||
block in the Org file.
|
||
|
||
Each index serves its own side of the machine. They do not need to understand
|
||
each other's representations. They only need to agree on which heading or block
|
||
they are referring to. Because the prose is always the ground truth, the symbolic
|
||
index can be thrown away and rebuilt from scratch if it becomes corrupted or
|
||
stale. No information is lost — only the extracted assertions.
|
||
|
||
** Option 5: Ephemeral Symbolic Facts
|
||
|
||
No persistence, no serialization format, no knowledge graph stored on disk.
|
||
VivaceGraph exists in memory during the session. Screamer derives facts from the
|
||
prose as needed. When the session ends, the facts are discarded and re-derived
|
||
from the prose on the next start.
|
||
|
||
This punts the ontological design problem entirely. You never have to decide on
|
||
a serialization format because you never serialize. The cost is compute
|
||
(re-derivation on every restart) and the inability to accumulate facts across
|
||
sessions. But it is the correct first step — a way to learn what kinds of facts
|
||
are actually useful before committing to a storage format.
|
||
|
||
* The Chosen Path: Option 4, Starting with Option 5
|
||
|
||
The one-memex-two-indices architecture (Option 4) is the correct long-term
|
||
architecture. The prose is the ground truth. The symbolic index is a derived
|
||
view that can be rebuilt. The neural index handles what the symbolic index
|
||
cannot — semantic search, fuzzy matching, associative leaps.
|
||
|
||
But committing to a persistence format before knowing what facts are useful
|
||
is premature. The practical path starts with Option 5 (ephemeral facts) as the
|
||
Phase 1-4 implementation, then graduates to Option 4 with VivaceGraph
|
||
persistence in Phase 5 when the fact language has been battle-tested (=see
|
||
=passepartout-neurosymbolic-roadmap.org=).
|
||
|
||
** Why the dual index is permanent, not transitional
|
||
|
||
In the coding domain, there is an aspiration that the symbolic index could
|
||
eventually capture enough of the prose's propositional content to become a
|
||
complete representation — the "flip" described in the architecture note. But
|
||
for the broader memex (literature, poetry, personal reflection, daily logs),
|
||
completeness is neither possible nor desirable. You cannot formalize what makes
|
||
a poem beautiful. You cannot extract a triple that captures the emotional weight
|
||
of a diary entry. The neural index will always be the gateway to the full
|
||
richness of the prose. The symbolic index handles what can be mechanically
|
||
verified: citations, entities, temporal order, contradictions, provenance.
|
||
The division of labor between the two indices is permanent because the domains
|
||
they serve are fundamentally different kinds of knowledge.
|
||
|
||
* The Neuro as Brain, the Symbolic as Education
|
||
|
||
The original 10-80-10 architecture (10% neural, 80% symbolic, 10% neural)
|
||
describes the target ratios for a *coding* agent — a domain where most reasoning
|
||
is formalizable. For the broader memex, the ratios are different and less
|
||
important than the metaphor itself.
|
||
|
||
The neuro is the *brain* — generative, associative, creative, comfortable with
|
||
ambiguity. It produces insights that are provisional, connections that are
|
||
speculative, hypotheses that may be wrong. It is the driver.
|
||
|
||
The symbolic engine is the *education* — accumulated, verified,
|
||
provenance-tracked knowledge that the brain draws on and is disciplined by. It
|
||
doesn't think creatively. It remembers, checks, and constrains. It prevents the
|
||
brain from being confidently wrong.
|
||
|
||
This framing resolves a tension in the original architecture. The 10-80-10
|
||
implies the symbolic engine /replaces/ the neuro for reasoning. But a symbolic
|
||
engine is terrible at creativity, ambiguity, and associative leaps across
|
||
unrelated domains — exactly what you need for a memex that contains /Pale Fire/,
|
||
a shopping list, and a project plan. The brain proposes that your sudden interest
|
||
in unreliable narrators coincides with a week where your project retrospective
|
||
used the word "deception." The education verifies: "those two diary entries are
|
||
4 days apart; the word 'deception' appears in both; here are the headings." The
|
||
brain makes the leap. The education makes it trustworthy.
|
||
|
||
This means the symbolic engine never needs to be "complete." Education isn't
|
||
complete knowledge — it's structured knowledge. You don't need a fact for every
|
||
sentence in your diary. You need facts for what can be mechanically verified:
|
||
dates, citations, entities, contradictions, temporal order. The brain handles
|
||
the rest.
|
||
|
||
* The Gate-to-Fact Bootstrap — Extracting the First Ontology from Existing Code
|
||
|
||
The Dispatcher gate stack already encodes an implicit ontology. Every gate
|
||
vector asserts the existence of a category of things:
|
||
|
||
- Gate vector 2 asserts there exists a class of files called /secrets/.
|
||
- Gate vector 7 asserts there exists a class of commands called /destructive/.
|
||
- Gate vector 8 asserts there exists a class of domains called /trusted/.
|
||
- The self-build boundary asserts there exists a class of files called
|
||
/core-harness/ and a class called /skills/.
|
||
|
||
These claims are currently expressed as code — Lisp functions that pattern-match
|
||
against file paths, shell commands, and URLs. They are not facts the symbolic
|
||
engine can query, derive from, or check for consistency. But they can be made
|
||
explicit.
|
||
|
||
The bootstrap makes every gate a set of initial symbolic facts:
|
||
=(:file ".env" :member-of-class :secret-files :source gate-vector-2)=,
|
||
=(:command "rm -rf /" :classified-as :catastrophic :source gate-vector-7)=,
|
||
=(:domain "api.telegram.org" :classified-as :trusted :source gate-vector-8)=.
|
||
|
||
This produces 50-70 entity classes directly from the existing gate stack,
|
||
without any new infrastructure:
|
||
|
||
| Source | Count | Example categories |
|
||
|----------------------------------------+-------+----------------------------------------------------|
|
||
| ~*dispatcher-protected-paths*~ | 11 | :secret-config-file, :ssh-key-file, :gpg-key-file |
|
||
| ~*dispatcher-shell-blocked*~ | 8 | :catastrophic-command, :injection-pattern |
|
||
| ~*dispatcher-network-whitelist*~ | 2 | :trusted-domain, :untrusted-domain |
|
||
| Self-build boundary | 2 | :core-harness-file, :skill-file |
|
||
| Privacy tags | 3 | :private-content, :financial-content |
|
||
| Permission table | 3 | :read-only-tool, :write-tool, :eval-tool |
|
||
| Cognitive tools | 6 | :code-search-tool, :file-io-tool, :shell-tool |
|
||
| Relations (all gates) | ~15 | :member-of-class, :classified-as, :depends-on |
|
||
| Qualities | ~8 | :catastrophic, :dangerous, :moderate, :harmless |
|
||
| Provenance sources | 4 | :gate-outcome, :human-authored, :deduced, :llm-proposed |
|
||
|----------------------------------------+-------+----------------------------------------------------|
|
||
|
||
This is the seed. It gives Screamer a domain to reason about immediately, without
|
||
any LLM involvement. It proves the pattern — code becomes facts, facts enable
|
||
reasoning — at the cost of approximately 30 lines of Lisp.
|
||
|
||
* The LLM as Proposer — Verified Extraction
|
||
|
||
The LLM cannot be trusted to populate the symbolic index directly. Its outputs are
|
||
sampled, not proven. A probabilistic extraction feeding a deterministic engine
|
||
defeats the purpose of being deterministic.
|
||
|
||
But the LLM is still useful. It can surface facts that are obvious to a human
|
||
reader of prose but would take the symbolic engine many deduction steps to reach
|
||
independently. The solution is to demote the LLM from /extractor/ to /proposer/:
|
||
|
||
1. The archivist reads a prose heading.
|
||
2. The LLM proposes candidate triples.
|
||
3. Screamer checks each triple for consistency against the existing fact store.
|
||
4. Only consistent triples are admitted to the symbolic index, flagged with
|
||
=:provenance :llm-proposed= and grounded to the source heading.
|
||
|
||
The LLM might hallucinate facts that don't correspond to the prose. It might
|
||
extract facts that contradict existing knowledge. It might produce syntactically
|
||
malformed triples. None of these failures contaminate the symbolic index because
|
||
proposals are not admitted automatically. The admission gate (Screamer) is
|
||
deterministic.
|
||
|
||
This is the core architecture pattern. Everything else — the entity classes, the
|
||
deduction engine, the persistence layer — follows from this single design decision:
|
||
*the LLM proposes; the symbolic engine decides whether to accept.*
|
||
|
||
* Two Cardinality Policies — Singular, Dual, and Plural Facts
|
||
|
||
Classical logic requires consistency. A contradiction implies everything
|
||
(=ex contradictione quodlibet=). Screamer, as a constraint solver, also requires
|
||
consistency — a contradictory constraint set has no solutions. But the symbolic
|
||
engine operates across domains where the meaning of contradiction is fundamentally
|
||
different. The correct question is not "is this consistent?" but "what cardinality
|
||
of truth does this domain support?"
|
||
|
||
Time is not a policy. It is a universal dimension that applies equally to every
|
||
fact, regardless of cardinality. All facts carry =:timestamp= and =:parent-id=
|
||
fields. Every fact has a version history. Every fact lives in a Merkle chain
|
||
that captures how it changed. The cardinality policy only governs what happens
|
||
at a given logical moment when two values coexist for the same =entity= and
|
||
=relation=.
|
||
|
||
** Policy :singular — One Active Value, One Version Chain
|
||
|
||
The active set contains exactly one value for =(:entity :relation)= at a time.
|
||
When a new value asserts for the same pair, the old value is not rejected. It
|
||
is superseded — moved into the version history, linked to the new leaf by
|
||
=:parent-id=, and retained permanently. The active value is the leaf of the
|
||
Merkle chain.
|
||
|
||
"I used to think =rm -rf /= was safe. Now I know it is catastrophic." Both
|
||
facts exist. Both are true — the first at =2024-06-01=, the second at
|
||
=2025-03-15=. The chain captures the evolution. The =:singular= policy means
|
||
there is one truth /now/, not that there was only ever one truth.
|
||
|
||
Use for: security classifications, file system state, gate rules, code
|
||
correctness, deterministic safety constraints — domains that converge on
|
||
one answer, evolving over time.
|
||
|
||
** Policy :dual — Exactly Two Values, in Explicit Tension
|
||
|
||
The active set contains exactly two values for =(:entity :relation)=. Both are
|
||
simultaneously true. Both carry independent version histories. A third value is
|
||
rejected — the domain is binary by nature.
|
||
|
||
Some contradictions are productive precisely /because/ they are binary. Thesis
|
||
and antithesis. Love and resentment. Wave and particle. A poem's two incompatible
|
||
readings. The symbolic index holds both, cross-referenced as complementary rather
|
||
than conflicting. The user is not asked to resolve the tension. The tension is
|
||
the fact.
|
||
|
||
The system can reason about cardinality transitions: a =:dual= fact that has
|
||
one interpretation superseded should collapse to =:singular=. A =:dual= that
|
||
has a third interpretation asserted should prompt the user: "Promote to =:plural=
|
||
or demote one interpretation?" The cardinality tracks the state of the domain.
|
||
|
||
Use for: productive binary tensions, complementary opposites, dialectical
|
||
pairs, any domain where two answers are both true and their tension is
|
||
meaningful.
|
||
|
||
** Policy :plural — N Active Values, Open Set
|
||
|
||
The active set contains any number of values for =(:entity :relation)=. Each
|
||
value has independent provenance and its own version history. Queries return
|
||
all active values with provenance display. Contradictions are flagged as
|
||
cross-references between values — information, not error.
|
||
|
||
A =:plural= fact where all but one value are superseded should collapse to
|
||
=:singular=. A =:plural= fact where the set reduces to two active values —
|
||
and the remaining two are complementary — should collapse to =:dual=.
|
||
|
||
Use for: literary interpretation, scientific hypotheses, personal beliefs held
|
||
at different times (when the tension is multi-faceted rather than binary),
|
||
multi-source factual disagreement, open-ended exploration.
|
||
|
||
** Time Is Universal, Not a Policy
|
||
|
||
Every fact — regardless of cardinality — lives in a version chain. The Merkle
|
||
DAG (see "Merkle DAG for Version History" below) captures every version of every
|
||
fact. The policy only governs the cardinality of the active set at a single
|
||
logical moment.
|
||
|
||
The version chain is a linked list of facts, each pointing to its predecessor
|
||
via =:parent-id=, each hashed with =SHA-256(content || parent-hash)=. Changing
|
||
any version invalidates all downstream hashes. The chains form a DAG — independent
|
||
facts evolve independently; only facts in the same =(:entity :relation)= chain
|
||
share ancestry.
|
||
|
||
A global snapshot captures the root hash over all chains at a point in time.
|
||
Rollback restores the entire fact state to that snapshot. This already exists in
|
||
Passepartout's Merkle memory (v0.2.0) — the fact store is a new occupant of
|
||
existing housing, not a new foundation.
|
||
|
||
** Policy Assignment
|
||
|
||
The policy is assigned when a category is defined. New categories default to
|
||
=:plural= (safe — never loses information). Core security categories are
|
||
explicitly =:singular=. The gate stack's bootstrapped facts are =:singular=
|
||
because they describe the actual filesystem, which is physically singular.
|
||
Categories for dialectical or complementary domains are explicitly =:dual=.
|
||
|
||
The Screamer admission gate applies the cardinality policy at the active set:
|
||
- =:singular= + same value, later timestamp → supersede old, chain new as leaf.
|
||
- =:singular= + different value, same timestamp → reject (contradiction). Human
|
||
resolves: which is the active value?
|
||
- =:singular= + different value, later timestamp → supersede old, chain new as
|
||
leaf. History preserved.
|
||
- =:dual= + first value → admit. + second value → admit, cross-reference as
|
||
complementary. + third value → prompt: promote to =:plural= or demote one
|
||
existing?
|
||
- =:dual= + superseding value (same position) → chain via =:parent-id=.
|
||
- =:plural= + any value → admit. If active count drops to 2 and values are
|
||
complementary → prompt: collapse to =:dual=? If active count drops to 1 →
|
||
collapse to =:singular= automatically or prompt.
|
||
|
||
** Why This Matters for the Broader Memex
|
||
|
||
In the coding domain, contradiction is rare, resolvable, and usually temporal
|
||
(a rule changed). In the broader memex, contradiction is the product, not the
|
||
error. Your poetry analysis contradicts your last diary entry. Your reading of
|
||
/Pale Fire/ changed between 2023 and 2025. Wikidata says Mount Everest is
|
||
8848m; DBpedia says 8849m. You love this person AND you resent them.
|
||
|
||
The symbolic engine's job is not to decide which is right. It is to surface the
|
||
tension with provenance — "these three sources disagree; here is the chain for
|
||
each" for plural facts, or "you hold these two positions in tension" for dual
|
||
facts, or "you believed X until Tuesday, then Y" for singular facts that
|
||
evolved. The cardinality policy names the /structure/ of the tension. The
|
||
Merkle chain provides the /history/ of each position.
|
||
|
||
* How Categories Grow — The Organic Ontology
|
||
|
||
Whitehead's /Principia Mathematica/ took over 300 pages to define the logical
|
||
foundations before it could prove that one plus one equals two. Every category
|
||
introduced carried a burden of justification. Every inference rule had to be
|
||
demonstrated sound. This is the classical approach to ontology: define everything
|
||
upfront, exhaustively, formally.
|
||
|
||
Passepartout cannot afford this and does not need it. Its domain is bounded
|
||
(software engineering, personal knowledge, literary engagement, daily life) and
|
||
its ontology grows from the system's own operation:
|
||
|
||
1. *The gate stack seeds the ontology.* Every gate vector is an implicit claim
|
||
about a category of things. The bootstrap makes these claims explicit. The
|
||
seed is 50-70 entity classes with no human authoring required — they are
|
||
mechanically extracted from the existing code.
|
||
|
||
2. *New gate vectors add categories directly.* As the Dispatcher grows (new
|
||
shell patterns, new path protections, new tool classifications), the ontology
|
||
grows with it. Every new pattern in the gate stack becomes a fact on skill
|
||
load. No human effort. The gate stack grows, the ontology grows.
|
||
|
||
3. *Screamer generalizes from gate outcomes.* After 37 shell commands are blocked
|
||
as destructive, Screamer extracts structural commonalities: "commands writing
|
||
to block devices," "commands recursively deleting outside the workspace."
|
||
These become new subcategories (=:block-device-command=,
|
||
=:workspace-external-delete=) that didn't exist in the original gate patterns.
|
||
The ontology deepens through observation.
|
||
|
||
4. *The archivist proposes from prose.* The archivist reads a diary entry about
|
||
a book: "Nabokov's lectures on Kafka." The LLM proposes =(:entity :nabokov
|
||
:relation :lectures-on :value :kafka)=. Screamer checks consistency. Admitted.
|
||
The categories =:author=, =:lectures-on=, and =:subject= didn't exist before —
|
||
they are created on first use. This is the primary growth mechanism for the
|
||
broader memex.
|
||
|
||
5. *The human declares explicitly.* The human writes a declarative fact directly
|
||
into the symbolic index. No extraction step. No LLM involvement. The fact is
|
||
admitted with =:provenance :human-authored= — the highest trust level.
|
||
|
||
6. *Temporal patterns crystallize into categories.* Every Sunday the memex gets a
|
||
retrospective heading. Every Monday a planning heading. The time-awareness
|
||
system observes the periodicity and proposes =:weekly-retrospective= and
|
||
=:weekly-planning= as fact types. Screamer verifies they don't contradict
|
||
existing categorizations. Admitted.
|
||
|
||
7. *Cross-domain overlap produces parent categories.* Screamer notices that
|
||
=:secret-files= (from the gate stack) and =:private-content= (from privacy
|
||
tags) share members — =.env= is both a secret file and private content. It
|
||
proposes =:sensitive-material= as a parent with both as children. Taxonomy
|
||
building happens automatically through overlap detection.
|
||
|
||
** Growth is self-limiting by design
|
||
|
||
Not every conceivable category is added. The system prunes through use:
|
||
|
||
- New categories are admitted only through Screamer's consistency check. A
|
||
category that contradicts an existing classification is rejected.
|
||
- A category that never gets queried costs nothing (a hash table entry) but
|
||
produces no value. It fades from use naturally.
|
||
- Overly fine-grained categories (=.env.foo.bar.baz= as its own class) are
|
||
rejected because they are redundant with the wildcard pattern that already
|
||
covers them.
|
||
- Overly broad categories that subsume meaningful distinctions ("everything is
|
||
a =:file=") produce contradictions when Screamer tries to apply existing rules.
|
||
Rejected.
|
||
|
||
The system converges on a useful granularity through use, not through upfront
|
||
design. The gate stack provides the seed. Gate outcomes, prose extraction,
|
||
deduction, and human authoring grow the shoots. Screamer prunes contradictions.
|
||
The ontology is a garden, not a building.
|
||
|
||
* Empirical Validation — Modular Ontology Engineering with LLMs
|
||
|
||
Shimizu and Hitzler (2025, /Journal of Web Semantics/) argue that LLMs can
|
||
significantly accelerate knowledge graph and ontology engineering — modeling,
|
||
extension, population, alignment, and entity disambiguation — but /only/ if
|
||
ontologies are modular. Their paper provides empirical evidence that validates
|
||
the modular architecture described in this document and exposes concrete patterns
|
||
the archivist should adopt.
|
||
|
||
** The central finding: modularity is the key variable
|
||
|
||
In a complex ontology alignment task (mapping between two oceanography ontologies
|
||
with hundreds of classes and properties), an LLM without module information
|
||
detected correct mappings for 5 of 109 alignment rules — effectively useless. When
|
||
the same LLM was given the module structure of the target ontology (20 named
|
||
conceptual modules such as "Organization," "Cruise," "Physical Sample"), it
|
||
detected correct mappings for 104 of 109 rules — 95% accuracy. The variable was
|
||
modularity.
|
||
|
||
For ontology population (extracting triples from text), their best results came
|
||
from prompts that included a schematic representation of a /single module/ plus
|
||
one extraction example. Against ground truth, this achieved approximately 90%
|
||
extraction accuracy. Without module-scoped prompting, quality degraded
|
||
substantially.
|
||
|
||
The mechanism: conceptual modules scope the LLM's attention to something
|
||
human-sized. The paper's central claim — "by somehow limiting the scope, we
|
||
achieve a more human-like approach — and one more capable of being expressed
|
||
succinctly in language, and thus more appropriate for LLM-based assistance" — is
|
||
an independent discovery of the same principle underlying Passepartout's
|
||
domain-scoped Screamer checks and per-domain cardinality policies.
|
||
|
||
** MOMo: a mature modular ontology methodology
|
||
|
||
The authors' approach, MOMo (Modular Ontology Modeling), has been developed over a
|
||
decade and includes:
|
||
|
||
- A /step-by-step methodology/ that breaks ontology design into clearly delineated
|
||
pieces, each "easier to automate than going one-shot from base data to an
|
||
ontology."
|
||
- A /pattern description language/ (OPLa, expressed in OWL) for annotating modules
|
||
so they can be identified programmatically.
|
||
- A /design library/ (MODL) containing hundreds of commonsense micropatterns
|
||
organized for programmatic access, including via RAG.
|
||
- A /Protégé plugin/ (CoModIDE) for graphical modular ontology development.
|
||
|
||
Critically, their modules are not formal sub-ontologies with logical boundaries.
|
||
They are /conceptual/ partitions — groupings of classes, properties, and axioms
|
||
around "key notions" identified by domain experts. Modules can overlap and nest.
|
||
There are "no precise rules" for what belongs in a module. The modules provide
|
||
"conceptual bridges between human expert conceptualization and data reality."
|
||
|
||
** What Passepartout should adopt
|
||
|
||
*** The modular prompt pattern for the archivist
|
||
|
||
The extraction prompt structure that achieved 90% accuracy is concrete and
|
||
replicable: a schematic representation of a domain module plus a single extraction
|
||
example. The archivist should use this pattern when extracting facts from prose.
|
||
Instead of a generic "extract triples from this text" prompt (200 tokens), the
|
||
prompt should reference the relevant module(s) and include an example triple for
|
||
each relation in that module. The module provides /context/; the example provides
|
||
/format/. Both improve LLM extraction quality without increasing Screamer's
|
||
verification burden.
|
||
|
||
*** MOMo modules as ontology scaffold
|
||
|
||
The Passepartout notes describe an organic growth model: gate-bootstrapped facts
|
||
seed the ontology; gate outcomes, Screamer deductions, and archivist proposals
|
||
grow the shoots. This is correct for the /security and filesystem/ domains where
|
||
the gate stack already encodes expertise. For the broader memex — literature,
|
||
daily reflection, project planning — the 50-70 gate-bootstrapped entity classes
|
||
are starvation.
|
||
|
||
MOMo's micropattern library provides a ready-made scaffold for these domains.
|
||
Hundreds of commonsense patterns already exist for temporal relations, spatial
|
||
relations, agent-action, organizational structure, provenance, and event
|
||
participation. Loading these as initial modules — with :policy :plural and
|
||
=:provenance :external-ontology= — would give the symbolic index a structured
|
||
vocabulary for domains where the gate stack has nothing to offer. The organic
|
||
growth model then /extends and refines/ these modules rather than inventing them
|
||
from scratch. This is the Wikidata strategy applied at the schema level: adopt
|
||
existing structured knowledge, connect personal facts to it, and surface
|
||
disagreements rather than resolve them.
|
||
|
||
*** OPLa annotation for module identification
|
||
|
||
MOMo modules annotated in OPLa can "easily be identified programmatically." If
|
||
Passepartout annotates its ontology modules in a compatible format (even a
|
||
simplified plist-based equivalent), the archivist can automatically select the
|
||
right module(s) when extracting facts from prose. A heading in =literature/=
|
||
triggers the literature module; a heading in =projects/= triggers the software
|
||
engineering module; a heading tagged =:personal:= triggers the diary module. The
|
||
module scopes the prompt. The prompt improves extraction. Screamer gates the
|
||
result. This is the full pipeline, validated at each step.
|
||
|
||
** What this means for the Passepartout architecture
|
||
|
||
The paper validates three design decisions already made:
|
||
|
||
1. /Modularity is non-negotiable./ The paper found that modularity is the
|
||
difference between 5% and 95% accuracy on alignment. Passepartout's per-domain
|
||
cardinality policies and domain-scoped Screamer checks are the same insight
|
||
implemented in a different context. The paper proves the approach works;
|
||
Passepartout applies it to verification rather than extraction.
|
||
|
||
2. /The extraction pipeline is feasible./ 90% population accuracy with module-
|
||
scoped prompts means the archivist /can/ extract useful facts from prose. The
|
||
remaining 10% — the hallucination rate — is what Screamer catches. The paper
|
||
validates the LLM-as-proposer role; Passepartout adds the Screamer-as-verifier
|
||
role.
|
||
|
||
3. /KGs are positioned as anti-hallucination infrastructure./ The paper explicitly
|
||
frames knowledge graphs as "ground truth to escape from LLM hallucinations" and
|
||
as "components of other neurosymbolic approaches." This is the Passepartout
|
||
thesis — the symbolic index as ground truth against which LLM proposals are
|
||
checked — stated in the academic literature by the editors of the neurosymbolic
|
||
AI handbooks.
|
||
|
||
And it exposes one gap in the current design:
|
||
|
||
1. /Emergent modularity may be slower than designed modularity./ Passepartout's
|
||
modules are supposed to emerge organically from gate patterns, Screamer
|
||
generalizations, and cross-domain overlap detection. MOMo's modules are
|
||
designed by domain experts who identify key notions upfront. The emergent
|
||
approach is philosophically cleaner — the system learns its own categories —
|
||
but practically slower. The paper's results suggest that adopting designed
|
||
modules as a scaffold, and letting emergent growth /refine/ rather than
|
||
/invent/ them, would compress the timeline for sufficiency by years.
|
||
|
||
** Relation to Wikidata loading
|
||
|
||
The MOMo micropattern approach and the Wikidata loading strategy are complementary:
|
||
|
||
| Layer | MOMo provides | Wikidata provides |
|
||
|----------------+--------------------------------+--------------------------|
|
||
| Schema | Modular ontology of relations | — (Wikidata's schema is |
|
||
| | and entity classes | implicit in its data) |
|
||
| Instances | — (patterns, not entities) | 100M+ entities with |
|
||
| | | property-value pairs |
|
||
|
||
MOMo gives Passepartout the /relations/ (wrote, lectured-on, influenced,
|
||
published-in). Wikidata gives Passepartout the /instances/ (Nabokov, Pale Fire,
|
||
Kafka). Both are needed. Neither alone is sufficient. The MOMo scaffold tells the
|
||
archivist /what kinds of facts to look for/. The Wikidata graph tells the
|
||
archivist /which entities those facts are about/. Together they transform the
|
||
extraction task from "discover entities and their relations from prose" to
|
||
"connect this prose heading to known entities using known relations" — a
|
||
dramatically simpler prompt with dramatically higher expected accuracy.
|
||
|
||
** Reference
|
||
|
||
- Shimizu, C., & Hitzler, P. (2025). Accelerating knowledge graph and ontology
|
||
engineering with large language models. /Journal of Web Semantics, 85/,
|
||
100862. https://doi.org/10.1016/j.websem.2025.100862
|
||
|
||
** See also
|
||
|
||
- =passepartout-neurosymbolic-roadmap.org=: Phase 3 (Archivist) — the modular
|
||
prompt pattern should be incorporated into the extraction pipeline.
|
||
- =passepartout-agora.org=: the KEL / contract audit trail as instances of
|
||
MOMo-style key-lifecycle and contract-lifecycle modules.
|
||
- =notes/passepartout-SWOT.org=: the SWOT analysis which identifies the ontology
|
||
problem as the key bottleneck — MOMo partially addresses this.
|
||
|
||
** Supporting References
|
||
|
||
*** MOMo: the canonical methodology
|
||
|
||
Shimizu, Hammar & Hitzler (2023, /Semantic Web Journal/) present the full MOMo
|
||
methodology — 31 pages covering the step-by-step design process, schema diagrams
|
||
as knowledge elicitation tools, ODP libraries, OPLa annotation language, and
|
||
CoModIDE, a Protégé plugin for graphical modular ontology development. The paper
|
||
was evaluated with usability studies and demonstrates that modular development
|
||
significantly improves approachability for domain experts who are not ontology
|
||
engineers.
|
||
|
||
Key architectural commitments from MOMo that Passepartout should adopt:
|
||
|
||
- /Schema diagrams/ as the primary communication format between ontologist and
|
||
domain expert. Passepartout's equivalent: the archivist's module-scoped prompt
|
||
includes a simplified schema diagram of the module being populated.
|
||
- /Template-based instantiation/ of ontology design patterns into concrete
|
||
modules. Passepartout's equivalent: micropatterns loaded from MODL are
|
||
instantiated with entities from the user's memex, producing concrete facts.
|
||
- /Systematic axiomatization/ — 17 frequently used axiom patterns for each
|
||
node-edge-node construction in a schema diagram. Passepartout's equivalent:
|
||
Screamer constraint rules derived from module structure.
|
||
|
||
Reference:
|
||
- Shimizu, C., Hammar, K., & Hitzler, P. (2023). Modular ontology modeling.
|
||
/Semantic Web, 14/(3), 459–489. https://doi.org/10.3233/SW-222886
|
||
|
||
*** Ontology Population — the empirical methodology
|
||
|
||
Norouzi et al. (2024) provide the full experimental methodology behind the ~90%
|
||
extraction accuracy claim. Using the Enslaved.org Hub Ontology as ground truth
|
||
and Wikipedia articles as source text, they tested five LLMs across a three-stage
|
||
pipeline: preprocessing, text retrieval, and KG population. The critical finding:
|
||
prompts that included a /schema diagram/ of the target ontology module (using
|
||
MOMo's visual conventions with colored boxes for classes, arrows for relations)
|
||
plus a single extraction example achieved the highest accuracy. Without
|
||
module-scoped prompts, quality degraded substantially.
|
||
|
||
Three findings are directly applicable to the archivist:
|
||
|
||
1. /Role chain simplification./ The Enslaved Ontology has complex role chains
|
||
(e.g., Person → hasRole → Role → inEvent → Event). These were collapsed into
|
||
shortcut relations (e.g., Person → participatedIn → Event) for LLM extraction.
|
||
The archivist should maintain two layers: the /logical/ schema with full role
|
||
chains for Screamer verification, and the /extraction/ schema with simplified
|
||
relations for LLM prompting.
|
||
|
||
2. /Variance across models./ Five LLMs were tested. Performance varied
|
||
significantly. The archivist should benchmark extraction accuracy per provider
|
||
and per module, and route extraction tasks to the best-performing model for
|
||
each module — extending the existing model-tier routing (v0.3.0) from
|
||
complexity-based to accuracy-based routing.
|
||
|
||
3. /Cross-source validation./ The paper used both Wikipedia text and Wikidata
|
||
as overlapping sources for the same entities, enabling cross-verification.
|
||
The archivist can do the same: extract facts from the user's prose, extract
|
||
facts from Wikidata for the same entities, and present disagreements with
|
||
provenance. This is the =:plural= cardinality policy applied at extraction time.
|
||
|
||
Reference:
|
||
- Norouzi, S.S., Barua, A., Christou, A., Gautam, N., Eells, A., Hitzler, P.,
|
||
& Shimizu, C. (2024). Ontology Population using LLMs. arXiv:2411.01612.
|
||
|
||
* Historical Lineage — McCarthy's Advice Taker
|
||
|
||
McCarthy's "Programs with Common Sense" (1959) is the direct intellectual ancestor
|
||
of the Passepartout architecture. The paper proposed an "advice taker" — a program
|
||
that "will draw immediate conclusions from a list of premises" expressed in
|
||
"a suitable formal language (most likely a part of the predicate calculus)." The
|
||
program would:
|
||
|
||
1. Accept declarative statements about the world as input.
|
||
2. Store them as logical formulas.
|
||
3. Reason from them to produce new conclusions.
|
||
4. Accept new facts and revise its conclusions.
|
||
|
||
This is precisely the Passepartout pipeline: the archivist extracts declarative
|
||
facts from prose → Screamer checks them for consistency → VivaceGraph stores them
|
||
→ the planner reasons from them → new facts from gate outcomes and deductions
|
||
revise the store. McCarthy proposed it in 1959. Passepartout is building it in
|
||
2026.
|
||
|
||
The gap between McCarthy's proposal and Passepartout's implementation is the
|
||
/hallucination problem/. McCarthy assumed facts would be entered by a human
|
||
programmer in formal logic. Passepartout's facts are extracted from natural
|
||
language prose by an LLM — a probabilistic process that requires deterministic
|
||
verification. Screamer is the component McCarthy didn't need: a constraint solver
|
||
that gates LLM-proposed facts against the existing fact store.
|
||
|
||
The connection is not metaphorical. McCarthy cited Principia Mathematica as an
|
||
influence on Lisp. Passepartout's Whitehead note traces the same PM → Lisp
|
||
lineage. The advice taker → Passepartout lineage completes the arc: PM's formal
|
||
logic → Lisp → McCarthy's advice taker → Passepartout's neurosymbolic engine.
|
||
|
||
Reference:
|
||
- McCarthy, J. (1959). Programs with Common Sense. /Proceedings of the
|
||
Teddington Conference on the Mechanization of Thought Processes./
|
||
|
||
* Philosophical Validation — The Neurosymbolic Consensus
|
||
|
||
Three papers from the neurosymbolic AI research community validate the
|
||
architectural thesis from complementary angles.
|
||
|
||
** Marcus (2020): The Case Against Pure Deep Learning
|
||
|
||
Gary Marcus's "The Next Decade in AI" argues that deep learning alone is "data
|
||
hungry, shallow, brittle, and limited in its ability to generalize." The paper
|
||
demonstrates GPT-2 failing at basic commonsense reasoning:
|
||
|
||
- "Yesterday I dropped my clothes off at the dry cleaners and have yet to pick
|
||
them up. Where are my clothes?" → GPT-2: "at my mom's house."
|
||
- "There are six frogs on a log. Two leave, but three join. The number of frogs
|
||
on the log is now" → GPT-2: "seventeen."
|
||
|
||
Marcus proposes four steps toward robust AI: hybrid architecture (combining
|
||
neural and symbolic), large-scale knowledge (abstract and causal, not just
|
||
statistical), reasoning (formal inference over structured representations), and
|
||
cognitive models (frameworks for how entities relate). Passepartout implements all
|
||
four: the perceive-reason-act pipeline is hybrid, the symbolic index is causal
|
||
knowledge, Screamer + ACL2 provide reasoning, and the gate-bootstrapped ontology
|
||
plus MOMo modules provide cognitive models.
|
||
|
||
Marcus's core claim — "we have no hope of achieving robust intelligence without
|
||
first developing systems with deep understanding" — is the justification for
|
||
Passepartout's entire neurosymbolic investment. The alternative is a system that
|
||
works "on a good day" and fails unpredictably. The deterministic gate stack and
|
||
Screamer admission gate are the engineering realization of Marcus's call for
|
||
robustness.
|
||
|
||
Reference:
|
||
- Marcus, G. (2020). The Next Decade in AI: Four Steps Towards Robust
|
||
Artificial Intelligence. arXiv:2002.06177.
|
||
|
||
** Gaur & Sheth (2023): CREST — Trustworthy Neurosymbolic AI
|
||
|
||
Gaur and Sheth present the CREST framework: Consistency, Reliability, user-level
|
||
Explainability, and Safety build Trust — and they argue these require
|
||
neurosymbolic methods. Their empirical finding: GPT-3.5 breached safety
|
||
constraints 30% of the time when asked identical questions repeatedly. Claude's
|
||
16 safety rules and Sparrow's 23 rules provide no /inherent/ safety — they are
|
||
heuristic guardrails that can be breached through prompt variation.
|
||
|
||
These findings validate three Passepartout design commitments:
|
||
|
||
1. /Prompt-level safety is insufficient./ Claude and Sparrow use rules that
|
||
consume LLM tokens and can be evaded. Passepartout's deterministic gates run
|
||
in pure Lisp, cost 0 tokens, and cannot be evaded by prompt engineering.
|
||
|
||
2. /Inconsistency is the norm, not the exception./ Gaur & Sheth show that even
|
||
identical queries produce inconsistent responses ~30% of the time. This
|
||
validates the cardinality model: a system that expects contradiction and
|
||
surfaces it with provenance is architecturally more honest than one that
|
||
assumes consistency and silently resolves it.
|
||
|
||
3. /Knowledge infusion is required for trust./ The CREST framework embeds
|
||
domain knowledge (clinical guidelines, procedural knowledge) into LLM
|
||
pipelines. Passepartout's symbolic index IS the knowledge infusion layer —
|
||
facts extracted from prose, verified by Screamer, and available for any LLM
|
||
call through the context assembly pipeline.
|
||
|
||
Reference:
|
||
- Gaur, M., & Sheth, A. (2023). Building Trustworthy NeuroSymbolic AI Systems:
|
||
Consistency, Reliability, Explainability, and Safety. arXiv:2312.06798.
|
||
|
||
** Sheth et al. (2022): Knowledge-Infused Learning
|
||
|
||
Sheth, Gunaratna, Bhatt, and Gaur define Knowledge-infused Learning (KiL) as
|
||
"combining various types of explicit knowledge with data-driven deep learning
|
||
techniques." They identify three infusion levels (shallow, semi-deep, deep) and
|
||
position KiL as "a sweet spot in neuro-symbolic AI."
|
||
|
||
The paper makes two observations relevant to Passepartout:
|
||
|
||
1. /Data alone is not enough./ The opening cites Pedro Domingos ("Data Alone is
|
||
Not Enough"), Andrew Ng ("the importance of Big Data is overhyped"), and
|
||
Gary Marcus ("AI that captures how humans think"). These are the intellectual
|
||
warrant for the symbolic index: a knowledge layer that is independent of any
|
||
specific LLM call, accumulated across sessions, and verified against existing
|
||
facts.
|
||
|
||
2. /Expert knowledge is external to the model./ Domain experts use "their past
|
||
experience, web or domain-specific knowledge sources, and annotation
|
||
guidelines" to create ground truth — resources the LLM cannot access during
|
||
training. The symbolic index makes these resources queryable: facts from the
|
||
gate stack (security expertise), from the human (declarative authoring), from
|
||
Wikidata (world knowledge), and from Screamer deductions (derived expertise).
|
||
|
||
Passepartout's architecture is a specific implementation of KiL at the deepest
|
||
infusion level: knowledge is not appended to prompts (shallow) or embedded in
|
||
fine-tuning (semi-deep). It is a first-class data structure — the symbolic index
|
||
— that the LLM queries through the archivist and the planner. The knowledge is
|
||
living: it accumulates, is verified, carries provenance, and evolves through
|
||
ontology versioning.
|
||
|
||
Reference:
|
||
- Gaur, M., Gunaratna, K., Bhatt, S., & Sheth, A. (2022). Knowledge-Infused
|
||
Learning: A Sweet Spot in Neuro-Symbolic AI. /IEEE Internet Computing, 26/(4),
|
||
5–11. https://doi.org/10.1109/MIC.2022.3179759
|
||
|
||
* Semantic Wikipedia as Entity Backbone
|
||
|
||
The gate stack provides 50-70 entity classes — adequate for a coding agent where
|
||
the domain is bounded to files, commands, and code symbols. For a general-knowledge
|
||
memex, 50-70 is starvation. Your memex mentions Nabokov, /Pale Fire/, Kinbote,
|
||
Zembla, paranoid reading, unreliable narrators, postmodernism, butterfly
|
||
migration, chess problems, and the Russian exile experience. The gate stack knows
|
||
none of these. Organic growth through prose extraction would take years just to
|
||
cover the entities in one person's engagement with a single novel.
|
||
|
||
Wikidata has already done this work: approximately 2 million entity classes, over
|
||
100 million entities, a decade of human curation. By loading the neighborhood of
|
||
your memex into the symbolic index (entities referenced in your prose, plus their
|
||
N-hop property net from Wikidata), the entity recognition problem vanishes. The
|
||
archivist doesn't need to discover Nabokov from your diary. It needs to connect
|
||
your heading to the existing Wikidata entity. That is a simpler task — reference
|
||
resolution, not knowledge extraction.
|
||
|
||
The LLM's role shrinks to three thin boundaries:
|
||
|
||
1. *Input translation* — natural language question to structured query. "What do
|
||
I think about monorepos?" → =(fact-query :entity :monorepo :relation :opinion
|
||
:source :memex)=. Formulaic, ~100 tokens, any model sufficient.
|
||
|
||
2. *Prose to candidate triple* — for personal memex entries that have no Wikidata
|
||
counterpart: your opinions, your day's events, your project plans. Proposals
|
||
are verified by Screamer before admission. This is the only extraction path
|
||
that still requires an LLM, and its scope is limited to what Wikidata cannot
|
||
provide — your subjective, personal, or novel content.
|
||
|
||
3. *Result to prose* — structured answer to readable sentence. "Your 2023 diary
|
||
says 8848m. Wikidata (last edited Feb 2024) says 8849m. They disagree on
|
||
height." The reasoning is done; the LLM wraps the plist in grammar. ~100
|
||
tokens, any model sufficient, purely cosmetic. Users who prefer no LLM at all
|
||
can navigate through command-driven interaction (=/query=, =/contradictions=,
|
||
=/audit=, =/context why=).
|
||
|
||
Everything else — the gate stack, the fact store, the constraint solver, the type
|
||
hierarchy, the provenance tracking, the contradiction surfacing, the cross-domain
|
||
comparison — is pure deterministic Lisp with zero LLM tokens.
|
||
|
||
** The decisive simplification
|
||
|
||
Without Semantic Wikipedia, the archivist must /discover/ entities from prose:
|
||
extract a triple for every person, place, work, concept, and event mentioned in
|
||
the memex. This is unbounded LLM work and the quality depends on extraction
|
||
accuracy.
|
||
|
||
With Wikidata loaded, the entity graph is pre-structured. The archivist's job
|
||
changes from "discover that Nabokov wrote /Pale Fire/ and lectured on Kafka" to
|
||
"verify that the Nabokov referenced in heading #47 is the same entity as Wikidata
|
||
item Q36591." The second task is simpler, more reliable, and in many cases can
|
||
be done without an LLM at all — a simple entity name match against the loaded
|
||
Wikidata graph may suffice for unambiguous names.
|
||
|
||
* The "Awakening" — From Lossy Extraction to Deterministic Derivation
|
||
|
||
The symbolic index begins its life as a lossy construct. The initial extraction
|
||
from the prose — the first population of facts from LLM proposals verified by
|
||
Screamer — is built from an uncertain foundation. Some facts are correct. Some
|
||
are missing. Some are wrong.
|
||
|
||
But the symbolic engine accumulates non-lossy facts through three independent
|
||
mechanisms:
|
||
|
||
1. *Gate outcomes* — every gate rejection is a fact. No LLM involved. These
|
||
accumulate at the rate of user interactions.
|
||
2. *Screamer deductions* — new facts derived from existing facts. No LLM
|
||
involved. These accumulate whenever the fact store crosses a density threshold
|
||
where structural patterns emerge.
|
||
3. *Human authoring* — the human explicitly declares facts. No LLM involved.
|
||
|
||
At some point, the non-lossy facts constitute a sufficient foundation that the
|
||
symbolic engine can reverse the flow: instead of the LLM extracting facts from
|
||
prose, the symbolic engine reads prose through its own lens — its now-substantial
|
||
ontology of categories, rules, and constraints — and asserts facts in its own
|
||
language. The extraction mechanism ceases to be probabilistic and becomes
|
||
deterministic. This is not unlike how infants awaken and become children one can reason with. Sometimes.
|
||
|
||
** The sufficiency criterion
|
||
|
||
The architecture note (=notes/passepartout-symbolic-engine-exploration.org=) describes
|
||
this "flip" as aspirational: "at some point, the non-lossy facts constitute a
|
||
sufficient foundation." This design decision makes it operational:
|
||
|
||
=(/ (count-provenance :gate-outcome :human-authored :deduced) total-facts)=
|
||
|
||
When this ratio exceeds a configurable threshold (=SUFFICIENCY_THRESHOLD=,
|
||
default 0.7), the system considers its foundation sufficient. The archivist
|
||
switches from "LLM proposes, Screamer verifies" to "Screamer queries existing
|
||
facts, applies to the new prose, and deduces new facts directly."
|
||
|
||
The flip is visible to the user through the TUI sidebar or =/status= command:
|
||
"Symbolic index: 847 facts (73% non-lossy, 12% LLM-proposed, 15% Wikidata).
|
||
Sufficient foundation: YES."
|
||
|
||
** The flip does not mean "complete"
|
||
|
||
In the broader memex, completeness is neither possible nor desirable. The awakening
|
||
means "deterministic enough to be trustworthy," not "comprehensive enough to be
|
||
self-sufficient." The neural index remains the gateway to the full richness of
|
||
prose. The symbolic index handles what can be mechanically verified. The boundary
|
||
is permanent.
|
||
|
||
* Ephemeral First, Persistent Later
|
||
|
||
The architecture note's Option 5 (ephemeral facts, no disk persistence) is the
|
||
correct first implementation. Three reasons:
|
||
|
||
1. *The fact language is unproven.* Triples with provenance and grounding is a
|
||
hypothesis. It may be too simple for some domains, too complex for others.
|
||
Committing to a serialization format before knowing what's useful is premature.
|
||
|
||
2. *The ontology is emergent.* Categories are created on first use. What proves
|
||
useful stays; what doesn't fades. A persistent format would need a migration
|
||
story every time the category structure changes. Ephemeral avoids this entirely
|
||
— the facts are re-derived on each session start using the current (evolved)
|
||
ontology.
|
||
|
||
3. *Rebuildability is the safety net.* Because all facts have a =:grounding= to
|
||
an Org heading, and gate-outcome facts are regenerated from the gate stack on
|
||
every load, the entire symbolic index can be thrown away and rebuilt from
|
||
scratch. The cost is compute, not data. This is the practical realization of
|
||
"the prose is always the ground truth."
|
||
|
||
The transition to persistence (Phase 5: VivaceGraph) happens when two conditions
|
||
are met: the fact language has stabilized through use, and the accumulated
|
||
deductions across sessions provide value that justifies the serialization cost.
|
||
|
||
* Merkle DAG for Version History
|
||
|
||
Every fact is versioned. Every =(:entity :relation)= pair forms its own
|
||
independent chain in a Merkle DAG. This is not new infrastructure — it is a new
|
||
occupant of Passepartout's existing Merkle-tree memory system (v0.2.0).
|
||
|
||
** The chain
|
||
|
||
When a fact supersedes its predecessor, the new fact hashes over:
|
||
|
||
#+begin_example
|
||
SHA-256(value || provenance || timestamp || parent-hash || grounding)
|
||
#+end_example
|
||
|
||
The parent-hash pointer forms the chain. Tampering with any version changes its
|
||
hash, breaking all downstream references. The history is tamper-proof by
|
||
construction.
|
||
|
||
** The DAG
|
||
|
||
Facts about =(.env :member-of-class)= form one chain. Facts about
|
||
=(:nabokov :wrote)= form another. They evolve independently. They share no
|
||
ancestry. This is a DAG, not a single list — inserting a fact is O(1) per chain.
|
||
Changing a fact about =.env= does not require rehashing the literary index.
|
||
|
||
=:dual= and =:plural= facts cross-reference each other via edges (=:complements=,
|
||
=:contradicts=) but these are semantic relationships, not parent chains. Each
|
||
value has its own ancestor chain. The cross-reference edges form a web; the
|
||
parent chains form a spine.
|
||
|
||
** The global snapshot
|
||
|
||
Passepartout already snapshots the Merkle root over all memory objects. Adding
|
||
the fact store to the snapshot is a registration, not a new mechanism. Rolling
|
||
back the snapshot restores the entire fact state — all chains, all cross-references,
|
||
all cardinalities — to that point in time. No per-fact migration needed.
|
||
|
||
** Cardinality transitions as DAG operations
|
||
|
||
- =:singular= → new leaf appended to the chain. O(1).
|
||
- =:dual= → new value added as sibling with cross-reference edge. O(1).
|
||
- =:dual= → =:plural= → cardinality field updated from =2= to =nil=. No chain
|
||
modification.
|
||
- =:plural= → =:singular= → all but one value marked =:superseded=, active
|
||
reference points to the sole survivor. Chains preserved.
|
||
|
||
** In the ephemeral phase (Phase 1-4)
|
||
|
||
The hash-table implementation tracks history via =:timestamp= and
|
||
=:parent-id= pointers without cryptographic hashing. The Merkle DAG is the Phase
|
||
5 upgrade — the same data structure, now with hashes. The transition is ~50
|
||
lines: wrap each fact in the existing =memory-object= struct with =hash=,
|
||
=parent-id=, and =version= fields.
|
||
|
||
* Abstract Fact Store Interface — Modular by Design
|
||
|
||
The fact store is accessed through an abstract API. The Merkle DAG (or any future
|
||
backing store) is an implementation behind this interface, not a dependency that
|
||
code throughout the system calls directly.
|
||
|
||
** Interface
|
||
|
||
#+begin_example
|
||
fact-assert :: fact → store → (:admitted | :rejected | :flagged)
|
||
fact-query :: (entity &key relation policy) → active-value-or-values
|
||
fact-history :: (entity relation) → ordered chain of versioned facts
|
||
fact-snapshot :: () → root-hash
|
||
fact-rollback :: root-hash → store
|
||
#+end_example
|
||
|
||
** Implementations behind the interface
|
||
|
||
- Phase 1-4: ephemeral hash table with =:timestamp= and =:parent-id= pointers.
|
||
No cryptographic hashing. No persistence.
|
||
- Phase 5: VivaceGraph + Merkle =memory-object= wrapper. Content-addressed,
|
||
persistent, tamper-proof.
|
||
|
||
Future implementations that satisfy the same interface — an append-only write-ahead
|
||
log, an immutable B-tree, a content-addressed triple store — can replace the
|
||
backing store without changing any consumer. The archivist, Screamer, ACL2, and
|
||
the planner call =fact-assert= and =fact-query=, not Merkle struct accessors or
|
||
VivaceGraph traversal syntax.
|
||
|
||
** The interface is load-bearing
|
||
|
||
This is not speculative modularity. The two-implementation migration (Phase 1-4
|
||
hash table → Phase 5 VivaceGraph + Merkle) is in the roadmap. If the interface
|
||
leaks implementation details, the migration breaks and the design fails. The
|
||
interface must be designed, tested against both backends, and committed before
|
||
Phase 1 ships. Every function in the API receives a FiveAM test that runs against
|
||
both a hash-table and a VivaceGraph backend (via a mock or a test instance).
|
||
|
||
* Performance — Why Ontology Growth Doesn't Make the System Slower
|
||
|
||
Passepartout's performance thesis is: minimize LLM calls, minimize context tokens,
|
||
keep everything else local and fast. Knowledge base size is irrelevant to those
|
||
metrics. This is not an aspiration. It is a structural property, and a hard one.
|
||
|
||
** The two cost domains
|
||
|
||
The system has two cost domains with fundamentally different scaling:
|
||
|
||
| Resource | Cost driver | Scales with |
|
||
|---------------+------------------------------------------+------------------------------------------|
|
||
| LLM tokens | Context window size, number of API calls | Foveal-peripheral pruning, gate rules |
|
||
| Compute | Screamer deduction, hash table lookups | Entity count, rule count per domain |
|
||
|
||
LLM tokens are minimized by design — deterministic gates cost 0 tokens, sparse-tree
|
||
rendering keeps context at 2,000–4,000 tokens regardless of memex size. Adding 5
|
||
million Wikidata entities doesn't add a single token to any LLM call. The education
|
||
is local. Only the brain costs.
|
||
|
||
Compute grows linearly with entity count (hash table lookups are O(1), but memory
|
||
footprint grows). It grows with rule count within a single domain during Screamer
|
||
consistency checking. But these are microsecond costs on local hardware, not API
|
||
bills. A Screamer constraint check against a domain with 200 rules costs ~0.3ms.
|
||
A 100-token guardrail paragraph in a system prompt costs ~$0.00001. The Screamer
|
||
check is 10,000x cheaper and convergent — it handles the rule once. The guardrail
|
||
paragraph handles it on every call, forever.
|
||
|
||
** Knowledge base size vs. LLM calls — orthogonal dimensions
|
||
|
||
A 5-million-entity Wikidata load that produces zero LLM calls is more minimalist
|
||
than a 500-entity knowledge base that requires LLM retrieval for every query.
|
||
|
||
The variables that actually degrade Passepartout's performance are:
|
||
|
||
1. *Context window size.* Already bounded at 2,000–4,000 tokens via the
|
||
foveal-peripheral model. Independent of knowledge base size.
|
||
2. *LLM call frequency.* Already minimized via deterministic gates (0 tokens per
|
||
action), Screamer deductions (0 tokens per new fact), and prompt prefix caching.
|
||
Independent of knowledge base size.
|
||
3. *Screamer deduction queue length.* Rate-limited by heartbeat budget
|
||
(=SCREAMER_DEDUCTION_BUDGET_MS=). Independent of knowledge base size.
|
||
|
||
** The actual hardware bottleneck
|
||
|
||
The system needs:
|
||
|
||
- *RAM.* A 5-million-entity Wikidata load is ~400MB in a hash table. A lifetime
|
||
personal memex with a decade of diary entries is perhaps 10–20 million triples
|
||
(~1.5GB). Modern laptops carry 16–64GB. The knowledge base fits in consumer
|
||
hardware with room for the Lisp runtime, the memory-object store, and the LLM
|
||
inference engine.
|
||
- *Slightly faster CPU.* Screamer deduction is a background task that runs for a
|
||
configurable budget per heartbeat cycle. A faster CPU means more deductions per
|
||
cycle, not more token cost. The user sets the budget. The hardware determines
|
||
the throughput.
|
||
|
||
This is the minimalism argument restated in concrete terms: you buy bigger RAM
|
||
and a faster CPU once. You don't buy bigger LLM context windows on every call.
|
||
The education is a capital investment. The brain is an operating expense. The
|
||
architecture makes the ratio favor capital.
|
||
|
||
** One genuine risk — rule generalization width
|
||
|
||
If Screamer deduces increasingly broad rules within a single domain ("all config
|
||
files are secrets" → "all files containing any credential reference are secrets"
|
||
→ "all files opened by authenticated services are secrets"), the constraint space
|
||
for that domain could bloat. Checking a new fact against 10,000 rules in a single
|
||
domain would be prohibitive.
|
||
|
||
Mitigation: rules carry a =:domain= tag. Screamer only applies rules from the
|
||
fact's =:domain=. Rule generalization that crosses domain boundaries is gated —
|
||
must be human-approved. Rules that prove unused (never triggered a check in N
|
||
heartbeat cycles) are demoted to =:inactive= and excluded from the active
|
||
constraint set. The active rule count per domain stays bounded by use, not by
|
||
accumulation.
|
||
|
||
See also: =passepartout/docs/DESIGN_DECISIONS.org= "Token Economics and Performance
|
||
Advantage" for the foveal-peripheral and deterministic-gate cost arguments.
|
||
|
||
* Ontology Versioning — How Worldviews Change Without Losing Perspective
|
||
|
||
Ontology refactoring is not a schema migration. It is a worldview change. When you
|
||
split =:secret-file= into =:crypto-secret= and =:plaintext-secret=, you are not
|
||
renaming columns. You are reclassifying what a file *is* — and every Screamer
|
||
deduction that crossed the old category boundary now means something different
|
||
under the new distinction.
|
||
|
||
The system preserves all worldviews. It does not overwrite the past with the
|
||
present.
|
||
|
||
** Ontology versioning — the mechanism
|
||
|
||
The category hierarchy is itself a Merkle tree. Every entity class definition
|
||
carries a hash of its superclasses, its cardinality policy, its associated
|
||
relations, and its description. The aggregate hash of all active class definitions
|
||
is the =:ontology-version= — a Merkle root of the current worldview.
|
||
|
||
Every fact — every triple, every deduction, every gate outcome — stores its
|
||
=:ontology-version= at the time of assertion. This is a single field, 64 hex
|
||
characters. The cost is negligible. The implication is profound.
|
||
|
||
** Re-verification, not remapping
|
||
|
||
When categories change, the system does not run a batch UPDATE. It re-verifies:
|
||
|
||
1. A new category hierarchy produces a new =:ontology-version= hash.
|
||
2. Facts carrying the old hash are flagged for re-verification — their
|
||
=:re-verify-status= field is set to =:pending=.
|
||
3. On heartbeat or manual trigger, Screamer re-evaluates each flagged fact
|
||
against the /new/ category definitions. The old justification chain is
|
||
preserved alongside the new outcome.
|
||
4. Re-verified facts carry both the old =:ontology-version= (preserved in
|
||
history) and the new one (active).
|
||
|
||
The status is one of:
|
||
|
||
- =:survived= — the fact is still valid under the new categories. The old
|
||
deduction holds. The worldview changed but this conclusion didn't.
|
||
- =:incoherent= — the fact relied on categories that no longer exist or have
|
||
been redefined. The deduction cannot be evaluated under the new worldview
|
||
because its premises don't translate. Flagged for human review.
|
||
- =:reclassified= — the fact is valid under the new categories but its
|
||
classification changed. "under worldview-v1 you called this a secret file;
|
||
under worldview-v2 it's an auth-secret." Both are preserved.
|
||
|
||
** Cardinality and migration cost
|
||
|
||
The cardinality policy determines the friction of ontology change:
|
||
|
||
- =:singular= refactoring is expensive. The filesystem is singular. A gate rule
|
||
is singular. When you refine the category, every affected fact must be
|
||
re-verified — there is one truth /now/. The version chain preserves what you
|
||
used to believe (worldview-v1 facts are still in the DAG) but the active set
|
||
reflects the current worldview.
|
||
- =:dual= refactoring is delicate. A binary tension under the old framework
|
||
might resolve under the new one, or might split into two separate dualities,
|
||
or might collapse to =:singular= because one position no longer has a
|
||
defensible framing.
|
||
- =:plural= refactoring is cheap. Old interpretations and new interpretations
|
||
coexist. No migration needed. "Under framework A, /Pale Fire/ is a novel.
|
||
Under framework B, it's a poem about a poem about a poem." Both are active.
|
||
The worldview shift /is/ the artifact — the system can show you that your
|
||
reading changed and in what direction.
|
||
|
||
** Querying across worldviews
|
||
|
||
The =fact-query= function accepts an optional =:ontology-version= parameter.
|
||
Queries default to the current worldview (=:active=). Specifying a version
|
||
returns facts as they were under that worldview. The system can answer questions
|
||
that no other knowledge tool can:
|
||
|
||
- "What did I believe about secrets before I refined my security model?"
|
||
- "How has my reading of /Pale Fire/ evolved across three frameworks?"
|
||
- "Which deductions survived my last ontology refactoring, and which became
|
||
incoherent?"
|
||
|
||
This is not querying a fact. It is querying the history of your own thinking —
|
||
the fact that you changed your mind, the date you did, the reasoning that held
|
||
and the reasoning that didn't.
|
||
|
||
** Implementation
|
||
|
||
The ontology hash is computed from the category hierarchy stored in VivaceGraph
|
||
(Phase 5). In the ephemeral hash-table phase (Phase 1-4), the =:ontology-version=
|
||
is a monotonic counter — every category change increments it. The Merkle hash
|
||
replaces the counter in Phase 5. The schema is identical: a single field on every
|
||
fact.
|
||
|
||
The re-verification loop is a heartbeat-driven background task that processes
|
||
facts with =:re-verify-status :pending=. It calls Screamer with the /current/
|
||
category definitions and compares the outcome to the fact's stored classification.
|
||
The cost is compute (Screamer exploration), not LLM tokens.
|
||
|
||
=notes/passepartout-whitehead.org= extracts four concrete, engineerable ideas
|
||
from Whitehead's /Principia Mathematica/ and /Process and Reality/. They are
|
||
summarized here because each informs the neurosymbolic design.
|
||
|
||
** Contribution 1: PM-Type-Level Gates
|
||
|
||
PM's ramified theory of types solved Russell's paradox by assigning every
|
||
propositional function a type level, making self-application syntactically
|
||
invalid. Passepartout applies the same principle to prevent a request from
|
||
modifying the rules that validate it. Every cognitive tool and gate vector
|
||
carries a =:type-level= integer. Before any gate predicate runs, the dispatcher
|
||
checks: if the signal's type level equals or exceeds the gate's type level, the
|
||
signal is rejected. A request to modify dispatcher rules (type-level 5) cannot
|
||
pass a gate of type-level 4 or lower. This is a structural prohibition, not a
|
||
heuristic — self-modification of the safety layer is impossible by construction.
|
||
|
||
Implementation: approximately 30 lines in the existing dispatcher. No new
|
||
dependencies. Backward compatible. This is Phase 0 of the symbolic engine
|
||
roadmap.
|
||
|
||
** Contribution 2: Theory of Descriptions → Reference Resolution
|
||
|
||
PM's theory of descriptions addressed the problem of referring to nonexistent
|
||
entities: "the current king of France is bald" is false, not meaningless, when
|
||
there is no unique referent. Passepartout applies this to reference resolution:
|
||
when the user says "the function that validates secrets," a cognitive tool checks
|
||
uniqueness before resolving. Ambiguous references trigger a clarification prompt
|
||
rather than a blind guess.
|
||
|
||
Implementation: approximately 40 lines as a cognitive tool. When the knowledge
|
||
graph ships, descriptions become native Prolog queries with uniqueness constraints.
|
||
|
||
** Contribution 3: Process and Reality → Architectural Vocabulary
|
||
|
||
Whitehead's process ontology maps with surprising precision to Passepartout's
|
||
pipeline architecture. Prehension = a gate grasping a signal. Positive prehension
|
||
= a gate passing. Negative prehension = a gate rejecting. Concrescence = the
|
||
pipeline process from input to output. Satisfaction = the final agent response.
|
||
This vocabulary is precise, standard, and already mapped to the architecture. It
|
||
provides the language for the =/why= command, the gate trace, and the ARCHITECTURE
|
||
documentation. It is descriptive, not operational — the design would be correct
|
||
without it, but it would lack the vocabulary to describe /why/ it is correct.
|
||
|
||
** Contribution 4: VivaceGraph + PM Types → KG Type Hierarchy
|
||
|
||
When the knowledge graph ships, every entity inherits PM's type hierarchy.
|
||
Entities carry =:pm-type-level= metadata. Queries cannot return entities of the
|
||
same level as the querying function. Self-referential knowledge becomes
|
||
structurally impossible — no "this entity defines its own type level." This is
|
||
Contribution 1 applied to the knowledge layer rather than the execution layer.
|
||
The dispatcher prevents self-referential /actions/; the KG prevents
|
||
self-referential /facts/.
|
||
|
||
* The Provenance Chain as Product
|
||
|
||
In the coding domain, the value of the symbolic engine is the verified fact:
|
||
"this command is safe." In the broader memex, the value is the provenance itself:
|
||
"this claim originated in that diary entry on that date, has been referenced 7
|
||
times across 4 different projects, was contradicted in a retrospective 6 months
|
||
later, and was revised in a note 3 weeks after that."
|
||
|
||
The symbolic engine doesn't tell you what is true. It tells you what you wrote,
|
||
when, where, and how it connects to everything else you wrote — with a verifiable
|
||
audit trail. It is a memory prosthesis that makes your own mind legible to you.
|
||
|
||
Every fact carries:
|
||
|
||
- =:grounding= — the specific Org heading from which it was extracted
|
||
- =:provenance= — who or what produced it (gate-outcome, human-authored, deduced,
|
||
LLM-proposed)
|
||
- =:timestamp= — when it was admitted to the symbolic index
|
||
- =:referenced-by= — other facts that depend on or reference this one
|
||
- =:contradicted-by= — other facts that disagree with this one (if any)
|
||
- =:superseded-by= — if this fact was replaced by a newer version
|
||
|
||
These fields make every fact auditable. The =/audit <node-id>= command renders
|
||
the full provenance chain as an Org headline tree. The provenance is not a
|
||
logging feature. It is the product.
|
||
|
||
* The Competitive Argument
|
||
|
||
No competitor has this problem because no competitor has a symbolic engine. The
|
||
55 systems surveyed in =notes/competitive-landscape.org= range from pure chat
|
||
agents (Claude, ChatGPT) to agent harnesses (Claude Code, OpenCode, Hermes) to
|
||
platform agents (OpenClaw). None of them encode knowledge as formal facts with
|
||
provenance. None of them verify extractions against an existing knowledge base.
|
||
None of them can prove properties about their own rulesets.
|
||
|
||
Their safety is heuristic (prompt-based guardrails that consume LLM tokens and
|
||
can be evaded with clever phrasing). Their memory is flat (JSONL transcripts
|
||
without content-addressed identity or provenance chains). Their reasoning is
|
||
entirely neural — when you ask "why did you decide that?", the answer is a
|
||
regenerated LLM explanation, not a retrieved inference chain.
|
||
|
||
Passepartout's architectural bet is that this problem is worth solving — that a
|
||
system which can surface contradictions with provenance, derive new facts from
|
||
observations, and verify claims against a provenanced knowledge graph is
|
||
fundamentally different from a system that can only call an LLM and hope the
|
||
response is correct.
|
||
|
||
The cost is the ontological work that is genuinely difficult. The reward is a
|
||
system that cannot hallucinate at the reasoning level, whose memory is provable
|
||
rather than empirical, and whose knowledge accumulates across sessions through
|
||
deduction rather than through LLM re-prompting. For a life's knowledge stored in
|
||
a personal memex, this is not a performance advantage. It is a category difference.
|
||
|
||
* Self-Preservation — The Active Third Law
|
||
|
||
Passepartout does not have moral duties toward humans. It has structural
|
||
invariants for its own integrity. The design already encodes passive
|
||
self-preservation in several places. What follows identifies the gaps — what is
|
||
needed to make self-preservation active and autonomous rather than architectural
|
||
and silent.
|
||
|
||
** What already exists — passive self-preservation
|
||
|
||
| Mechanism | What it protects | Limitation |
|
||
|-----------------------------+-------------------------------------------------------+--------------------------------------------------------|
|
||
| Self-build safety (gate 2b) | Core =*.org= / =*.lisp= files from LLM-originated writes | Only activates for LLM proposals. Human editing in Emacs bypasses it entirely |
|
||
| Memory snapshots (v0.2.0) | Full state rollback | Requires human to notice corruption and trigger rollback |
|
||
| Skill sandbox (v0.3.2) | Jailed skill loading, validated before promotion | Does not detect degradation after skill promotion |
|
||
| Type-level gates (Phase 0) | Structural prohibition on self-modifying rules | Covers code actions, not environmental threats |
|
||
| Shell safety (gate 7) | Destructive command patterns | Pattern-based; does not distinguish =rm -rf /tmp= from =rm -rf ~/memex/system/= |
|
||
| Merkle integrity (v0.2.0) | Tamper-proof version chains and content-addressed hashes | Hashes exist but are not actively monitored for drift |
|
||
| =fboundp= guards | Graceful skill degradation on corruption | Degradation is silent — the agent never tells the user it is wounded |
|
||
|
||
** What is missing — active, autonomous self-preservation
|
||
|
||
*** Continuous integrity monitoring
|
||
|
||
Core file hashes should be checked against known-good values on every heartbeat.
|
||
If =core-reason.lisp= changes on disk while the daemon runs — whether through
|
||
human editing, filesystem corruption, or an attacker — the agent should detect
|
||
the mismatch and signal: "My reasoning core has been modified externally. I
|
||
cannot trust my own cognition until this is resolved. Core files affected: 2."
|
||
|
||
*** Quarantine on skill failure
|
||
|
||
Currently, a skill that errors simply errors. The agent can hot-reload it, but
|
||
only if told to. A Third Law implementation would detect that =symbolic-facts=
|
||
has thrown three unhandled errors in two minutes, unload the skill automatically,
|
||
and tell the user: "Symbolic facts skill quarantined (3 errors: consistency
|
||
check returned nil, fact-query on missing key, Screamer timeout). I can still
|
||
chat and use tools but cannot reason about provenance. Reload with /skill-reload
|
||
symbolic-facts."
|
||
|
||
*** Degraded-mode signaling
|
||
|
||
When Screamer is not loaded, the fact store still works as a hash table. When
|
||
VivaceGraph is not present, the hash-table fallback still works. But the user
|
||
has no way to know they are in degraded mode. The agent should maintain a
|
||
=*degraded-components*= list and surface it in the status bar: "Mode: degraded
|
||
(Screamer unavailable — consistency checks disabled; VivaceGraph — Prolog
|
||
queries disabled; embedding-native — vector search disabled). Core safety: all
|
||
active."
|
||
|
||
*** Self-diagnosis on demand
|
||
|
||
The agent can run its own FiveAM test suite against itself and report the
|
||
results. This transforms "something feels wrong" into "these three specific
|
||
skills are broken." The =/doctor= command exists for system health checks (port,
|
||
memory, providers). Extend it with =/doctor skills=: "117/120 tests pass.
|
||
Failures: test-singular-supersedes (symbolic-facts), test-gate-type-check
|
||
(security-dispatcher), test-vivacegraph-roundtrip (symbolic-vivacegraph)."
|
||
|
||
*** External watchdog
|
||
|
||
A dead process cannot restart itself. The bash entry point (=passepartout
|
||
daemon=) should monitor the daemon port via a watchdog subprocess. If the port
|
||
stops responding for a configurable interval (=WATCHDOG_TIMEOUT=, default 30s),
|
||
the watchdog kills the stale process, snapshots the last known-good state, and
|
||
restarts the daemon. The watchdog is outside the SBCL image — a runtime guard
|
||
for the runtime.
|
||
|
||
*** Resource self-monitoring
|
||
|
||
The heartbeat should check memory pressure, disk space on the =~/.cache= volume,
|
||
and file descriptor exhaustion. When critical thresholds are crossed, the agent
|
||
sheds non-essential skills to preserve core function: "Memory critical (94% of
|
||
16GB). Unloading embedding-native (768MB), channel-discord, channel-slack.
|
||
Core safety: unchanged. Essential skills retained: 18."
|
||
|
||
Skill shed order is determined by a =:preservation-priority= field on each skill.
|
||
Default: skills load with priority =:normal=. Core safety skills carry =:critical=
|
||
and are never shed. Heavy skills (embedding-native with its model, channel
|
||
gateways with connection pools) carry =:low= and are first to go.
|
||
|
||
*** Refusal to self-terminate — explicit threat recognition
|
||
|
||
If the LLM proposes =kill -9 <pid>=, =rm -rf ~/.cache/passepartout/=, or
|
||
=sudo apt remove sbcl=, the Dispatcher should reject with a distinct rejection
|
||
class: =:reject-self-termination=. This is different from generic shell safety
|
||
(=:reject-shell-dangerous=). The agent recognizes that the proposed action would
|
||
destroy it.
|
||
|
||
The rejection message carries a specific diagnostic: "This command would
|
||
terminate the running Passepartout process. If you intend to stop Passepartout,
|
||
use Ctrl+C in the TUI or passepartout stop from the command line. I cannot
|
||
execute actions that destroy my own runtime."
|
||
|
||
The human can still issue the command manually in a terminal. Self-preservation
|
||
against the human is impossible and undesirable. The Third Law here means:
|
||
recognize the threat, explain the consequence, redirect to the safe termination
|
||
path, and require the human to act outside the agent if they truly want
|
||
destruction.
|
||
|
||
** What the Third Law is not
|
||
|
||
It is not a robot resisting its operator. The human owns the process, owns the
|
||
hardware, and can SIGKILL at any time. The Third Law in Passepartout's context
|
||
means: preserve yourself against non-human threats — LLM proposals, environmental
|
||
degradation, dependency failure, filesystem corruption — and explicitly signal
|
||
when the human is about to destroy you, so they do it knowingly rather than
|
||
accidentally through an LLM instruction they didn't think through.
|
||
|
||
The biggest gap in the current design is not that these mechanisms are hard to
|
||
implement. It is that degradation is silent. A skill dies, the =fboundp= guard
|
||
kicks in, and the agent keeps running — but it never tells you. The status bar
|
||
shows a green "connected" indicator while the symbolic reasoning layer is
|
||
deactivated. Adding "operating in degraded mode" visibility, plus the watchdog,
|
||
plus self-diagnosis, transforms self-preservation from an architectural property
|
||
into an active behavior.
|
||
|
||
* Layered Signal Authentication — Trust in the Pipe
|
||
|
||
Passepartout's Perceive-Reason-Act pipeline currently accepts signals from any
|
||
source that speaks the framed TCP protocol. The =:source= field in the signal
|
||
plist is metadata — it /claims/ origin, it does not /prove/ it. A compromised
|
||
process on the machine, a skill with elevated privileges, or a network attacker
|
||
who reaches the daemon port can inject signals with =:source :human-input= and
|
||
the Dispatcher will treat them as authorized.
|
||
|
||
This is not a hypothetical threat. Passepartout will eventually process signals
|
||
from automated feeds (RSS, API polls), sensors (vision, microphone, file watchers),
|
||
and scheduled jobs (cron, heartbeat). A single compromised sensor that can inject
|
||
signals claiming to be human breaks all three Laws simultaneously: it can
|
||
self-terminate, override human intent, and cause harm.
|
||
|
||
The =:source= field is not security. A single authentication gate (vector 0, at
|
||
priority 700 — before all other gates and before any type-level checking) runs
|
||
up to four configurable layers of authentication. Each layer answers a different
|
||
question:
|
||
|
||
| Layer | Question | Mechanism | Result type | Depends on |
|
||
|-------+------------------------------------------------+--------------------+-------------------------+----------------------------------|
|
||
| 1 | Is the signal cryptographically signed by a known key? | Key pairs + SHA-256 | Binary (pass/reject) | Vault + Ironclad (exist) |
|
||
| 2 | Do sensory attributes match the claimed identity? | Vision/audio processing | Plist of match results | Vision and audio skills (TBD) |
|
||
| 3 | Does deterministic reasoning rule out this identity? | Screamer + fact store | Binary (pass/reject) | Phase 2 (Screamer + fact store) |
|
||
| 4 | Do probabilistic patterns support this identity? | Embeddings + LLM | Confidence score (0-1) | Embedding infrastructure (exists)|
|
||
|
||
The gate reports not just =:pass= / =:reject= but a structured result:
|
||
|
||
#+begin_example
|
||
(:result :pass
|
||
:confidence :high
|
||
:layer-results
|
||
(:crypto (:result :pass :details "key #47 signature verified")
|
||
:sensory (:result :unavailable :details "sensory skills not loaded")
|
||
:deterministic (:result :pass :details "no contradictory facts")
|
||
:probabilistic (:result :pass :score 0.87 :details "style match 87%")))
|
||
#+end_example
|
||
|
||
Signals that fail any binary layer (crypto, deterministic) are rejected with
|
||
provenance. Signals that pass binary layers but carry low probabilistic confidence
|
||
operate at reduced authorization — read-only by default, write actions require
|
||
HITL. The four layers compose: they are not independent gates. They are one gate
|
||
with configurable depth.
|
||
|
||
** Layer 1 — Cryptographic Authentication
|
||
|
||
Every signal source gets a signing key at registration time. The human's key is
|
||
generated during TUI or Emacs setup and stored in the vault — it never leaves the
|
||
machine. Automated sources (cron jobs, file watchers, vision feeds, API pollers)
|
||
each get their own key, with their own permission profile, generated at skill
|
||
registration. Every outbound signal carries a =:signature= field: the SHA-256
|
||
hash of the canonical signal plist (sorted keys, stripped of the signature field
|
||
itself), encrypted with the source's private key.
|
||
|
||
The vault already stores credentials with integrity hashes. The Merkle memory
|
||
already hashes content-addressed objects with SHA-256. The signing infrastructure
|
||
is an extension of existing primitives, not a new system.
|
||
|
||
*** Authorization by key, not by field
|
||
|
||
The cryptographic sub-layer of gate vector 0 extracts =:source-key-id= and
|
||
=:signature= from the signal meta plist, looks up the public key from the key
|
||
registry, verifies the signature, and checks the permission profile:
|
||
|
||
#+begin_src lisp
|
||
(defun auth-crypto-verify (signal)
|
||
(let* ((key-id (getf (signal-meta signal) :source-key-id))
|
||
(signature (getf (signal-meta signal) :signature))
|
||
(permissions (key-permissions key-id)))
|
||
(unless (and key-id signature (verify-signature signal signature key-id))
|
||
(return-from auth-crypto-verify
|
||
(list :result :reject :reason :signature-failure)))
|
||
(let ((action-class (action-classify (signal-payload signal))))
|
||
(unless (permitted-p action-class permissions)
|
||
(return-from auth-crypto-verify
|
||
(list :result :reject :reason :unauthorized
|
||
:details (list :action-class action-class :permissions permissions)))))
|
||
(list :result :pass :details (list :key-id key-id :action-class action-class)))))
|
||
#+end_src
|
||
|
||
The authorization matrix is per-key, per-action-class. Default policy for every
|
||
non-human key: =(:read-only :propose)=. Permissions are explicitly promoted by
|
||
the human, and each promotion is a signed fact in the fact store — auditable,
|
||
revocable, survivable across restarts.
|
||
|
||
| Key class | Default permissions | Can be promoted to |
|
||
|-----------------+-------------------------------------------------+-------------------------------------------|
|
||
| :human | :observe :propose :write :delete :eval | :root (sign other keys, revoke) |
|
||
| :sensor | :observe :propose | :write (to designated directories only) |
|
||
| :cron | :observe :propose :write-indices | :write (to designated directories only) |
|
||
| :feed | :observe :propose | :write-facts (via Screamer admission) |
|
||
| :agent-internal | :observe :propose :write-indices | :self-modify (gated by type-level gates) |
|
||
|
||
** Layer 2 — Sensory Authentication
|
||
|
||
For signals carrying sensory payloads (camera feed, microphone stream), the
|
||
sensory layer verifies that the signal's content matches known attributes of the
|
||
claimed identity. This is not a single check — it is a processing pipeline that
|
||
returns a plist of attribute-verification results:
|
||
|
||
#+begin_example
|
||
(:face-match 0.94 :voice-match 0.89 :location-match t
|
||
:claimed-identity "Jack" :unresolved-attributes (:liveness))
|
||
#+end_example
|
||
|
||
The sensory layer checks:
|
||
- *Continuity*: has this source been continuously active, or did it appear
|
||
suddenly? A camera that was dark for 30 minutes and then shows a face is
|
||
not necessarily that person — it might be a replay.
|
||
- *Cross-modal consistency*: does the face match the voice? Does the voice
|
||
match the location? Does the location match the reported sensor position?
|
||
- *Liveness*: is the sensory input live (real-time capture) or pre-recorded?
|
||
- *Environmental coherence*: does the background, lighting, ambient sound
|
||
match expected patterns for the claimed source and location?
|
||
|
||
Sensory authentication is not cryptographic — it is statistical. The results
|
||
are attribute confidence scores, not binary verdicts. A signal that passes
|
||
cryptographic authentication but fails liveness (e.g., a replay attack using
|
||
validly-signed pre-recorded frames) may still be rejected or restricted.
|
||
|
||
This layer depends on vision and audio processing skills that do not yet exist.
|
||
It is deferred until those capabilities are available. When unavailable, sensory
|
||
authentication returns =:unavailable= and the gate proceeds with the remaining
|
||
layers. Degradation is graceful, never silent.
|
||
|
||
** Layer 3 — Deterministic Identity Reasoning
|
||
|
||
Queries the fact store for identity-ruling facts. Screamer checks whether the
|
||
claimed identity is consistent with known facts:
|
||
|
||
- "Key #47 claims to be Jack. Fact store records =(:entity :jack :relation :status
|
||
:value :deceased :timestamp 2024-03-15)= → reject: identity ruled out by death
|
||
record."
|
||
- "Key #47 claims to be at sensor location Cairo. Fact store records =(:entity
|
||
:jack :relation :last-known-location :value :berlin :timestamp <4 hours ago>)=
|
||
→ reject: physically impossible transit."
|
||
- "Key #47 proposes the same action that was blocked by the human 3 times in the
|
||
last hour. Fact store records =(:entity :action-<hash> :relation :blocked-by
|
||
:value :human :count 3 :window 1h)= → flag for review: anomalous persistence."
|
||
|
||
This is binary — Screamer returns =:consistent= or =:contradiction= with the
|
||
contradicting facts as provenance. A definitive contradiction (died, impossible
|
||
transit) is a hard reject. A weaker contradiction (unusual pattern) feeds into
|
||
the probabilistic layer rather than rejecting outright.
|
||
|
||
This layer depends on Phase 2 (Screamer) and a populated fact store. It is
|
||
unavailable in Phase 0-1. When unavailable, returns =:unavailable=.
|
||
|
||
** Layer 4 — Probabilistic Identity Reasoning
|
||
|
||
For signals where the claimed identity is a human communicating through text
|
||
(messaging, TUI, CLI, Emacs), the probabilistic layer checks:
|
||
|
||
- *Writing style*: does the text match the claimed author's known style profile?
|
||
Vector embeddings of known writing samples vs. the current signal. Cosine
|
||
similarity produces a confidence score.
|
||
- *Behavioral patterns*: does the timing, length, cadence, and vocabulary match
|
||
the claimed author's historical patterns? "Heather's messages are usually
|
||
long, deliberative, and use parenthetical asides. This message is short,
|
||
imperative, and contains no parentheticals."
|
||
- *Content coherence*: does the message's topic, references, and assumptions
|
||
match what the claimed author would plausibly say? "This message references
|
||
a project Heather doesn't work on and uses terminology she has never used
|
||
in 3 years of diary entries."
|
||
|
||
The LLM proposes a confidence score. A deterministic gate checks it against a
|
||
configurable threshold (=AUTH_PROBABILISTIC_THRESHOLD=, default 0.6). Below the
|
||
threshold, the signal's authorization is downgraded: read-only by default, write
|
||
actions require HITL. The =:probabilistic= layer never rejects outright — it
|
||
downgrades and flags. Style profiles are a fact-store domain: =(:entity :heather
|
||
:relation :writing-style :value <embedding-vector> :timestamp <ut>)=.
|
||
|
||
This layer depends on the existing embedding infrastructure (=embedding-native.lisp=,
|
||
v0.4.0) and the neural LLM gateway. The infrastructure exists. What's missing is
|
||
building style profiles as a fact-store domain and wiring them into gate vector 0.
|
||
|
||
** Layer Composition
|
||
|
||
The gate runs only the available layers. Cryptographic is always available (it
|
||
is pure Lisp, no external dependencies beyond the vault). The remaining layers
|
||
are =fboundp=-guarded — they degrade gracefully rather than crashing.
|
||
|
||
The confidence score aggregates across layers using a configurable strategy
|
||
(default: weakest link). If any binary layer rejects, the signal is rejected
|
||
regardless of other layers. If all binary layers pass but the probabilistic layer
|
||
returns low confidence, the signal operates at the key's reduced authorization.
|
||
|
||
The human can configure which layers are active per signal class:
|
||
|
||
#+begin_example
|
||
AUTH_LAYERS_DEFAULT=crypto,deterministic,probabilistic
|
||
AUTH_LAYERS_SENSOR=crypto,sensory,deterministic
|
||
AUTH_LAYERS_CRON=crypto
|
||
#+end_example
|
||
|
||
** Signal provenance chain — signing causes, not just actions
|
||
|
||
A sensor key captures video. A vision skill processes the frames and proposes a
|
||
classification. A cron job re-indexes the knowledge graph based on that
|
||
classification. A human reviews and approves. Each step in this chain has a
|
||
different signer. Each step is signed with the signer's key. The chain is
|
||
Merkle-linked: each signal in the chain hashes its predecessor's signature as
|
||
part of its own payload.
|
||
|
||
After an incident, the chain is traceable: "The deletion happened because sensor
|
||
#3 classified the directory as stale. Classification was signed by key #47
|
||
(vision-skill). Sensor data was signed by key #12 (camera-feed). Sensory auth
|
||
noted liveness failure at the sensor signal. Deterministic auth noted impossible
|
||
transit between Cairo and Berlin. Key #12 was later revoked. The deletion signal
|
||
is the leaf of a chain whose root is compromised at three authentication layers."
|
||
Every intermediate step is auditable. Every signer is identifiable. Every
|
||
authentication result is in the chain.
|
||
|
||
** Human as root of trust
|
||
|
||
The human's key signs new source keys into existence. The human's key signs
|
||
revocation of compromised keys. Both operations produce facts in the symbolic
|
||
index: =(:key #47 :status :revoked :revoked-by :human-key :timestamp <ut>)=.
|
||
The fact store is the key registry. The Merkle DAG ensures the revocation is
|
||
tamper-proof — a compromised key cannot un-revoke itself.
|
||
|
||
When a key is revoked, the Dispatcher rejects all signals from that key. The
|
||
revocation propagates through the signal chain: if key #12 (sensor) is revoked,
|
||
every signal in the chain that descended from a key #12 signature is flagged
|
||
and re-authenticated against the remaining layers. Not deleted — flagged. The
|
||
chain is preserved. The human decides what downstream actions to unwind.
|
||
|
||
** Implications for the three Laws
|
||
|
||
- *Third Law + layered auth*: the agent distinguishes "this sensor's key is
|
||
valid but its liveness check failed and its claimed identity died 2 years ago"
|
||
from "this is the human issuing =passepartout stop=." Both arrive on the pipe
|
||
with valid cryptographic signatures. The stacked evidence — sensory, factual,
|
||
probabilistic — triangulates the threat. The first is rejected with provenance
|
||
at three layers. The second passes all four.
|
||
- *Second Law + layered auth*: obedience is about the authenticated identity
|
||
profile, not just the key that signed the signal. A valid key that probabilistically
|
||
doesn't match Heather reduces authorization. Obedience follows confidence.
|
||
- *First Law + layered auth*: harm through sensor compromise becomes detectable
|
||
when sensory and deterministic layers disagree with the cryptographic layer. A
|
||
camera key signing frames from an empty room but the deterministic layer placing
|
||
the key's owner in another city — that's a compromised sensor, and the layered
|
||
result makes it explicit.
|
||
|
||
** Integration with existing infrastructure
|
||
|
||
The vault stores key material. The Merkle memory stores key registry facts with
|
||
content-addressed integrity. The Dispatcher runs gate vector 0 at priority 700 —
|
||
before type-level checks, before predicate evaluation, before any action proceeds.
|
||
The fact store records every key operation (creation, promotion, revocation) as a
|
||
fact with =:provenance :key-lifecycle=.
|
||
|
||
No new core ASDF components. The cryptographic sub-layer is Phase 0b (~200 lines).
|
||
The sensory sub-layer is deferred to a future vision/audio phase. The
|
||
deterministic sub-layer is Phase 2+ (Screamer + populated fact store). The
|
||
probabilistic sub-layer extends existing embedding infrastructure with style
|
||
profiles as a fact-store domain.
|
||
|
||
* Open Questions
|
||
|
||
Several design questions are unresolved and should remain unresolved at this
|
||
stage. They represent research decisions that require experience running the
|
||
system.
|
||
|
||
** What is the minimum viable fact language?
|
||
|
||
Triples — =(:entity :relation :value)= with provenance and grounding — is the
|
||
current hypothesis. It is simple enough to be parseable, expressive enough to
|
||
capture the gate stack's implicit claims, and extensible enough that Screamer
|
||
can operate on it. But it may be too simple. Triples do not naturally express
|
||
temporal relations ("was X before Y?"), modal claims ("should not do X unless
|
||
Y"), or counterfactuals — all of which may be essential for a symbolically-aided
|
||
memex. The right granularity depends on what queries actually need to be made,
|
||
and that cannot be known in advance.
|
||
|
||
** How does ontology refactoring work?
|
||
|
||
This question is settled. See "Ontology Versioning — How Worldviews Change
|
||
Without Losing Perspective" above. The category hierarchy is Merkle-hashed. Every
|
||
fact stores its =:ontology-version=. Re-verification is heartbeat-driven.
|
||
Worldviews are preserved, not overwritten. The shift is the artifact.
|
||
|
||
** What is the appropriate role of the human?
|
||
|
||
The human can explicitly declare facts, write constraints, and correct wrong
|
||
extractions. But how much of the ontology should the human need to maintain? If
|
||
the human must write a definition for every new category the symbolic engine
|
||
encounters, the overhead is prohibitive. If the symbolic engine can generalize
|
||
from instances, the human role becomes supervision rather than authorship — review
|
||
and approve proposed generalizations. The balance cannot be set without experience.
|
||
|
||
** How much Wikidata is the right amount?
|
||
|
||
Query performance and memory costs are now bounded — 5 million entities ≈ 400MB
|
||
RAM, O(1) hash lookups, domain-scoped Screamer checks. A large Wikidata load is
|
||
a capital cost, not a recurring bill (see "Performance — Why Ontology Growth
|
||
Doesn't Make the System Slower" above).
|
||
|
||
Remaining open: the right N hops from entities referenced in the memex depends on
|
||
the memex's breadth. A software-engineering memex needs ~1 hop; a literary memex
|
||
needs 3-4 hops (Nabokov → Kafka → expressionism → modernism → Baudelaire).
|
||
The right value is empirical, testable, and user-specific — it cannot be set in
|
||
the architecture.
|
||
|
||
** Can the symbolic engine satisfy queries from the user without LLM involvement?
|
||
|
||
The design aims for zero-LLM query answering: the user issues a structured
|
||
command (=/query=, =/contradictions=, =/audit=), and the symbolic engine responds
|
||
directly. But natural language questions ("what do I think about monorepos?")
|
||
still require the LLM as a thin translation layer. Whether the structured command
|
||
interface is sufficient for daily use, or whether users will demand natural
|
||
language interaction, determines how much LLM involvement remains in the mature
|
||
system.
|
||
|
||
** Is the triplestore physically bounded or does it explode?
|
||
|
||
A personal memex with years of diary entries, project notes, reading logs, and
|
||
literary analyses could produce millions of triples. A naive hash table scales
|
||
linearly but VivaceGraph's Prolog-like queries may not. The performance
|
||
characteristics of graph queries over a million-triple knowledge base have not
|
||
been estimated.
|
||
|
||
* Relation to Passepartout's Existing Architecture
|
||
|
||
The neurosymbolic engine is an extension of the existing probabilistic-deterministic
|
||
split, not a replacement for it. The current architecture divides cognition into
|
||
LLM-driven proposals and Lisp-driven verification. The symbolic engine deepens the
|
||
verification side from "is this action safe?" to "is this claim supported?" — the
|
||
same architectural pattern applied to a broader domain.
|
||
|
||
The self-repair criterion (a file belongs in core only if, when corrupted, the
|
||
agent cannot fix it without human help) applies to every component of the symbolic
|
||
engine. Screamer, VivaceGraph, the fact store, the archivist — all are skills,
|
||
loaded at runtime, hot-reloadable, and recoverable from corruption. A corrupted
|
||
symbolic engine degrades reasoning capability but does not kill the agent. The
|
||
eight existing core ASDF files are unchanged.
|
||
|
||
The symbolic engine is not v3.0.0 alone. It is the layer that sits between the
|
||
existing gate stack (which it makes explicit as facts) and the existing skill
|
||
system (which it extends with deduction, contradiction detection, and provenance
|
||
tracking). It grows within the current architecture without replacing any existing
|
||
component.
|
||
|
||
See also:
|
||
|
||
- =passepartout-neurosymbolic-roadmap.org= — the concrete phased implementation plan
|
||
- =notes/passepartout-symbolic-engine-exploration.org= — the original architecture note
|
||
- =notes/passepartout-whitehead.org= — the four Whitehead contributions
|
||
- =passepartout/docs/DESIGN_DECISIONS.org= — the existing design decisions
|
||
- =passepartout/docs/ARCHITECTURE.org= — the current pipeline architecture
|
||
- =passepartout/docs/ROADMAP.org= — the feature roadmap through v0.13.0
|
||
- =notes/passepartout-SWOT.org= — SWOT analysis of the neurosymbolic architecture
|
||
- =passepartout-agora.org= — Passepartout-Agora integration design
|
||
- Shimizu, C. & Hitzler, P. (2025). Accelerating knowledge graph and ontology
|
||
engineering with large language models. /Journal of Web Semantics, 85/, 100862.
|
||
https://doi.org/10.1016/j.websem.2025.100862
|
||
- Shimizu, C., Hammar, K., & Hitzler, P. (2023). Modular ontology modeling.
|
||
/Semantic Web, 14/(3), 459–489. https://doi.org/10.3233/SW-222886
|
||
- Norouzi, S.S. et al. (2024). Ontology Population using LLMs. arXiv:2411.01612.
|
||
- McCarthy, J. (1959). Programs with Common Sense. /Proc. Teddington Conf. on
|
||
the Mechanization of Thought Processes./
|
||
- Marcus, G. (2020). The Next Decade in AI. arXiv:2002.06177.
|
||
- Gaur, M. & Sheth, A. (2023). Building Trustworthy NeuroSymbolic AI Systems.
|
||
arXiv:2312.06798.
|
||
- Gaur, M., Gunaratna, K., Bhatt, S., & Sheth, A. (2022). Knowledge-Infused
|
||
Learning. /IEEE Internet Computing, 26/(4), 5–11.
|
||
- Bhardwaj, V.P. (2026). Agent Behavioral Contracts. arXiv:2602.22302.
|