memex: update AGENTS.md with ROADMAP TODO workflow, bump passepartout to v0.8.0

- AGENTS.md: add steps 0 (read next TODO from ROADMAP) and 6 (mark DONE
  with LOGBOOK) to development cycle
- Notes updates accumulated during v0.8.0 work
- Bump passepartout submodule to v0.8.0
This commit is contained in:
2026-05-09 15:00:35 -04:00
parent 4e9431ec1d
commit 04944a62e2
4 changed files with 1209 additions and 140 deletions

View File

@@ -21,7 +21,7 @@ architecture exploration is in
=notes/passepartout-symbolic-engine-exploration.org=. Whitehead's contributions are
enumerated in =notes/passepartout-whitehead.org=.
* Phase 0: PM-Type-Level Gates (~30 lines — builds on existing Dispatcher)
* Phase 0: PM-Type-Level Gates + Core Integrity (~75 lines — builds on existing Dispatcher)
** What
@@ -52,13 +52,26 @@ syntactically invalid before any logical evaluation.
write-file at 3, read-file at 1, shell at 2, eval at 4.
4. Assign type levels to existing gate vectors: self-build boundary at 5,
shell safety at 3, path protection at 2, network exfil at 2, secret content at 1.
5. Add =dispatcher-check-self-termination=: scan shell commands for patterns
targeting the Passepartout process (=kill -9 <pid>=, =rm -rf ~/.cache/passepartout/=,
=sudo apt remove sbcl=). Return =:reject-self-termination= with a diagnostic
message explaining which command matched and why it would destroy the agent.
Human override is possible via HITL — the gate does not prevent the human
from issuing the command in a terminal. It prevents the /LLM/ from issuing
it accidentally. ~20 lines.
6. Add =integrity-verify-core-files=: on heartbeat, hash the eight core files
against known-good values stored at daemon startup. On mismatch, inject an
integrity alert into the signal queue. ~25 lines, uses existing SHA-256
infrastructure from v0.2.0 Merkle memory.
** Verification
Existing FiveAM gate tests continue to pass. New test: signal at type-level 5
targeting a gate at type-level 4 returns =:reject-type-violation= without
evaluating the gate predicate. New test: signal at type-level 1 passing through
a gate at type-level 3 proceeds to predicate evaluation.
a gate at type-level 3 proceeds to predicate evaluation. New test: =kill -9 <pid>=
returns =:reject-self-termination=. New test: modified core file is detected by
integrity hash check.
** Relation to Other Work
@@ -67,6 +80,115 @@ gate-to-fact bootstrap mechanism — every type-level rejection emits a structur
event that Phase 1 ingests as a fact. The ~30 lines implement the seed of the
ontology without any new dependencies.
* Phase 0b: Layered Signal Authentication — Layer 1 (Cryptographic) (~200 lines — extends Phase 0)
** What
Implement gate vector 0 at priority 700 — before all other gates and before any
type-level checking — with Layer 1 (cryptographic authentication) active.
Layers 2-4 (sensory, deterministic reasoning, probabilistic) are stubbed with
=:unavailable= results and deferred to later phases.
Signals carry cryptographic signatures verified against a key registry stored
as fact-store facts. Automated signal sources cannot impersonate the human. The
human can revoke compromised keys. The authorization matrix is per-key, per-action-class.
** Rationale
Authentication is layered because no single mechanism suffices. Cryptographic
authentication proves key ownership but not identity. A valid key can be used
by a compromised process. A valid key can sign pre-recorded frames. A valid key
can be held by someone who is not who they claim to be. The four-layer design
(Layer 1: crypto, Layer 2: sensory, Layer 3: deterministic reasoning, Layer 4:
probabilistic) stacks evidence. Phase 0b ships Layer 1 — the foundation — with
the architecture for layers 2-4 already designed.
The =:source= field in the signal plist is metadata — it /claims/ origin, it
does not /prove/ it. This phase replaces it with cryptographic proof.
** Implementation
*** Key generation and signature utilities — extends =security-vault.lisp=
Generate key pairs for signal sources. Canonicalize signal plists (sorted keys,
stripped of the signature field). Sign with the source's private key. Verify
with the public key from the key registry. ~50 lines. Uses Ironclad (already an
ASDF dependency). The vault already stores credential material — key material
extends the same storage with the same encryption.
*** Gate vector 0 — extends =security-dispatcher.lisp=
Registered at priority 700 (before the policy gate at 600, before all other
gates). Architecture for all four layers:
#+begin_src lisp
(defun gate-layered-authentication (signal)
(let ((results '()))
;; Layer 1: Cryptographic (always available, always runs first)
(let ((crypto-result (auth-crypto-verify signal)))
(push (cons :crypto crypto-result) results)
(when (eq (getf crypto-result :result) :reject)
(return-from gate-layered-authentication
(list :result :reject :confidence nil
:layer-results (nreverse results)))))
;; Layer 2: Sensory (fboundp-guarded, deferred)
(let ((sensory (if (fboundp 'auth-sensory-verify)
(auth-sensory-verify signal)
'(:result :unavailable))))
(push (cons :sensory sensory) results))
;; Layer 3: Deterministic (fboundp-guarded, deferred to Phase 2+)
(let ((det (if (fboundp 'auth-deterministic-verify)
(auth-deterministic-verify signal)
'(:result :unavailable))))
(push (cons :deterministic det) results)
(when (eq (getf det :result) :reject)
(return-from gate-layered-authentication
(list :result :reject :confidence nil
:layer-results (nreverse results)))))
;; Layer 4: Probabilistic (fboundp-guarded, deferred)
(let ((prob (if (fboundp 'auth-probabilistic-verify)
(auth-probabilistic-verify signal)
'(:result :unavailable))))
(push (cons :probabilistic prob) results))
;; Layer 4 never rejects outright — it downgrades authorization
(let ((confidence (aggregate-confidence results)))
(list :result :pass :confidence confidence
:layer-results (nreverse results))))))
#+end_src
Layer 1: verify cryptographic signature, check permission matrix against key
registry, reject on failure. ~50 lines. Layers 2-4: stubbed, return =:unavailable=.
*** Key registry — facts in the fact store
Key lifecycle facts are admitted in a =:key-lifecycle= domain with =:singular=
cardinality: =(:key-id "#47" :class :sensor :permissions (:observe :propose) :status :active)=.
Key creation, promotion, and revocation are facts with Merkle version chains.
The human's key signs new keys into existence and signs revocation. ~50 lines.
*** Signal provenance chain — Merkle-linked causality
When a signal triggers a downstream signal, each carries a =:sigchain= field
with all upstream =(:key-id <k> :signature <s> :auth-result <r>)= entries.
Tampering with any link invalidates the leaf. Revocation propagates through
the chain — flagged, not deleted. ~50 lines.
** Verification — ~8 FiveAM tests
1. =test-sign-verify-roundtrip= — sign and verify a plist roundtrip.
2. =test-tampered-signal-rejected= — modify payload after signing, verification fails.
3. =test-human-key-permits-write= — human key with =:write= passes Layer 1 and the full gate.
4. =test-sensor-key-denied-write= — sensor key proposing a write is rejected.
5. =test-revoked-key-rejected= — revoked key is rejected by Layer 1.
6. =test-sigchain-invalidated-by-revocation= — root signer revoked flags downstream.
7. =test-layers-2-3-4-unavailable= — when Layers 2-4 are not loaded, they return
=:unavailable= and the gate proceeds with Layer 1 only.
8. =test-layer-3-rejects-on-contradiction= — deterministic reasoning (mock) detects
identity-ruling contradiction, gate rejects.
* Phase 1: Minimum Viable Fact Language (~150 lines — new skill)
** What
@@ -95,6 +217,31 @@ first step. Three reasons:
** Implementation — =org/symbolic-facts.org= → =lisp/symbolic-facts.lisp= (skill)
*** Abstract Fact Store Interface — design before implementation
Before any code is written, the five-function API must be designed and committed:
#+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
This interface is load-bearing. Every consumer — the archivist, Screamer, ACL2,
the planner — calls these five functions. They never access the backing store
directly. In Phase 1-4, the backing store is an ephemeral hash table. In Phase 5,
it is VivaceGraph + Merkle =memory-object= wrappers. The interface must be tested
against both backends from the start. Every API function receives a FiveAM test
that runs against both a hash-table mock and a VivaceGraph mock.
The interface also exposes a read-only =fact-degraded-mode-p= function. When
Screamer is not loaded, the fact store functions with basic hash-table consistency
checks (string equality, not constraint solving). When VivaceGraph is not loaded,
Prolog queries are unavailable. The degraded-mode flag tells consumers (and the
status bar) what is and isn't operational.
*** Triple store
A hash table keyed by =(entity relation)=. Values are plists:
@@ -104,13 +251,14 @@ A hash table keyed by =(entity relation)=. Values are plists:
:grounding <heading-id-or-nil>
:provenance <:gate-outcome | :human-authored | :deduced | :llm-proposed>
:timestamp <universal-time>
:contradiction <:awaiting-resolution-or-nil>
:superseded-by <entity-string-or-nil>)
:parent-id <hash-of-predecessor>
:policy <:singular | :dual | :plural>)
#+end_example
The =:provenance= field tracks how the fact entered the store. The
=:contradiction= field is nil on standard facts. The =:superseded-by= field is
set when a =:temporal= domain fact is replaced by a newer version.
The =:provenance= field tracks how the fact entered the store. The =:parent-id=
field links to the previous version in the Merkle chain — every fact has version
history regardless of cardinality. The =:policy= field records the cardinality
that was active when the fact was admitted.
*** Bootstrap from gates
@@ -150,19 +298,29 @@ lookup. Returns the matching triple or nil. ~30 lines.
=(fact-query-all &key relation value source-provenance)= — returns all triples
matching the filter criteria. Enables "find all files classified as secrets."
*** Contradiction detection
*** Contradiction detection — policy-driven, not policy-agnostic
On every =fact-assert=, check if the new triple contradicts an existing one
(same entity, same relation, different value, same provenance domain). If the
entity's class has =:contradiction-policy :exclusive=, the new fact is rejected
with a signal. If the policy is =:coexistent=, both facts are stored with a
=:contradiction= flag cross-referencing each other. If the policy is =:temporal=,
the old fact is marked =:superseded-by= the new one but retained.
On every =fact-assert=, the system checks the fact's =entity= class to determine
its cardinality policy. Time is universal — every fact carries a =:timestamp= and
=:parent-id= link regardless of policy. The policy only governs the active set:
The policy table is a hash table mapping entity classes to one of =:exclusive=,
=:coexistent=, or =:temporal=. Gate-bootstrapped facts default to =:exclusive=
(the filesystem is singular). New categories default to =:coexistent= (safe,
never loses information).
- =:singular=: same =(:entity :relation)=, same value → supersede (chain via
=:parent-id=). Same pair, different value at later timestamp → supersede,
chain as new leaf. Same pair, different value at same timestamp → contradiction
rejected, human resolves which is the active value.
- =:dual=: first two values admitted as complementary, cross-referenced via
=:complement= edge. Third value → prompt: promote to =:plural= or demote one?
Each value has its own version chain via =:parent-id=.
- =:plural=: any value admitted. Values cross-referenced when in tension. Each
has independent version chain. If active count drops to 1 → collapse to
=:singular=. If active count drops to 2 and values are complementary → prompt
to collapse to =:dual=.
The policy table is a hash table mapping entity classes to one of =:singular=,
=:dual=, or =:plural=. Gate-bootstrapped facts default to =:singular= (the
filesystem is physically singular). New categories default to =:plural= (safe —
never loses information). Categories for dialectical or complementary domains
are explicitly =:dual=.
** Verification — ~8 FiveAM tests
@@ -175,20 +333,120 @@ never loses information).
4. =test-fact-query-returns-correct-value= — querying by entity and relation
returns the expected value plist.
5. =test-duplicate-ingestion-idempotent= — asserting the same fact twice does
not produce a duplicate or a contradiction.
6. =test-exclusive-contradiction-rejected= — asserting a contradictory fact in
an =:exclusive= domain returns a rejection.
7. =test-coexistent-contradiction-flagged= — asserting a contradictory fact in a
=:coexistent= domain stores both with cross-referencing flags.
8. =test-temporal-supersedes= — asserting a newer fact in a =:temporal= domain
marks the old fact as superseded but retains it.
not produce a duplicate or a contradiction.
6. =test-singular-supersedes= — a fact with a later timestamp supersedes the old
value, which is retained with =:parent-id= chain in the Merkle DAG.
7. =test-singular-same-time-contradiction= — asserting a contradictory fact in a
=:singular= domain at the same logical timestamp returns a rejection, requiring
human resolution.
8. =test-plural-admits-all= — asserting multiple values for the same pair in a
=:plural= domain stores all with cross-references.
9. =test-dual-admits-two-rejects-third= — a =:dual= domain admits two complementary
values and rejects the third, prompting cardinality promotion to =:plural=.
** Relation to Other Work
This is Phase 1 of =notes/passepartout-v3.0.0-roadmap.org=. It implements Options 4 and 5
from the architecture note. The contradiction policies are from
from the architecture note. The cardinality policies are defined in
=passepartout-neurosymbolic-design-decisions-and-options.org=.
* Phase 1a: Self-Preservation Mechanisms (~120 lines — extends Phase 0 and Phase 1)
** What
Make self-preservation active rather than architectural. The agent monitors its
own integrity, quarantines failing skills, signals degradation to the user, and
monitors resource pressure. The external watchdog guards the daemon process from
outside the SBCL image.
** Rationale
The current architecture has passive self-preservation: the self-build boundary
blocks LLM-originated core modifications, memory snapshots enable rollback, and
=fboundp= guards catch missing skills. But degradation is silent — a skill dies,
the guard fires, and the agent never tells you. The status bar shows green
"connected" while the symbolic reasoning layer is down.
These mechanisms are small (~20-50 lines each), leverage existing infrastructure
(Merkle hashes, heartbeat, the dispatcher gate stack), and transform
self-preservation from a structural property into an active behavior. They
implement the Third Law for Passepartout: preserve yourself against non-human
threats — LLM proposals, environmental degradation, resource exhaustion — and
signal to the human when you are wounded.
** Implementation
*** Quarantine on skill failure — extends =core-skills.lisp=
Track per-skill error counts in a =*skill-error-counter*= hash table, resetting
on each heartbeat cycle. When a skill accumulates three unhandled errors within
a single cycle, unload the skill, log the quarantine event, and inject a system
message: "Skill 'symbolic-facts' quarantined (3 errors: consistency check nil,
fact-query on missing key, Screamer timeout). Reload with /skill-reload
symbolic-facts." The skill's =defskill= struct is flagged =:quarantined= and
excluded from trigger resolution until explicitly reloaded. ~40 lines.
*** Degraded-mode signaling — extends =core-reason.lisp= and TUI
Maintain a =*degraded-components*= list populated by =fboundp= guards and the
quarantine system. When =think()= assembles the system prompt, inject a
DEGRADATION section: "I am operating in degraded mode. Screamer is unavailable
(consistency checks disabled). VivaceGraph is unavailable (Prolog queries
disabled). Core safety gates are all active."
The TUI status bar renders a second line, amber-colored, when =*degraded-components*=
is non-empty: "⚠ Degraded: Screamer, VivaceGraph. /doctor skills for details."
~30 lines across daemon and TUI.
*** Resource self-monitoring — extends =symbolic-events.lisp=
On heartbeat, check memory pressure (=sb-kernel:dynamic-usage= against total),
disk space on =~/.cache/= (=uiop:directory-exists-p= + stat), and open file
descriptors. When a resource crosses a critical threshold, shed non-essential
skills in order of =:preservation-priority= (=:critical= never shed, =:normal=
shed after =:low=, =:low= shed first).
Inject a system message: "Memory critical (94% of 16GB). Unloading
embedding-native (768MB), channel-discord, channel-slack. Core safety: unchanged.
Essential skills retained: 18." ~50 lines.
Skill shed order is determined by a new =:preservation-priority= slot on
=defskill= (default =:normal=). Core safety skills carry =:critical= and are
never shed. Heavy skills (embedding-native with its model in memory, channel
gateways with connection pools) carry =:low=.
*** External watchdog — extends =passepartout= bash entry point
The bash script spawns a watchdog subprocess that polls the daemon port every
=WATCHDOG_TIMEOUT= seconds (default 30). If the port stops responding, the
watchdog snapshots the last known-good Merkle root, kills the stale process,
and restarts the daemon with =--snapshot <root-hash>=.
The watchdog is outside the SBCL image. A dead process cannot restart itself.
~25 lines of bash, no new Lisp code.
** Verification — ~6 FiveAM tests
1. =test-quarantine-on-three-errors= — a skill that errors three times in a
single cycle is quarantined and removed from trigger resolution.
2. =test-degraded-mode-visible= — when Screamer is not loaded, the system
prompt includes a DEGRADATION section.
3. =test-resource-shed-low-priority= — when memory exceeds threshold, =:low=
priority skills are unloaded first.
4. =test-critical-skills-never-shed==:critical= priority skills are retained
regardless of resource pressure.
5. =test-resource-recovery-reloads= — when resources recover below threshold
for N consecutive heartbeats, shed skills are reloaded automatically.
6. =test-quarantined-skill-relaodable= — a quarantined skill can be reloaded
via =/skill-reload= and passes sandbox validation before promotion.
** Relation to Other Work
This phase implements the Third Law of self-preservation as described in
=passepartout-neurosymbolic-design-decisions-and-options.org=. The integrity
monitoring (Phase 0) and degraded-mode signaling (Phase 1) provide the
infrastructure this phase extends with active, autonomous behavior.
* Phase 2: Screamer as Admission Gate (~200 lines — new skill)
** What
@@ -246,29 +504,36 @@ heartbeat or manually. The cost is compute (Screamer exploration), not tokens.
*** Admission gate
=(screamer-admit candidate-fact existing-facts)= — wraps consistency check with
the contradiction policy lookup. If the candidate fact's entity class has policy
=:exclusive=, contradictions reject. If =:coexistent=, flag. If =:temporal=,
supersede.
the cardinality policy lookup. The policy is determined by the fact's entity class
(see Phase 1: =:singular=, =:dual=, or =:plural=).
- =:singular=: same value ⇒ supersede (chain via =:parent-id=). Different value,
later timestamp ⇒ supersede. Different value, same timestamp ⇒ contradiction
rejected (human resolves).
- =:dual=: first two values admitted as complementary. Third rejected (prompt
cardinality promotion).
- =:plural=: any value admitted with cross-references. Active count transitions
trigger cardinality collapse checks.
This is the function the archivist calls before any LLM-proposed fact enters the
store. It is also called on human-authored facts (which override the policy —
the human can assert contradictory facts in any domain). It is not called on
gate-outcome facts (gates are the ground truth for security domains).
store. It is also called on human-authored facts (which override the human can
assert facts that bypass cardinality checks). It is not called on gate-outcome
facts (gates are the ground truth for security =:singular= domains).
** Verification — ~6 FiveAM tests
1. =test-screamer-consistency-passes= — a fact consistent with existing triples
returns =:consistent=.
2. =test-screamer-contradiction-detected= — "app.env is not secret" contradicts
"all *.env files are secrets" and returns =:contradiction=.
"all *.env files are secrets" and returns =:contradiction=.
3. =test-screamer-redundant-detected= — asserting a fact already implied by
existing facts returns =:redundant=.
existing facts returns =:redundant=.
4. =test-screamer-deduction-produces-new-fact= — given "all *.env files are
secrets" and "prod.env matches *.env", Screamer deduces "prod.env is secret."
5. =test-admission-gate-rejects-contradiction= — the archivist's proposal that
contradicts an =:exclusive= domain fact is rejected.
6. =test-admission-gate-flags-coexistent-contradiction= — the archivist's proposal
that contradicts a =:coexistent= domain fact is stored with a cross-reference.
secrets" and "prod.env matches *.env", Screamer deduces "prod.env is secret."
5. =test-admission-gate-singular-supersedes= — a later-timestamped value for a
=:singular= domain fact supersedes the old value, chaining via =:parent-id=.
6. =test-admission-gate-dual-rejects-third= — a =:dual= domain rejects the third
value, prompting =:plural= promotion.
** Relation to Other Work
@@ -315,8 +580,8 @@ relations (=:wrote=, =:published-in=, =:influenced=). If the heading is in
*** Verify through Screamer
Each proposed triple runs through =(screamer-admit candidate existing-facts)=
from Phase 2. Consistent and coexistent-flagged triples are admitted. Contradictory
triples in =:exclusive= domains are discarded with a log entry.
from Phase 2. Facts admitted follow the cardinality policy of their entity class
(=:singular=, =:dual=, or =:plural=). Rejected facts are discarded with a log entry.
*** Provenance tracking
@@ -448,7 +713,7 @@ This is Phase 4 of =notes/passepartout-v3.0.0-roadmap.org=. The flip concept ori
=notes/passepartout-symbolic-engine-exploration.org= (lines 68-76) and is refined in
=passepartout-neurosymbolic-design-decisions-and-options.org= under "The Flip."
* Phase 5: VivaceGraph as Persistent Store (~300 lines — new skill)
* Phase 5: VivaceGraph + Merkle DAG + Ontology Versioning (~400 lines — new skill)
** What
@@ -531,6 +796,41 @@ On daemon start, =(vivacegraph-load)= reads the last saved graph. On heartbeat,
=*memory-auto-save-interval*=. The save is atomic: write to a temp file, rename
on success. Corruption-safe.
*** Merkle DAG version chains
Each =(:entity :relation)= pair forms an independent Merkle chain. Facts hash
over =SHA-256(value || provenance || timestamp || parent-hash || grounding)=.
The =:parent-id= pointer forms the chain. Tampering with any version breaks all
downstream hashes.
The chains form a DAG, not a single list. Facts about =.env= evolve independently
from facts about Nabokov. Inserting a new version is O(1) per chain. =:dual= and
=:plural= facts cross-reference via =:complement= and =:contradiction= edges
but maintain independent ancestor chains. The Merkle DAG rests on the existing
=memory-object= infrastructure from v0.2.0 — the fact store is a new occupant
of existing housing. ~50 lines to bridge the fact schema into =memory-object=
wrappers.
*** Ontology versioning
The category hierarchy itself is a Merkle tree. Every entity class definition
hashes over its superclasses, cardinality policy, relations, and description.
The aggregate hash of all active class definitions is the =:ontology-version=
a Merkle root of the current worldview.
Every fact stores its =:ontology-version= at the time of assertion (a single
64-hex-char field). When categories change, the new hash flags affected facts
for re-verification (Screamer re-evaluates each against the new category
definitions). Re-verification outcomes are =:survived= (deduction still holds),
=:incoherent= (premises don't translate under new categories, flagged for human
review), or =:reclassified= (valid but under different classification).
Queries accept an optional =:ontology-version= parameter. The default is
=:active= (current worldview). Specifying a version returns facts as they were
under that worldview: "Under my 2024 security model, this file was a secret.
Under my 2025 model, it is an auth-secret." ~40 lines on top of VivaceGraph
persistence.
** Verification — ~5 FiveAM tests
1. =test-vivacegraph-roundtrip= — save and load preserves all facts with
@@ -542,7 +842,13 @@ on success. Corruption-safe.
4. =test-type-level-prevents-self-reference= — a query from a type-level-2
function cannot return type-level-3 facts.
5. =test-fact-store-fallback-without-vivacegraph= — when VivaceGraph is not
loaded, the hash-table fallback functions identically to Phase 1-4 behavior.
loaded, the hash-table fallback functions identically to Phase 1-4 behavior.
6. =test-merkle-chain-tamper-detected= — modifying a fact's value breaks the
hash chain, detectable by re-walking the =:parent-id= spine.
7. =test-ontology-version-query= — querying with an old =:ontology-version=
returns facts as they were under that worldview, not the current one.
8. =test-reverification-flags-on-category-change= — changing a category
definition sets =:re-verify-status :pending= on all affected facts.
** Relation to Other Work
@@ -749,10 +1055,10 @@ is pre-structured. The archivist's job changes from "discover entities" to
to it (1-hop neighbors). Optionally expand to 2-hop for deeply connected
domains.
3. *Admit with co-existent policy.* Wikidata facts are admitted with
=:provenance :wikidata= and contradiction policy =:coexistent=. They do not
override your memex's facts. They sit alongside them. Contradictions are
surfaced, not resolved.
3. *Admit with plural policy.* Wikidata facts are admitted with
=:provenance :wikidata= and cardinality policy =:plural=. They do not
override your memex's facts. They sit alongside them with provenance
displayed. Disagreements are surfaced, not resolved.
4. *Cross-domain query.* "What does my memex say about Nabokov that Wikidata
doesn't?" "Where does my memex disagree with Wikidata?" "What entities in my
@@ -778,35 +1084,65 @@ hop. A memex spanning literature, history, philosophy, and science may need 3-4
hops. The query performance and memory costs of a large Wikidata load have not
been estimated.
** Deferred Authentication Layers (Layers 2-4)
Phase 0b ships Layer 1 (cryptographic). The remaining layers are deferred to
when their dependencies are available:
- *Layer 2 — Sensory.* Active when vision and audio processing skills are loaded.
Verifies liveness, cross-modal consistency (face matches voice matches location),
and environmental coherence. Defers to Phase TBD (vision/audio skills feature
cycle). When unavailable, returns =:unavailable= — graceful degradation.
- *Layer 3 — Deterministic Identity Reasoning.* Active when Phase 2 (Screamer +
populated fact store) is complete. Queries the fact store for identity-ruling
facts ("Jack is deceased; this signal claims to be Jack") and returns binary
reject/pass. Defers to Phase 2+.
- *Layer 4 — Probabilistic Identity Reasoning.* Active when style profiles exist
as a fact-store domain. Uses embedding infrastructure (=embedding-native.lisp=,
v0.4.0, already exists) to compare writing style, behavioral patterns, and
content coherence against known profiles. Returns a confidence score; never
rejects outright — downgrades authorization. Defers to when style profiles are
built as a fact-store domain.
The gate architecture (single vector 0, =fboundp=-guarded sub-layers,
configurable per signal class) is designed with all four layers from Phase 0b.
Adding a layer requires adding a skill, not modifying the gate.
* Summary: Lines and Dependencies
| Phase | Component | Lines | New Skill? | Depends On | Earliest Release |
|-------+-------------------------+-------+------------+-----------------+------------------|
| 0 | PM-type-level gates | ~30 | No | Dispatcher | Immediately |
| 1 | Triple fact store | ~150 | Yes | Phase 0 | v0.7.2+ |
| 2 | Screamer admission | ~200 | Yes | Phase 1 | v0.7.2+ |
| 3 | Archivist extraction | ~100 | Extends | Phase 2 | v0.8.0+ |
| 4 | Flip — sufficiency | ~50 | Extends | Phase 3 | v0.8.0+ |
| 5 | VivaceGraph store | ~300 | Yes | Phase 4 | v0.10.0+ |
| 6 | ACL2 verification | ~200 | Yes | Phase 5 | v0.12.0+ |
| 7 | 10-80-10 planner | ~500 | Yes | Phase 6 | v3.0.0 |
| 8+ | Semantic Wikipedia | TBD | Yes | Phase 5 | TBD |
|-------+-------------------------+-------+------------+-----------------+------------------|
| Total | | ~1530 | | | |
| Phase | Component | Lines | New Skill? | Depends On | Earliest Release |
|-------+-----------------------------------------+--------+------------+-----------------+------------------|
| 0 | PM-type-level gates + core integrity | ~75 | No | Dispatcher | Immediately |
| 0b | Layered auth — Layer 1 (cryptographic) | ~200 | No | Phase 0 | v0.7.2+ |
| 1 | Triple fact store + abstract API | ~200 | Yes | Phase 0b | v0.7.2+ |
| 1a | Self-preservation mechanisms | ~120 | Extends | Phase 0, 1 | v0.7.2+ |
| 2 | Screamer admission gate | ~200 | Yes | Phase 1 | v0.7.2+ |
| 3 | Archivist as fact proposer | ~100 | Extends | Phase 2 | v0.8.0+ |
| 4 | Sufficiency criterion — the flip | ~50 | Extends | Phase 3 | v0.8.0+ |
| 5 | VivaceGraph + Merkle DAG + ontology ver | ~400 | Yes | Phase 4 | v0.10.0+ |
| 6 | ACL2 structural verification | ~200 | Yes | Phase 5 | v0.12.0+ |
| 7 | 10-80-10 planner | ~500 | Yes | Phase 6 | v3.0.0 |
| 8+ | Semantic Wikipedia integration | TBD | Yes | Phase 5 | TBD |
|-------+-----------------------------------------+--------+------------+-----------------+------------------|
| Total | | ~2045 | | | |
This roadmap is independent of the feature roadmap in
=passepartout/docs/ROADMAP.org=. Phase 0 ships alongside any v0.7.x patch. The
symbolic engine grows in parallel with feature work (TUI improvements, MCP tools,
gateway expansion, etc.), not after it. The feature roadmap describes /what/ the
agent can do; this roadmap describes /how/ it knows what it knows.
agent can do; this roadmap describes /how/ it knows what it knows and how it
protects itself.
The total new code across all phases is approximately 1,530 lines. Relative to
The total new code across all phases is approximately 2,045 lines. Relative to
the existing codebase (~8,000+ lines across 40+ Org source files and 30+ skills),
the symbolic engine is a ~20% addition. Relative to the ROADMAP's planned feature
the symbolic engine is a ~25% addition. Relative to the ROADMAP's planned feature
work through v0.13.0 (thousands of lines of TUI rendering, MCP protocol
implementation, skin engine, planning, etc.), the symbolic engine is a small,
orthogonal thread that grows the architecture's reasoning depth while the feature
work grows its interaction breadth.
orthogonal thread that grows the architecture's reasoning depth, self-preservation,
signal authentication, and knowledge integrity while the feature work grows its
interaction breadth.
capability, and knowledge integrity while the feature work grows its interaction
breadth.
* Competitive Advantage Analysis
@@ -818,6 +1154,23 @@ A request to modify the dispatcher's own rules is impossible by construction, no
just caught by pattern matching. No competitor has this — their equivalent of
"core file protection" is a prompt instruction, not a type system.
** Phase 0b: Layered signal authentication — verified origin, not claimed origin
No competitor verifies /who/ issued a signal. Every agent harness accepts signals
from any source that speaks its protocol — TUI, CLI, subprocess, internal skill.
A compromised dependency can impersonate any signal source. Passepartout's
four-layer authentication gate makes signal source spoofing impossible at Layer 1
(cryptographic), detectable at Layers 2-3 (sensory + deterministic reasoning),
and probabilistically flagged at Layer 4 (style analysis). The key registry is a
fact-store domain with Merkle-hashed provenance — key creation, promotion, and
revocation are auditable, versioned, and survivable across restarts. The signal
provenance chain makes multi-step automated causality traceable: "this deletion
happened because sensor #3 signed a classification (liveness check failed, sender
deceased 2 years ago) that skill #7 signed a re-indexing from, and sensor #3 was
subsequently revoked." No competitor can trace an action to its authenticated
source through four independent evidence layers because no competitor has a
layered authentication gate and a Merkle-linked provenance chain.
** Phase 2-3: Verified extraction — the symbolic index grows without corruption
No competitor verifies extracted facts against an existing knowledge base. Their
@@ -851,6 +1204,22 @@ Nabokov wrote /Pale Fire/ and lectured on Kafka. Passepartout with Wikidata
loaded knows both, and the entity knowledge costs zero LLM tokens — it is loaded
once as structured data and queried via VivaceGraph traversals.
** Phase 0-1a: Self-preservation — the agent knows when it is wounded
No competitor detects its own degradation. Claude Code, OpenCode, and Hermes
all fail silently when a tool crashes or a dependency is missing — the agent
keeps running, producing degraded output, never telling the user. Passepartout's
quarantine system detects failing skills, unloads them automatically, and
displays a degraded-mode indicator in the status bar. The external watchdog
restarts the daemon if the process dies. The integrity monitor detects corrupted
core files. The agent refuses to execute commands that would destroy its own
runtime, explaining /why/ and redirecting to the safe termination path.
This is not a feature. It is the architectural difference between a tool that
breaks silently and a system that preserves itself actively, signals its wounds,
and traces its degradation to specific components that can be reloaded or
repaired.
** The permanent competitive advantage
The competitive advantage is not any single feature. It is the architecture's