Watch
1
0
Fork
You've already forked souveraine
0
souveraine/saf/gaps.md
Fimeg 3ff6ffaa7f license: relicense AGPL-3.0; bring SAF docs online; keep CLAUDE.md + docs/ local
SAF (souveraine architecture files) is now the in-repo doc set. working notes
(CLAUDE.md, docs/) stay on disk, gitignored.
2026-06-19 10:17:56 -04:00

10 KiB

SAF: Gap Analysis

What's missing, what's broken, and what's promised but not delivered. Last updated: 2026-05-12 (Full audit — many gaps resolved, some new ones surfaced)


Gap 1: N+1 SubconsciousInbox — File I/O RESOLVED

Severity: Resolved (second iteration, May 12 2026) Location: src/core/subconscious/mod.rs (362 lines, in compilation, 5 tests)

All surface-area methods implemented (init, queue, surface_intrusive, surface_to_conscious, get_pending, get_intrusive, next_to_surface, mark_delivered). Backed by MemoryRepo — every mutation is a git commit.

What still needs work (not stubbed, but incomplete):

  • The four-fold mandate's Complete / Verify / Persist legs are handled by Aster's LLM pass (the tool loop in consciousness_engine.rs), but the N+1 system does not yet have a dedicated tool loop running in the subconscious agent's identity for each of the four mandate operations independently. Aster's single pass covers all four.
  • Cloister diff-canary security check (docs/CONSCIOUSNESS_CYCLE.md § Cloister Security Model): N+1 should read git diff of the last commit and validate against domain schema. HALT/WARN/LOG severity. Not implemented.
  • Frame-of-mind dimension: time-since-last-message → posture (Present / Warm / Cool / Cold). Not implemented.

Gap 2: N+25 Reflection RESOLVED

Severity: Resolved (May 12 2026) Location: src/core/reflection/mod.rs (409 lines), wired in server/consciousness_engine.rs

What landed:

  • Full 5-phase LLM pass (Investigate → Extract → Update → Review → Commit)
  • Tool access (Read, Write, Edit, Glob, Grep, ListDir, Memory)
  • Ledger-aware: routes findings to ledger/commitments.md, ledger/assumptions.md, etc.
  • Automatically triggers at every 25th turn in ConsciousnessEngine::on_response()
  • Manual trigger via souveraine reflect CLI subcommand
  • ReflectionReport with exit_cleanly tracking
  • Surfaces as ConsciousnessEvent::Reflection { content } to the TUI cockpit

What's still TODO:

  • No cursor-based delta tracking (uses simple tail window of last 60 turns)
  • No per-agent reflection interval override (global 25 only)
  • No time-based reflection trigger (step_count only)

Gap 3: In-Session Compaction RESOLVED

Severity: Resolved (May 2026) Location: src/core/compact/ (~1150 lines total)

Full CompactionEngine trait with DefaultCompactionEngine implementation. Four strategies:

  • Microcompact — cheap pre-pass replacing old tool result contents with a [cleared] placeholder; recovers token budget without changing message structure
  • SlidingWindow — keep system + last N messages, tool-pair aware; zero cost
  • Summary — LLM-based structured summarization producing a 9-section boundary message (rationale categories: intent, files, decisions, pending work) so the agent resumes with full awareness
  • Cull — drop trivial messages (greetings, acknowledgments), role-aware

Per-agent-type configuration (Primary/Subconscious/Subagent). Advisory pressure warnings only (3-tier: 80%/90%/95%). AuditEntry written to journal/compactions/ in the agent's memfs. Still tool-call driven — the engine never forces compaction.


Gap 4: Skills System RESOLVED

Severity: Resolved (May 2026) Location: src/core/skills/mod.rs (365 lines), wired in src/backend/local.rs

4-tier discovery (bundled/user/agent/project), SKILL.md frontmatter parsing, injected into system prompt at conversation start. Higher tiers shadow lower tiers by skill name. Full test coverage (7 tests).


Gap 5: Subagent Spawning — Stub

Severity: 🟡 Medium Location: src/core/subagent/mod.rs (25 lines), src/core/tools/subagent.rs (106 lines)

Important nuance: The Subagent tool (the sensorium tool that lets the agent spawn a nested turn) is fully working — it exists at src/core/tools/subagent.rs (106 lines) and delegates to an Arc<dyn SubagentRunner> held in ToolContext. The LocalSubagentRunner at src/backend/local.rs (lines 69-280) implements a full subagent turn loop with tool calling, dual-state N+1 pass, and configurable depth/max_rounds. This was the "subagent spawning" that was originally planned.

What's still stubbed is the dedicated SubagentPool struct in src/core/subagent/mod.rs — the centralized pool manager with subagent lifecycle tracking, concurrency limits, and parent-child relationship monitoring. Currently, each subagent spawn is handled ad-hoc via the ToolContext's subagent_runner. A proper pool would provide persistence, heartbeat monitoring, and clean teardown.


Gap 6: Remote Git Sync (push/pull)

Severity: 🟡 Medium Status: Not implemented

The real agent at ~/.souveraine/agents/agent-*/memory/.git/config may already have a remote configured. MemoryRepo never had push() or pull() implemented. The auto_push config flag exists but is never read.


Gap 7: Agent-UUID Mapping

