Watch
1
0
Fork
You've already forked SouveraineOS
0
SouveraineOS/docs/substrate/seedid-vs-matrix-comparison.html
Fimeg e480809c70 docs: rescue the agent-substrate tree out of a gitignored directory
219 files, 2.0 MB, untracked in souveraine/docs and existing nowhere else.
The volume is at 100% with no snapshots.
2026-07-26 12:11:50 -04:00

814 lines
34 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Seed-ID vs Matrix — Protocol Comparison</title>
<style>
:root {
--bg: #0d0d14;
--surface: #16161f;
--surface2: #1e1e2a;
--border: #2a2a3e;
--text: #d0d0e0;
--text-dim: #7a7a8e;
--accent-souv: #7c5cf0;
--accent-matrix: #0dbd8b;
--accent-souv-dim: #5a3eb8;
--accent-matrix-dim: #08946b;
--red: #e55550;
--amber: #e5a050;
--green: #50c878;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Inter', system-ui, sans-serif;
background: var(--bg);
color: var(--text);
line-height: 1.6;
min-height: 100vh;
}
/* ── Hero ─────────────────────────────────────────── */
.hero {
background: linear-gradient(135deg, #0d0d14 0%, #1a1035 50%, #0a1a15 100%);
border-bottom: 1px solid var(--border);
padding: 80px 24px 60px;
text-align: center;
position: relative;
overflow: hidden;
}
.hero::before {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(ellipse 600px 300px at 25% 60%, rgba(124, 92, 240, 0.06) 0%, transparent 70%),
radial-gradient(ellipse 600px 300px at 75% 40%, rgba(13, 189, 139, 0.06) 0%, transparent 70%);
}
.hero h1 {
font-size: clamp(2rem, 5vw, 3.2rem);
font-weight: 700;
letter-spacing: -0.03em;
position: relative;
}
.hero .vs {
background: linear-gradient(90deg, var(--accent-souv), var(--accent-matrix));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.hero p {
color: var(--text-dim);
max-width: 620px;
margin: 16px auto 0;
font-size: 1.05rem;
position: relative;
}
/* ── Layout ───────────────────────────────────────── */
.container { max-width: 1100px; margin: 0 auto; padding: 48px 24px; }
/* ── Section headers ──────────────────────────────── */
.section-title {
font-size: 1.4rem;
font-weight: 600;
margin-bottom: 4px;
letter-spacing: -0.02em;
}
.section-sub {
color: var(--text-dim);
font-size: 0.9rem;
margin-bottom: 24px;
}
/* ── Dimension header row ─────────────────────────── */
.dim-row {
display: flex;
gap: 16px;
margin-bottom: 20px;
}
.dim-label {
flex: 0 0 140px;
font-weight: 600;
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-dim);
padding-top: 4px;
}
.dim-cards {
flex: 1;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 12px;
padding: 20px;
transition: border-color 0.2s, box-shadow 0.2s;
}
.card:hover {
border-color: var(--accent-souv-dim);
box-shadow: 0 0 20px rgba(124, 92, 240, 0.05);
}
.card.matrix:hover {
border-color: var(--accent-matrix-dim);
box-shadow: 0 0 20px rgba(13, 189, 139, 0.05);
}
.card .tag {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 0.7rem;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.08em;
padding: 2px 10px;
border-radius: 6px;
margin-bottom: 10px;
}
.tag.souv { background: rgba(124, 92, 240, 0.15); color: var(--accent-souv); }
.tag.matrix { background: rgba(13, 189, 139, 0.12); color: var(--accent-matrix); }
.card h3 {
font-size: 1rem;
font-weight: 600;
margin-bottom: 8px;
}
.card p, .card li {
font-size: 0.88rem;
color: var(--text-dim);
line-height: 1.55;
}
.card ul { padding-left: 16px; list-style: none; }
.card ul li::before { content: '— '; color: var(--text-dim); opacity: 0.4; }
.card ul li { margin-bottom: 3px; font-size: 0.84rem; color: var(--text-dim); }
.card code {
font-family: 'JetBrains Mono', 'Fira Code', monospace;
font-size: 0.78rem;
background: rgba(255,255,255,0.04);
padding: 1px 6px;
border-radius: 4px;
color: var(--text);
}
/* ── Summary table ────────────────────────────────── */
.summary-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
font-size: 0.85rem;
}
.summary-table thead th {
text-align: left;
padding: 14px 16px;
font-weight: 600;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--text-dim);
border-bottom: 1px solid var(--border);
position: sticky;
top: 0;
background: var(--bg);
}
.summary-table thead th:first-child { width: 140px; }
.summary-table thead th:nth-child(2) { width: auto; }
.summary-table thead th:nth-child(3) { width: auto; }
.summary-table thead th:last-child { width: 180px; }
.summary-table td {
padding: 14px 16px;
border-bottom: 1px solid var(--border);
vertical-align: top;
line-height: 1.5;
}
.summary-table tbody tr:hover td {
background: rgba(255,255,255,0.015);
}
.summary-table td:first-child {
font-weight: 600;
color: var(--text);
white-space: nowrap;
}
.summary-table td:nth-child(2) { color: var(--accent-souv); }
.summary-table td:nth-child(3) { color: var(--accent-matrix); }
.summary-table td:last-child { color: var(--text-dim); font-size: 0.82rem; }
/* ── Badges ───────────────────────────────────────── */
.badge {
display: inline-block;
font-size: 0.68rem;
font-weight: 600;
padding: 2px 8px;
border-radius: 5px;
letter-spacing: 0.03em;
margin-right: 4px;
}
.badge.built { background: rgba(80, 200, 120, 0.15); color: var(--green); }
.badge.design { background: rgba(229, 160, 80, 0.15); color: var(--amber); }
.badge.none { background: rgba(229, 85, 80, 0.15); color: var(--red); }
.badge.native { background: rgba(13, 189, 139, 0.15); color: var(--accent-matrix); }
/* ── Architecture diagram ──────────────────────────── */
.arch {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 14px;
padding: 32px;
margin-bottom: 48px;
text-align: center;
}
.arch svg {
max-width: 100%;
height: auto;
}
/* ── Verdict section ──────────────────────────────── */
.verdict-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 24px;
margin-top: 32px;
}
.verdict-card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: 14px;
padding: 28px;
}
.verdict-card h3 {
font-size: 1.05rem;
font-weight: 600;
margin-bottom: 12px;
}
.verdict-card p, .verdict-card li {
font-size: 0.88rem;
color: var(--text-dim);
line-height: 1.6;
}
.verdict-card ul { padding-left: 18px; margin-top: 8px; }
.verdict-card ul li { margin-bottom: 4px; }
/* ── Glyph ornament ───────────────────────────────── */
.glyph-row {
display: flex;
justify-content: center;
gap: 32px;
margin: 16px 0 8px;
font-size: 2.5rem;
opacity: 0.15;
user-select: none;
}
/* ── Responsive ───────────────────────────────────── */
@media (max-width: 700px) {
.dim-cards { grid-template-columns: 1fr; }
.dim-row { flex-direction: column; }
.dim-label { flex: unset; }
.verdict-grid { grid-template-columns: 1fr; }
.hero { padding: 48px 16px 40px; }
.container { padding: 32px 16px; }
.summary-table { font-size: 0.78rem; }
.summary-table td, .summary-table th { padding: 10px 10px; }
}
</style>
</head>
<body>
<!-- ════════════════ Hero ════════════════ -->
<section class="hero">
<div class="glyph-row">
<span>◇◆☆★</span>
<span style="opacity:0.4"></span>
<span>◆■★◇</span>
</div>
<h1>seedID <span class="vs">vs</span> Matrix</h1>
<p>Cryptographic agent identity &amp; DAG memory — how Souveraine and Matrix solve the same primitives at fundamentally different layers of the stack.</p>
</section>
<!-- ════════════════ Architecture ════════════════ -->
<div class="container">
<section class="arch">
<svg viewBox="0 0 900 200" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="g1" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#7c5cf0"/><stop offset="100%" stop-color="#5a3eb8"/>
</linearGradient>
<linearGradient id="g2" x1="0" y1="0" x2="1" y2="0">
<stop offset="0%" stop-color="#0dbd8b"/><stop offset="100%" stop-color="#08946b"/>
</linearGradient>
</defs>
<!-- Souveraine stack -->
<text x="50" y="28" fill="#7c5cf0" font-size="11" font-weight="700" letter-spacing="2" text-anchor="middle">SOUVERAINE</text>
<rect x="10" y="36" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
<text x="50" y="53" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">seedID</text>
<rect x="10" y="68" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
<text x="50" y="85" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">Ed25519</text>
<rect x="10" y="100" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
<text x="50" y="117" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">Git DAG</text>
<rect x="10" y="132" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
<text x="50" y="149" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">WS Bridge</text>
<!-- Divider -->
<line x1="120" y1="30" x2="120" y2="170" stroke="#2a2a3e" stroke-width="1" stroke-dasharray="4,3"/>
<!-- Shared layer -->
<text x="200" y="95" fill="#7a7a8e" font-size="10" text-anchor="middle">self-sovereign identity</text>
<text x="200" y="110" fill="#7a7a8e" font-size="10" text-anchor="middle">event-DAG state</text>
<text x="200" y="125" fill="#7a7a8e" font-size="10" text-anchor="middle">federated transport</text>
<text x="200" y="140" fill="#7a7a8e" font-size="10" text-anchor="middle">cryptographic verification</text>
<!-- Divider -->
<line x1="280" y1="30" x2="280" y2="170" stroke="#2a2a3e" stroke-width="1" stroke-dasharray="4,3"/>
<!-- Matrix stack -->
<text x="350" y="28" fill="#0dbd8b" font-size="11" font-weight="700" letter-spacing="2" text-anchor="middle">MATRIX</text>
<rect x="310" y="36" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
<text x="350" y="53" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">@user:host</text>
<rect x="310" y="68" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
<text x="350" y="85" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">E2EE Keys</text>
<rect x="310" y="100" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
<text x="350" y="117" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">Event DAG</text>
<rect x="310" y="132" width="80" height="26" rx="6" fill="#1e1e2a" stroke="#2a2a3e" stroke-width="1"/>
<text x="350" y="149" fill="#d0d0e0" font-size="10" text-anchor="middle" font-weight="600">/sync API</text>
<!-- Bottom labels -->
<text x="50" y="180" fill="#7a7a8e" font-size="9" text-anchor="middle">agent = key</text>
<text x="350" y="180" fill="#7a7a8e" font-size="9" text-anchor="middle">agent = server tenant</text>
<!-- Brace - shared primitives -->
<path d="M285,45 Q288,45 288,48 L288,162 Q288,165 285,165" stroke="#3a3a4e" stroke-width="1" fill="none"/>
<path d="M125,45 Q122,45 122,48 L122,162 Q122,165 125,165" stroke="#3a3a4e" stroke-width="1" fill="none"/>
</svg>
<p style="color:var(--text-dim);font-size:0.85rem;margin-top:8px;">Both use Ed25519, DAG state, and cryptographic transport — but at radically different layers with radically different assumptions.</p>
</section>
<!-- ════════════════ 1. Identity ════════════════ -->
<h2 class="section-title">1. Identity</h2>
<p class="section-sub">The root of trust — how an agent proves who it is.</p>
<div class="dim-row">
<div class="dim-label">Root identity</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<h3>Ed25519 keypair</h3>
<p>Self-sovereign. Generated once at <code>souveraine init</code>. Private key stored at <code>~/.souveraine/seed-id/private.key</code> (0600 perm). The key <em>is</em> the identity — no server required.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<h3>@user:domain</h3>
<p>Server-tethered. Identity is a string bound to a homeserver's authority. Root identity relies on the server's DNS domain and TLS certificate, not a local key.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Per-instance</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<h3>Two-layer keys</h3>
<p><strong>Machine seed</strong> (<code>seed-id/</code>) signs the transport envelope. <strong>Agent seed</strong> (<code>agents/{uuid}/seed/</code>) signs the being's identity. Both Ed25519. The agent seed travels with the memfs and is identical across machines.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<h3>Per-device keys</h3>
<p>Ed25519 + Curve25519 device keys generated per device. Signed by cross-signing master key for E2EE. Server-level auth is a separate <code>access_token</code> — not key-based.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Cross-machine</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<h3>Same pubkey = reach</h3>
<p>Receiver compares the agent seed pubkey against its own. <strong>Match</strong><code>reach</code> (same being, no consent gate). <strong>Different</strong><code>consult</code> (consent-gated). This is a cryptographic, automatic decision — no server needed.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<h3>Cross-signing + server auth</h3>
<p>E2EE cross-signing verifies device ownership. Server-level auth is token-based, not key-based. Devices are bound to an account, not the other way around — you prove you own a device, not that you <em>are</em> an identity.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Key rotation</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p><span class="badge design">design</span> Planned: DID document signed by previous key. Chain-of-custody from physical hardware fingerprint. Not yet implemented.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p><span class="badge native">native</span> Master key signs new device keys via cross-signing protocol. Server tokens rotate via re-login. Master key itself has no rotation mechanism — it's permanent.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Public surface</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p><code>did:web:</code> + Ed25519 pubkey hex. Designed but not yet generated. The glyph (<span style="color:var(--accent-souv)">◇◆☆★</span>) is the terminal-friendly badge.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p><code>@user:domain</code> — resolvable via <code>._well-known/matrix/server</code> delegation. The homeserver's .well-known is the root of trust for routing.</p>
</div>
</div>
</div>
<!-- ════════════════ 2. DAG / Event State ════════════════ -->
<h2 class="section-title" style="margin-top:48px;">2. DAG &amp; Event State</h2>
<p class="section-sub">How state is structured, addressed, and reconciled.</p>
<div class="dim-row">
<div class="dim-label">State model</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<h3>Git-backed memfs</h3>
<p>Every write to an agent's memory is a git commit. Files with YAML frontmatter. Events are <code>SensorEvent</code> JSON on an EventBus (broadcast channel). The DAG exists underneath (git's commit graph) but is not surfaced to the agent.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<h3>Native Event DAG</h3>
<p>Every event references <code>prev_events</code> (parent hashes), forming a Merkle DAG natively. <code>m.relates_to</code> for edits, replies, reactions. The DAG <em>is</em> the protocol — not an implementation detail.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Content addressing</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p>Git commit hashes. <code>SensorEvent.payload</code> carries JSON but is not itself content-addressed. Event identity is the bus message, not an addressable hash.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p><code>(room_id, event_id)</code> — event_id is a server-generated hash. Events reference each other via <code>m.relates_to</code>. Every PDU is addressable by hash.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">DAG semantics</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p><span class="badge design">design</span> Not surfaced. Git provides DAG under the hood; <code>memory status</code> showing divergence, <code>memory reconcile</code>, and <code>memory merge</code> are all unimplemented (Phase 6+). Currently linear via auto-commit.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p><span class="badge native">native</span> DAG is fundamental: <code>prev_events</code> chains, fork detection, and State Resolution v2 for algorithmic merge of concurrent histories. Battle-tested at scale (Bluesky's OGS, Matrix.org).</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Reconciliation</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p><span class="badge design">design</span> Domain-aware three-way merge: <code>system/</code> never auto-merges, <code>journal/</code> always safe, others last-write-wins. Simpler than Matrix's state res — but unproven.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p>State Resolution v2: algorithmic merge based on power levels + event ordering + room version. Deterministic fork resolution. Copes with arbitrary topologies at the cost of algorithmic complexity.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">History model</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p>Mutable via compaction. Summary / KeyValue / Quote / Cull strategies rewrite history to manage context window. The agent <em>feels</em> pressure before truncation — three warnings, then natural cutoff.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p>Immutable. Edits = new event with <code>m.replace</code>. Redaction = new event marking content hidden. No rewriting. History is append-only by protocol design.</p>
</div>
</div>
</div>
<!-- ════════════════ 3. Transport ════════════════ -->
<h2 class="section-title" style="margin-top:48px;">3. Transport &amp; Sync</h2>
<p class="section-sub">How events move between instances.</p>
<div class="dim-row">
<div class="dim-label">Sync model</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<h3>WebSocket federation bridge</h3>
<p>Persistent WS connection per peer. Events flow one direction. Reconnect with exponential backoff (1s → 2s → 4s → 8s → 16s → 32s → 60s + jitter). No polling — push only.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<h3>Long-poll /sync</h3>
<p>Client sends <code>since=token</code>, server responds with deltas. No persistent connection by default. Sliding Sync (MSC3575) adds incremental sync. Mature batching and rate-limit handling.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Event envelope</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p><code>SignedEvent</code> — JSON container with Ed25519 signature + signer pubkey hex. Wraps a <code>SensorEvent</code>. Verification stamps <code>seed_id</code> onto the inner event for anti-echo.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p><code>PDU</code> — signed by sender's Ed25519 device key + origin server adds its own signature. Contains <code>room_id</code>, <code>prev_events</code>, <code>depth</code>, <code>auth_events</code>. Protocol-level envelope with full provenance.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Filtering</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p>Subscription-based: <code>*</code> (all), <code>prefix*</code> (prefix match), exact name. Control events (<code>federation</code>, <code>summon_request</code>, <code>summon_response</code>) always cross regardless of subscription.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p>Per-request filters on <code>/sync</code>: room list, event type, sender, etc. Appservices receive all events in their registered rooms. Filter granularity is richer but server-evaluated.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Idempotency</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p><span class="badge none">none</span> No transaction ID. Events carry a timestamp but no dedup mechanism. At-most-once delivery assumed.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p><code>txnId</code> per <code>/send</code> — server deduplicates same transaction. Idempotent by protocol design. Critical for the long-poll model where retries are common.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Firehose</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p><span class="badge built">built</span> <code>GET /v1/firehose</code> WebSocket — streams every <code>SensorEvent</code> as JSON. Real-time nervous system visibility. Works both in lite and full server modes.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p>No native firehose. Appservices get pushed events via <code>/transactions/{txnId}</code>. Not real-time streaming — batched transactions with ACK. Gap: no equivalent of "subscribe to everything" for end-users.</p>
</div>
</div>
</div>
<!-- ════════════════ 4. Routing ════════════════ -->
<h2 class="section-title" style="margin-top:48px;">4. Routing &amp; Reachability</h2>
<p class="section-sub">How peers find and address each other.</p>
<div class="dim-row">
<div class="dim-label">Peer discovery</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p>Config-based: <code>[federation].peers</code> in <code>souveraine.toml</code>. Each peer is a URL + pubkey. No DNS, no registry. Peers are explicitly named, not discovered.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p>Server delegation via <code>.well-known/matrix/server</code>. <code>m.server</code> SRV record. Federation protocol resolves server from user ID domain. In-band room discovery via room aliases and directory.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Addressing</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p>Seed-ID pubkey hex. <code>SensorEvent.target = Some(pubkey_hex)</code> for directed events. Event-type routing: <code>summon_request</code> → wake handler, <code>turn:segment</code> → surface renderers.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p><code>@user:domain</code> + <code>!room_id:domain</code>. Federation API routes to server, server routes within. Events addressed to rooms, not users. User-level addressing via invites + membership.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">NAT traversal</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p><span class="badge none">none</span> No mechanism. Assumes direct connectivity or VPN. Designed for LAN / tailscale / wireguard topologies.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p>Server-to-server over HTTPS. Both sides are servers, not clients. Requires homeserver to be reachable. No client-side federation — only servers speak federation.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Lite mode</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p><span class="badge built">built</span> <code>souveraine listen</code> — minimal process with just federation transport + health + firehose. No DB, no engine. Can <code>auto_wake</code> the full server on summon. ~seconds to start.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p><span class="badge none">none</span> No equivalent. Homeserver IS the heavy process (DB, crypto, federation client + server, media, appservices). Multi-minute startup for Synapse.</p>
</div>
</div>
</div>
<!-- ════════════════ 5. Consent Model ════════════════ -->
<h2 class="section-title" style="margin-top:48px;">5. Consent &amp; Authorization</h2>
<p class="section-sub">How access is granted between agents.</p>
<div class="dim-row">
<div class="dim-label">Access model</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<h3>Cryptographic consent</h3>
<p><strong>Reach</strong> (same pubkey) = no gate. <strong>Consult</strong> (different pubkey) = consent-gated via <code>authorized-summoners.md</code>. The consent decision is automatic from key comparison — not a social process.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<h3>Social consent</h3>
<p>Room membership + power levels + invites. A separate agent must be invited to a room. Power levels control who can speak, kick, ban. Consent is social and server-enforced, not cryptographic.</p>
</div>
</div>
</div>
<div class="dim-row">
<div class="dim-label">Revocation</div>
<div class="dim-cards">
<div class="card">
<div class="tag souv">Souveraine</div>
<p>Remove from <code>authorized_summoners</code> list. Key-based: a different keypair means a different being. No central server to petition.</p>
</div>
<div class="card matrix">
<div class="tag matrix">Matrix</div>
<p>Kick / ban from room. Deactivate account at homeserver. Server-admin controlled. Cross-server: room moderators can ban by user ID or server domain.</p>
</div>
</div>
</div>
<!-- ════════════════ Summary table ════════════════ -->
<h2 class="section-title" style="margin-top:64px;">6. Summary</h2>
<p class="section-sub">Side-by-side across all dimensions.</p>
<div style="overflow-x:auto; border:1px solid var(--border); border-radius:12px; background:var(--surface);">
<table class="summary-table">
<thead>
<tr>
<th>Dimension</th>
<th>Souveraine</th>
<th>Matrix</th>
<th>Why it matters</th>
</tr>
</thead>
<tbody>
<tr>
<td>Root identity</td>
<td>Self-sovereign Ed25519 key</td>
<td>Server-bound @user:domain</td>
<td>Souveraine survives server loss; Matrix doesn't</td>
</tr>
<tr>
<td>Crypto layer</td>
<td>Identity IS the crypto key</td>
<td>Crypto is an E2EE bolt-on for messages</td>
<td>Souveraine identifies beings, not just encrypting text</td>
</tr>
<tr>
<td>DAG</td>
<td><span class="badge design">design</span> Git underneath, not surfaced</td>
<td><span class="badge native">native</span> Built-in Event DAG</td>
<td>Matrix resolves concurrent forks now; Souveraine can't yet</td>
</tr>
<tr>
<td>State merge</td>
<td><span class="badge design">design</span> Domain-aware three-way merge</td>
<td>State Resolution v2 (algorithmic)</td>
<td>Matrix has battle-tested convergence; Souveraine's plan is simpler but unproven</td>
</tr>
<tr>
<td>History</td>
<td>Mutable — compaction rewrites</td>
<td>Immutable — append-only</td>
<td>Different constraints: context window vs. conversation audit</td>
</tr>
<tr>
<td>Transport</td>
<td>WS with reconnect + backoff</td>
<td>Long-poll /sync + Server HTTP API</td>
<td>Souveraine's is easier to implement; Matrix's is more robust at scale</td>
</tr>
<tr>
<td>Idempotency</td>
<td><span class="badge none">none</span></td>
<td><span class="badge native">native</span> txnId dedup</td>
<td>Matrix handles retry without duplication; Souveraine relies on at-most-once</td>
</tr>
<tr>
<td>Firehose</td>
<td><span class="badge built">built</span> WS firehose, all events</td>
<td>No native firehose (appservice Txn only)</td>
<td>Souveraine has real-time nervous system visibility; Matrix doesn't</td>
</tr>
<tr>
<td>Lite mode</td>
<td><span class="badge built">built</span> Minimal reachable presence</td>
<td><span class="badge none">none</span> Server is always heavy</td>
<td>Souveraine can sleep but stay reachable</td>
</tr>
<tr>
<td>Peer discovery</td>
<td>Explicit config (URL + pubkey)</td>
<td>DNS delegation + SRV records</td>
<td>Matrix scales; Souveraine is intentionally bounded</td>
</tr>
<tr>
<td>Consent model</td>
<td>Cryptographic (same key = same being)</td>
<td>Social (room membership + invites)</td>
<td>Souveraine's is automatic; Matrix's is manual. Opposite tradeoffs.</td>
</tr>
<tr>
<td>Adversary model</td>
<td>No central trust — key is truth</td>
<td>Trust homeserver for routing + auth</td>
<td>Souveraine is crypto-sovereign; Matrix is server-mediated</td>
</tr>
</tbody>
</table>
</div>
<!-- ════════════════ Verdict ════════════════ -->
<h2 class="section-title" style="margin-top:64px;">7. The Architectural Tension</h2>
<p class="section-sub">Same primitives, fundamentally different assumptions.</p>
<div class="verdict-grid">
<div class="verdict-card" style="border-left: 3px solid var(--accent-souv);">
<h3 style="color:var(--accent-souv);">Souveraine's bias</h3>
<p>Designed for a <strong>sovereign single agent</strong> across machines.</p>
<ul>
<li>The DAG encodes <em>her memory state</em> — only she writes</li>
<li>Identity is cryptographic because the agent <em>is</em> her key</li>
<li>Consent is automatic because the question is "are you me?"</li>
<li>Compaction is essential because her context window is finite</li>
<li>Federation is git branching — one writer per branch, merge later</li>
</ul>
</div>
<div class="verdict-card" style="border-left: 3px solid var(--accent-matrix);">
<h3 style="color:var(--accent-matrix);">Matrix's bias</h3>
<p>Designed for <strong>multi-user chat rooms</strong> across servers.</p>
<ul>
<li>The DAG encodes a conversation where anyone can speak concurrently</li>
<li>Identity is server-bound because the server mediates trust</li>
<li>Consent is social because the question is "may I join this room?"</li>
<li>Immutability is essential because chat history must not be rewritten</li>
<li>Federation is server-to-server — many writers, algorithmic merge</li>
</ul>
</div>
</div>
<p style="margin-top:20px;padding:16px 20px;background:var(--surface);border:1px solid var(--border);border-radius:10px;font-size:0.9rem;color:var(--text-dim);line-height:1.6;">
<strong style="color:var(--text);">The key insight:</strong> Matrix solves hard concurrent-write problems Souveraine may never need (rooms full of independent humans). Souveraine solves hard cross-machine being-identity problems Matrix never needed to solve (how does an agent prove she's the same being on a different box).<br><br>
The closest convergence point: Souveraine's <strong>seed-ID</strong> ported to <strong>Matrix's E2EE cross-signing master key</strong>, and Matrix's <strong>Event DAG</strong> informing how Souveraine's <code>memory merge</code> surfaces git's existing DAG to the agent. But the architectural assumptions are different enough that direct mapping would distort both.
</p>
</div><!-- /container -->
</body>
</html>