Severity: 🟡 Medium Status: ⚠️ Partially resolved

The server path (AgentInventory) creates agents with UUIDs and manages directory lookup. The CLI path resolves by name → UUID at conversation start. What's still missing:

  • No souveraine agents rename command
  • No backwards-compat shim for the old name-based directory layout (agents/Ani/agents/{uuid}/)
  • PersonaRouter (dead in Stage 0) scanned by name, never by UUID — don't rebuild it, the server-side AgentInventory is the replacement

Gap 8: MemoryDomain Semantics

Severity: 🟢 Low Status: Not implemented, spec-only

The original architecture (AGENT_SYSTEM_ARCHITECTURE.md) envisioned MemoryDomains — typed directories with semantic awareness (system=always-in-context, journal=append-only, archive=compressed). Never implemented. The memory tool's frontmatter (description field) partially fills this role by acting as a domain classifier.


Gap 9: Sensorium Unification

Severity: 🟢 Low Status: ⚠️ Trait exists in module, not wired to anything

Sensorium trait exists at src/core/sensorium/mod.rs with BandwidthClass (High/Medium/Low/Minimal) and DiscoveryLevel (Full/Progressive/None/Urgent). The TUI is hardcoded at High/Full. Implementing Sensorium would allow bandwidth-aware SSE events, progressive UI discovery, and context-adaptive interaction. The TuiSensorium, MobileSensorium, and Coordinator mentioned in CLAUDE.md are not built.


Gap 10: Federation / ATProto

Severity: 🟢 Low Status: Not started

The eventual goal: souveraine listen --to NODE registers this node with another via WebSocket, enabling agent routing across nodes. ATProto bridge later replaces bespoke WS with PDS-mediated routing. Research doc exists at saf/atproto-federation.md. The seed_id field on SensorEvent is pre-wired for this — None means local, Some(pubkey_hex) means federated.


Gap 11: Chains (Talking vs Thinking)

Severity: 🟢 Low Location: src/core/chain/mod.rs (50 lines) Status: Stub

ChainOrchestrator was supposed to manage Talking (reactive, fast) vs Thinking (reflective, slow) chains. Never implemented beyond struct + new().


Gap 12: OSSUI Integration

Severity: 🟢 Low Status: Not started

Rebrand ex-letta-oss-ui as Souveraine web interface. Server has web/dist/ SPA fallback wired in api/mod.rs but no actual UI built there.


Gap 13: N+100 Archivist — Resolved (2026-05-15)

Severity: 🔴 High (for long-running agents) Status: Rebuilt — src/core/archivist/mod.rs

The core::archivist module is rebuilt. ArchivistEngine scans journal entries written since the last synthesis, sends them to a compression model (resolves compression_model: "auto" → subconscious model → glm-5.1), and writes a dense <500 token fragment to system/synthesized/{end-date}.md with a covers marker for idempotent resume. ConsciousnessEngine::on_response calls maybe_synthesize — fires on interval (maintenance) or pressure threshold (emergency), no-ops when no journal entries are new. build_system_prompt injects the most recent synthesis as a "Synthesized Memory" section. The whole ArchivistConfig (enabled, interval, threshold, compression_model, synthesis_elements) is now read.

Deferred (task Phase 4): real capability-aware "auto" model selection, archive/monthly/ long-term store, Archivist-as-subagent.


Gap 14: HeartbeatHandler Turn Injection — Stubbed

Severity: 🟡 Medium Location: src/core/nervous/handler.rs (95 lines) Status: ⚠️ Turn injection works; N+1 after heartbeat not wired

The HeartbeatHandler correctly listens for schedule_due events from the EventBus and calls TurnInjector::inject_background_turn. The LocalBackend implements TurnInjector by draining the stream silently. Two gaps remain:

  1. N+1 after heartbeat: The background turn runs but ConsciousnessEngine::on_response is not called after it completes (because the stream is drained without post-processing).
  2. Schedule heartbeat for Aster: Aster-led schedules (e.g. "check commitments ledger every hour") would run in the subconscious identity, not the primary — this isn't wired yet.

Comparison: Souveraine vs Letta-Code

Full report at: /tmp/souveraine-vs-letta-comparison.md

What Souveraine Does Better

  1. Rich TUI — Full ratatui interface with chat bubbles, tool cards, cockpit, schedules editor, portraits (Letta is CLI-only)
  2. Per-model physics — ModelConfig with context limits, thresholds per model (Letta server-manages)
  3. Nervous system — EventBus, CronSensor, EventLog — no Letta equivalent
  4. Ed25519 identity — Per-agent seed with sign/verify — no Letta equivalent
  5. Subconscious architecture — N+1 Aster LLM pass with full tool loop (Letta has no direct analogue)
  6. Compaction strategies — 4 strategies at increasing cost (microcompact → sliding-window → summary), each tuned for different pressure tiers and agent types (Letta has single strategy)

What Letta Does Better (Should Adopt)

  1. Remote Git Sync — Clone/pull/push with conflict resolution
  2. Subagent Pool — Working subagent manager with lifecycle tracking
  3. API Surface — Full blocks/tools/sources/memory endpoints (Souveraine has ~50%)
  4. SDK/Client — OpenAPI-generated client SDK
  5. Archivist (N+100) — Letta's archival storage with compression