ontoref/assets/web/architecture-diagram-details.html
Jesús Pérez 0436a3b436
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
chore: add web and branding
2026-03-13 00:19:51 +00:00

2 lines
31 KiB
HTML

<!doctype html><html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=device-width, initial-scale=1.0" /><title>Ontoref — Architecture</title><link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" /><style>:root{--bg:#0f172a;--bg2:#1e293b;--bg3:#0a0f1e;--text:#e2e8f0;--muted:#64748b;--subtle:#334155;--blue:#60a5fa;--orange:#E8A838;--green:#4ade80;--purple:#c084fc;--teal:#22d3ee;--yellow:#facc15;--red:#f87171;--border:rgba(96,165,250,0.2);}html.light{--bg:#f8fafc;--bg2:#f1f5f9;--bg3:#e2e8f0;--text:#0f172a;--muted:#64748b;--subtle:#cbd5e1;--border:rgba(96,165,250,0.35);}*{margin:0;padding:0;box-sizing:border-box;}body{background:var(--bg);color:var(--text);font-family:"Inter",sans-serif;min-height:100vh;transition:background 0.3s,color 0.3s;padding:2rem;padding-top:5rem;}.nav{position:fixed;top:1.5rem;right:1.5rem;z-index:100;display:flex;gap:0.4rem;align-items:center;background:var(--bg2);border:1px solid var(--border);border-radius:20px;padding:0.3rem;backdrop-filter:blur(10px);}.nav a,.nav button{background:transparent;border:none;color:var(--muted);padding:0.4rem 0.9rem;border-radius:16px;cursor:pointer;font-weight:700;font-size:0.8rem;text-transform:uppercase;font-family:"JetBrains Mono",monospace;text-decoration:none;transition:all 0.2s;}.nav a:hover,.nav button:hover{color:var(--blue);}.nav .back{background:rgba(96,165,250,0.12);color:var(--blue);border:1px solid rgba(96,165,250,0.3);}.nav .back:hover{background:rgba(96,165,250,0.2);}.page{max-width:1200px;margin:0 auto;}.page-title{text-align:center;margin-bottom:3rem;}.page-title h1{font-size:2.2rem;font-weight:800;background:linear-gradient(135deg,var(--blue) 0%,var(--orange) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;margin-bottom:0.5rem;}.page-title p{color:var(--muted);font-size:0.95rem;}.arch{display:flex;flex-direction:column;gap:1px;border-radius:16px;overflow:hidden;border:1px solid var(--border);margin-bottom:3rem;}.layer{display:grid;grid-template-columns:180px 1fr;min-height:80px;position:relative;}.layer-tag{display:flex;align-items:center;justify-content:center;padding:1rem;font-family:"JetBrains Mono",monospace;font-size:0.68rem;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;text-align:center;line-height:1.4;border-right:1px solid var(--border);}.layer-body{padding:1rem 1.5rem;display:flex;flex-direction:column;justify-content:center;gap:0.4rem;}.layer-body .items{display:flex;flex-wrap:wrap;gap:0.4rem;}.chip{font-family:"JetBrains Mono",monospace;font-size:0.72rem;padding:0.2rem 0.6rem;border-radius:6px;background:rgba(255,255,255,0.04);border:1px solid var(--subtle);color:var(--muted);}.layer-body .desc{font-size:0.78rem;color:var(--muted);font-style:italic;line-height:1.5;}.l-declarative .layer-tag{background:rgba(96,165,250,0.08);color:var(--blue);border-color:rgba(96,165,250,0.2);}.l-declarative .layer-body{background:rgba(96,165,250,0.03);}.l-operational .layer-tag{background:rgba(232,168,56,0.08);color:var(--orange);border-color:rgba(232,168,56,0.2);}.l-operational .layer-body{background:rgba(232,168,56,0.02);}.l-entry .layer-tag{background:rgba(74,222,128,0.08);color:var(--green);border-color:rgba(74,222,128,0.2);}.l-entry .layer-body{background:rgba(74,222,128,0.02);}.l-graph .layer-tag{background:rgba(192,132,252,0.08);color:var(--purple);border-color:rgba(192,132,252,0.2);}.l-graph .layer-body{background:rgba(192,132,252,0.02);}.l-runtime .layer-tag{background:rgba(34,211,238,0.08);color:var(--teal);border-color:rgba(34,211,238,0.2);}.l-runtime .layer-body{background:rgba(34,211,238,0.02);}.l-adopt .layer-tag{background:rgba(250,204,21,0.08);color:var(--yellow);border-color:rgba(250,204,21,0.2);}.l-adopt .layer-body{background:rgba(250,204,21,0.02);}.daemon-detail{display:grid;grid-template-columns:repeat(3,1fr);gap:1.5rem;margin-bottom:3rem;}.daemon-detail .span2{grid-column:span 2;}.daemon-box{border-radius:12px;padding:1.5rem;border:1px solid var(--border);background:var(--bg2);}.daemon-box h3{font-size:0.78rem;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;font-family:"JetBrains Mono",monospace;margin-bottom:1rem;}.daemon-box.box-http h3{color:var(--teal);}.daemon-box.box-mcp h3{color:var(--blue);}.daemon-box.box-sessions h3{color:var(--green);}.daemon-box.box-notify h3{color:var(--orange);}.daemon-box.box-ncl h3{color:var(--yellow);}.daemon-box h3.sub-h{font-size:0.7rem;margin-top:1.25rem;margin-bottom:0.5rem;padding-top:1rem;border-top:1px solid rgba(255,255,255,0.06);}.route-list{list-style:none;}.route-list li{display:flex;align-items:baseline;gap:0.5rem;padding:0.25rem 0;border-bottom:1px solid rgba(255,255,255,0.04);font-size:0.75rem;}.route-list li:last-child{border-bottom:none;}.method{font-family:"JetBrains Mono",monospace;font-size:0.65rem;font-weight:700;padding:0.1rem 0.35rem;border-radius:4px;min-width:2.8rem;text-align:center;flex-shrink:0;}.method.get{background:rgba(74,222,128,0.15);color:var(--green);}.method.post{background:rgba(96,165,250,0.15);color:var(--blue);}.route-path{font-family:"JetBrains Mono",monospace;color:var(--text);font-size:0.72rem;flex:1;}.route-desc{color:var(--muted);font-size:0.68rem;}.tool-list{list-style:none;}.tool-list li{padding:0.25rem 0;border-bottom:1px solid rgba(255,255,255,0.04);font-size:0.73rem;}.tool-list li:last-child{border-bottom:none;}.tool-name{font-family:"JetBrains Mono",monospace;color:var(--blue);font-size:0.7rem;}.tool-desc{color:var(--muted);font-size:0.68rem;}.flow-section{margin-bottom:3rem;}.flow-section h2{font-size:1.1rem;font-weight:700;color:var(--muted);letter-spacing:0.06em;text-transform:uppercase;font-family:"JetBrains Mono",monospace;margin-bottom:1.5rem;text-align:center;}.flow-row{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;gap:0;margin-bottom:1rem;}.flow-row-label{font-family:"JetBrains Mono",monospace;font-size:0.68rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.6rem;text-align:center;}.flow-node{background:var(--bg2);border:1px solid var(--border);border-radius:10px;padding:0.8rem 1.2rem;text-align:center;min-width:100px;}.flow-node .fn-label{font-family:"JetBrains Mono",monospace;font-size:0.72rem;font-weight:600;}.flow-node .fn-sub{font-size:0.65rem;color:var(--muted);margin-top:0.2rem;}.flow-arrow{color:var(--subtle);font-size:1.4rem;padding:0 0.3rem;flex-shrink:0;}.flow-arrow.warn{color:var(--orange);}.fn-actor .fn-label{color:var(--green);}.fn-cli .fn-label{color:var(--yellow);}.fn-daemon .fn-label{color:var(--teal);}.fn-mcp .fn-label{color:var(--blue);}.fn-ncl .fn-label{color:var(--orange);}.fn-git .fn-label{color:var(--purple);}.fn-hook .fn-label{color:var(--red);}.fn-pass .fn-label{color:var(--green);}.persistence-grid{display:grid;grid-template-columns:1fr 1fr;gap:1.5rem;margin-bottom:3rem;}.persist-box{border-radius:12px;padding:1.5rem;border:1px solid;background:var(--bg2);}.persist-box.tier-memory{border-color:rgba(96,165,250,0.25);}.persist-box.tier-surreal{border-color:rgba(34,211,238,0.25);}.persist-box h3{font-size:0.78rem;font-weight:700;letter-spacing:0.08em;text-transform:uppercase;font-family:"JetBrains Mono",monospace;margin-bottom:0.4rem;}.persist-box.tier-memory h3{color:var(--blue);}.persist-box.tier-surreal h3{color:var(--teal);}.persist-box .tier-sub{font-size:0.72rem;color:var(--muted);font-style:italic;margin-bottom:0.85rem;}.persist-box ul{list-style:none;padding:0;font-size:0.75rem;color:var(--muted);line-height:1.9;}.persist-box ul li::before{content:"· ";}.persist-box ul strong{color:var(--text);}.persist-box ul code{font-family:"JetBrains Mono",monospace;font-size:0.7rem;color:var(--blue);}.constraints{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:1rem;margin-bottom:3rem;}.constraint-card{background:var(--bg2);border-radius:10px;padding:1rem 1.25rem;border-left:3px solid;font-size:0.8rem;}.constraint-card.hard{border-color:var(--red);}.constraint-card.soft{border-color:var(--yellow);}.constraint-card .c-id{font-family:"JetBrains Mono",monospace;font-size:0.68rem;color:var(--muted);margin-bottom:0.3rem;}.constraint-card .c-claim{color:var(--text);line-height:1.5;}.constraint-card.hard .c-id::before{content:"HARD · ";color:var(--red);}.constraint-card.soft .c-id::before{content:"SOFT · ";color:var(--yellow);}.section-h{font-size:1.1rem;font-weight:700;color:var(--muted);letter-spacing:0.06em;text-transform:uppercase;font-family:"JetBrains Mono",monospace;margin-bottom:1.5rem;padding-bottom:0.5rem;border-bottom:1px solid var(--border);}@media (max-width:1000px){.daemon-detail{grid-template-columns:1fr 1fr;}.daemon-detail .span2{grid-column:span 2;}.layer{grid-template-columns:120px 1fr;}}@media (max-width:700px){.daemon-detail{grid-template-columns:1fr;}.daemon-detail .span2{grid-column:span 1;}.persistence-grid{grid-template-columns:1fr;}body{padding:1rem;padding-top:5rem;}.layer{grid-template-columns:1fr;}.layer-tag{border-right:none;border-bottom:1px solid var(--border);min-height:auto;}.flow-row{gap:0.5rem;flex-direction:column;}.flow-arrow{transform:rotate(90deg);}}</style></head><body><div class="nav"><button onclick="toggleTheme()" id="theme-btn" title="Toggle theme">☀️</button><a href="index.html" class="back">← Ontoref</a></div><div class="page"><div class="page-title"><h1>Architecture</h1><p>Protocol layers, runtime components, data flows, persistence tiers, and active constraints — v0.1.0</p></div><div class="section-h">Protocol Layers</div><div class="arch"><div class="layer l-declarative"><div class="layer-tag">Declarative<br/>Layer<br/>Nickel</div><div class="layer-body"><div class="items"><span class="chip">.ontology/core.ncl</span><span class="chip">.ontology/state.ncl</span><span class="chip">adrs/adr-NNN.ncl</span><span class="chip">reflection/schemas/</span><span class="chip">reflection/modes/</span><span class="chip">reflection/forms/</span><span class="chip">reflection/qa.ncl</span><span class="chip">.ontoref/config.ncl</span></div><div class="desc">Strong types, contracts, enums. Fails at definition time. No runtime evaluation — nickel export produces JSON consumed by all layers above.</div></div></div><div class="layer l-graph"><div class="layer-tag">Knowledge<br/>Graph<br/>.ontology/</div><div class="layer-body"><div class="items"><span class="chip">4 axioms</span><span class="chip">2 tensions</span><span class="chip">12 practices</span><span class="chip">nodes + edges</span><span class="chip">invariants</span><span class="chip">gates</span><span class="chip">dimensions</span></div><div class="desc">The project knows what it knows. Actor-agnostic. Machine-queryable. ontoref uses its own protocol — the .ontology/ here describes ontoref itself.</div></div></div><div class="layer l-operational"><div class="layer-tag">Operational<br/>Layer<br/>Nushell</div><div class="layer-body"><div class="items"><span class="chip">adr.nu</span><span class="chip">backlog.nu</span><span class="chip">coder.nu</span><span class="chip">describe.nu</span><span class="chip">sync.nu</span><span class="chip">config.nu</span><span class="chip">register.nu</span><span class="chip">forms.nu</span><span class="chip">+8 more</span></div><div class="desc">Typed Nushell pipelines over structured data — no text streams. 16 modules, each responsible for one operational domain. DAG modes validated before execution.</div></div></div><div class="layer l-entry"><div class="layer-tag">Entry<br/>Point<br/>Bash → Nu</div><div class="layer-body"><div class="items"><span class="chip">./ontoref</span><span class="chip">actor detection</span><span class="chip">advisory locking</span><span class="chip">NICKEL_IMPORT_PATH</span><span class="chip">./ontoref -V</span></div><div class="desc">Single entry point per project. Detects actor (developer / agent / CI) from flag, env var, or TTY. Acquires mkdir-based POSIX advisory lock per resource. Dispatches to Nu.</div></div></div><div class="layer l-runtime"><div class="layer-tag">Runtime<br/>Layer<br/>Rust + axum</div><div class="layer-body"><div class="items"><span class="chip">ontoref-daemon</span><span class="chip">ontoref-ontology</span><span class="chip">ontoref-reflection</span><span class="chip">axum HTTP API</span><span class="chip">Tera templates</span><span class="chip">MCP server</span><span class="chip">DashMap cache</span><span class="chip">notify watcher</span><span class="chip">drift observer</span><span class="chip">search engine</span><span class="chip">notification store</span><span class="chip">actor registry</span><span class="chip">session store</span><span class="chip">SurrealDB (optional)</span></div><div class="desc">Optional persistent daemon. Caches nickel export results (path+mtime keyed). Serves HTTP UI (10 pages) + MCP server (19 tools). Actor registry with DashMap sessions. Notification barrier (pre_commit, drift, ontology_drift). Full-text search engine across nodes/ADRs/modes. Never a protocol requirement.</div></div></div><div class="layer l-adopt"><div class="layer-tag">Adoption<br/>Layer<br/>Per-project</div><div class="layer-body"><div class="items"><span class="chip">templates/ontology/</span><span class="chip">templates/ontoref-config.ncl</span><span class="chip">templates/scripts-ontoref</span><span class="chip">adopt_ontoref mode</span><span class="chip">ONTOREF_PROJECT_ROOT</span></div><div class="desc">Each project maintains its own .ontology/ data. One ontoref checkout serves multiple projects via ONTOREF_PROJECT_ROOT. Zero lock-in — files are plain NCL.</div></div></div></div><div class="flow-section"><div class="section-h">Request Flows</div><div class="flow-row-label">CLI path — developer or agent via shell</div><div class="flow-row"><div class="flow-node fn-actor"><div class="fn-label">Actor</div><div class="fn-sub">developer · agent · CI</div></div><div class="flow-arrow"></div><div class="flow-node fn-cli"><div class="fn-label">./ontoref</div><div class="fn-sub">bash wrapper</div></div><div class="flow-arrow"></div><div class="flow-node fn-cli"><div class="fn-label">ontoref.nu</div><div class="fn-sub">Nu dispatcher</div></div><div class="flow-arrow"></div><div class="flow-node fn-daemon"><div class="fn-label">daemon</div><div class="fn-sub">cache / notify</div></div><div class="flow-arrow"></div><div class="flow-node fn-ncl"><div class="fn-label">nickel export</div><div class="fn-sub">.ontology/ · adrs/</div></div><div class="flow-arrow"></div><div class="flow-node fn-git"><div class="fn-label">reflection/</div><div class="fn-sub">qa.ncl · backlog.ncl</div></div></div><div class="flow-row-label" style="margin-top:1.5rem;">MCP / AI agent path — Claude Code or any MCP client</div><div class="flow-row" style="opacity: 0.85;"><div class="flow-node fn-mcp" style="min-width: 80px;"><div class="fn-label">AI Agent</div><div class="fn-sub">Claude · any MCP client</div></div><div class="flow-arrow"></div><div class="flow-node fn-daemon"><div class="fn-label">MCP server</div><div class="fn-sub">stdio · HTTP /mcp</div></div><div class="flow-arrow"></div><div class="flow-node fn-ncl"><div class="fn-label">19 tools</div><div class="fn-sub">read · write · query</div></div><div class="flow-arrow"></div><div class="flow-node fn-git"><div class="fn-label">NCL files</div><div class="fn-sub">git-versioned</div></div></div><div class="flow-row-label" style="margin-top:1.5rem;">Pre-commit barrier — notification-gated commit path</div><div class="flow-row" style="opacity: 0.85;"><div class="flow-node fn-hook"><div class="fn-label">git commit</div><div class="fn-sub">pre-commit hook fires</div></div><div class="flow-arrow warn"></div><div class="flow-node fn-daemon"><div class="fn-label">GET /notifications</div><div class="fn-sub">/pending?token=X&amp;project=Y</div></div><div class="flow-arrow"></div><div class="flow-node fn-ncl"><div class="fn-label">pending?</div><div class="fn-sub">pre_commit · drift · ontology_drift</div></div><div class="flow-arrow warn"></div><div class="flow-node fn-hook"><div class="fn-label">block</div><div class="fn-sub">until acked in UI / POST /notifications/ack</div></div><div class="flow-arrow"></div><div class="flow-node fn-pass"><div class="fn-label">pass</div><div class="fn-sub">fail-open if daemon unreachable</div></div></div></div><div class="section-h">Daemon Components</div><div class="daemon-detail"><div class="daemon-box box-http"><h3>HTTP API · /ui/{slug}</h3><ul class="route-list"><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/</span><span class="route-desc">Dashboard — overview, actors, cache stats</span></li><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/graph</span><span class="route-desc">D3 ontology graph (nodes by pole, edges)</span></li><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/search</span><span class="route-desc">Search across nodes/ADRs/modes</span></li><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/sessions</span><span class="route-desc">Live actor registry</span></li><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/notifications</span><span class="route-desc">Notification feed + ack UI</span></li><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/backlog</span><span class="route-desc">Backlog with priority/status</span></li><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/qa</span><span class="route-desc">Q&amp;A knowledge store</span></li><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/actions</span><span class="route-desc">Quick actions catalog</span></li><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/modes</span><span class="route-desc">Reflection modes browser</span></li><li><span class="method get">GET</span><span class="route-path">/ui/{slug}/compose</span><span class="route-desc">Agent task composer (live sharing)</span></li><li><span class="method get">GET</span><span class="route-path">/actors</span><span class="route-desc">Actor sessions list</span></li><li><span class="method get">GET</span><span class="route-path">/search?q=&amp;project=</span><span class="route-desc">Search JSON endpoint</span></li><li><span class="method get">GET</span><span class="route-path">/notifications/pending</span><span class="route-desc">Pre-commit hook polling</span></li><li><span class="method post">POST</span><span class="route-path">/notifications/ack</span><span class="route-desc">Ack one or all notifications</span></li><li><span class="method post">POST</span><span class="route-path">/{slug}/notifications/emit</span><span class="route-desc">Emit custom notification</span></li><li><span class="method post">POST</span><span class="route-path">/{slug}/notifications/{id}/action</span><span class="route-desc">Trigger notification action</span></li><li><span class="method post">POST</span><span class="route-path">/compose/send</span><span class="route-desc">Dispatch mode to ./ontoref server-side</span></li><li><span class="method post">POST</span><span class="route-path">/actions/run</span><span class="route-desc">Execute quick action by id</span></li><li><span class="method post">POST</span><span class="route-path">/qa/add</span><span class="route-desc">Append Q&amp;A entry to NCL</span></li><li><span class="method post">POST</span><span class="route-path">/qa/delete</span><span class="route-desc">Remove entry by id</span></li><li><span class="method post">POST</span><span class="route-path">/qa/update</span><span class="route-desc">Mutate question + answer</span></li><li><span class="method get">GET</span><span class="route-path">/qa-json</span><span class="route-desc">Export all Q&amp;A entries</span></li><li><span class="method post">POST</span><span class="route-path">/backlog/add</span><span class="route-desc">Add backlog item</span></li><li><span class="method post">POST</span><span class="route-path">/backlog/status</span><span class="route-desc">Update backlog item status</span></li><li><span class="method get">GET</span><span class="route-path">/backlog-json</span><span class="route-desc">Export backlog as JSON</span></li><li><span class="method get">GET</span><span class="route-path">/health</span><span class="route-desc">Cache stats + uptime + SurrealDB status</span></li></ul></div><div class="daemon-box box-mcp"><h3>MCP Server · 19 tools</h3><ul class="tool-list"><li><span class="tool-name">ontoref_help</span><span class="tool-desc">— list all tools and usage</span></li><li><span class="tool-name">ontoref_list_projects</span><span class="tool-desc">— enumerate loaded projects</span></li><li><span class="tool-name">ontoref_set_project</span><span class="tool-desc">— set session default project</span></li><li><span class="tool-name">ontoref_project_status</span><span class="tool-desc">— full project dashboard</span></li><li><span class="tool-name">ontoref_describe</span><span class="tool-desc">— architecture overview</span></li><li><span class="tool-name">ontoref_search</span><span class="tool-desc">— free-text across nodes/ADRs/modes</span></li><li><span class="tool-name">ontoref_get</span><span class="tool-desc">— fetch node by id</span></li><li><span class="tool-name">ontoref_get_node</span><span class="tool-desc">— full ontology node with edges</span></li><li><span class="tool-name">ontoref_list_adrs</span><span class="tool-desc">— list ADRs by status filter</span></li><li><span class="tool-name">ontoref_get_adr</span><span class="tool-desc">— full ADR with constraints</span></li><li><span class="tool-name">ontoref_list_modes</span><span class="tool-desc">— list reflection modes</span></li><li><span class="tool-name">ontoref_get_mode</span><span class="tool-desc">— mode DAG contract</span></li><li><span class="tool-name">ontoref_get_backlog</span><span class="tool-desc">— backlog filtered by status</span></li><li><span class="tool-name">ontoref_backlog</span><span class="tool-desc">— add / update_status</span></li><li><span class="tool-name">ontoref_constraints</span><span class="tool-desc">— all architectural constraints</span></li><li><span class="tool-name">ontoref_qa_list</span><span class="tool-desc">— list Q&amp;A with optional filter</span></li><li><span class="tool-name">ontoref_qa_add</span><span class="tool-desc">— append to reflection/qa.ncl</span></li><li><span class="tool-name">ontoref_action_list</span><span class="tool-desc">— quick actions from config.ncl</span></li><li><span class="tool-name">ontoref_action_add</span><span class="tool-desc">— create mode + register action</span></li></ul></div><div class="daemon-box box-sessions"><h3>Sessions &amp; Actor Registry</h3><ul class="route-list"><li><span class="route-path">ActorRegistry</span><span class="route-desc">backed by DashMap&lt;String, ActorSession&gt;</span></li><li><span class="route-path">token</span><span class="route-desc">random string, unique per session</span></li><li><span class="route-path">actor_type</span><span class="route-desc">developer · agent · CI</span></li><li><span class="route-path">registered_at</span><span class="route-desc">ISO timestamp, set on registration</span></li><li><span class="route-path">last_seen</span><span class="route-desc">updated on each API call</span></li><li><span class="route-path">current_mode</span><span class="route-desc">last active reflection mode</span></li><li><span class="route-path">serializable</span><span class="route-desc">snapshot for disk persistence</span></li><li><span class="route-path">pre-commit CI</span><span class="route-desc">registers as ci actor on hook fire</span></li></ul><h3 class="sub-h">Compose / Live Sharing</h3><ul class="route-list"><li><span class="route-path">/ui/{slug}/compose</span><span class="route-desc">renders mode form schemas as interactive HTML</span></li><li><span class="route-path">POST /compose/send</span><span class="route-desc">dispatches ./ontoref {mode} {params} on server</span></li><li><span class="route-path">shared context</span><span class="route-desc">multiple actors see same composed task live</span></li><li><span class="route-path">/ui/{slug}/manage</span><span class="route-desc">project registry CRUD (multi-project mode)</span></li></ul></div><div class="daemon-box box-notify"><h3>Notification Store &amp; Search</h3><ul class="route-list"><li><span class="route-path">NotificationStore</span><span class="route-desc">in-memory queue per (project, token)</span></li><li><span class="route-path">pre_commit</span><span class="route-desc">blocks git commits until acked by actor</span></li><li><span class="route-path">drift</span><span class="route-desc">schema drift between codebase and ontology</span></li><li><span class="route-path">ontology_drift</span><span class="route-desc">from passive observer — missing/stale/drift/broken counts</span></li><li><span class="route-path">fail-open</span><span class="route-desc">if daemon unreachable, pre-commit hook passes</span></li><li><span class="route-path">ack workflow</span><span class="route-desc">POST /notifications/ack (one or all); action buttons in UI</span></li></ul><h3 class="sub-h">Search Engine</h3><ul class="route-list"><li><span class="route-path">indexes</span><span class="route-desc">ontology nodes (id, name, description)</span></li><li><span class="route-path">indexes</span><span class="route-desc">ADRs (title, context, decision)</span></li><li><span class="route-path">indexes</span><span class="route-desc">reflection modes (name, description, steps)</span></li><li><span class="route-path">SearchResult</span><span class="route-desc">kind · id · title · snippet · score</span></li><li><span class="route-path">used by</span><span class="route-desc">UI search page + MCP ontoref_search tool</span></li></ul></div><div class="daemon-box box-ncl span2"><h3>NCL Files — Mutations</h3><ul class="route-list"><li><span class="route-path">reflection/qa.ncl</span><span class="route-desc">QaStore — typed entries, git-versioned; written only via crates/ontoref-daemon/src/ui/qa_ncl.rs (ADR-003 hard constraint)</span></li><li><span class="route-path">reflection/backlog.ncl</span><span class="route-desc">BacklogStore — items with status (Open/InProgress/Done/Cancelled) and priority (Critical/High/Medium/Low)</span></li><li><span class="route-path">.ontoref/config.ncl</span><span class="route-desc">quick_actions catalog, log level, NATS toggle</span></li><li><span class="route-path">reflection/modes/*.ncl</span><span class="route-desc">new mode files created by ontoref_action_add</span></li></ul><h3 class="sub-h">Drift Observer</h3><ul class="route-list"><li><span class="route-path">watches</span><span class="route-desc">crates/ · .ontology/ · adrs/ · reflection/modes/</span></li><li><span class="route-path">debounce</span><span class="route-desc">15 seconds after last filesystem event</span></li><li><span class="route-path">runs</span><span class="route-desc">sync scan → sync diff (read-only, never applies changes)</span></li><li><span class="route-path">emits</span><span class="route-desc">ontology_drift { missing, stale, drift, broken } to NotificationStore</span></li></ul><h3 class="sub-h">SurrealDB (optional --db feature)</h3><ul class="route-list"><li><span class="route-path">connection</span><span class="route-desc">WebSocket to --db-url ws://...; 5s timeout at startup; fail-open</span></li><li><span class="route-path">seeds</span><span class="route-desc">ontology tables from local NCL files on startup and on file changes (via notify watcher)</span></li><li><span class="route-path">persists</span><span class="route-desc">actor sessions, seeded ontology tables, search index, notification history — survives daemon restarts</span></li><li><span class="route-path">without --db</span><span class="route-desc">DashMap-backed in-memory cache only; process-lifetime; actor sessions and search index are ephemeral</span></li></ul></div></div><div class="section-h">Persistence Tiers</div><div class="persistence-grid"><div class="persist-box tier-memory"><h3>In-Memory — Always Active</h3><p class="tier-sub">DashMap-backed, process-lifetime — no flags required</p><ul><li><strong>DashMap cache</strong> — NCL export results, path+mtime keyed</li><li><strong>NotificationStore</strong> — per (project, token) notification queue</li><li><strong>ActorRegistry</strong> — live session DashMap</li><li><strong>SessionStore</strong> — token → ActorSession map</li><li><strong>Search index</strong> — in-process full-text over loaded NCL data</li><li>All state is <strong>lost on daemon restart</strong></li><li>Serializable snapshots can be written to disk as JSON/NCL</li></ul></div><div class="persist-box tier-surreal"><h3>SurrealDB — Optional <code>--db</code> Flag</h3><p class="tier-sub">WebSocket connection, fail-open — survives daemon restarts</p><ul><li><strong>Actor sessions</strong> — token, type, registered_at, last_seen, mode</li><li><strong>Seeded ontology tables</strong> — nodes, ADRs, modes from NCL files</li><li><strong>Search index</strong> — persisted search index for nodes/ADRs/modes</li><li><strong>Notification history</strong> — acked and dismissed notifications</li><li>Enabled with <code>--db-url ws://...</code> + <code>--db-namespace</code></li><li>If SurrealDB is unreachable at startup, <strong>daemon still starts</strong> using in-memory tier</li></ul></div></div><div class="section-h">Active Constraints (ADR-003 · ADR-002 · ADR-001)</div><div class="constraints"><div class="constraint-card hard"><div class="c-id">qa-write-via-mutation-module</div><div class="c-claim">All mutations to reflection/qa.ncl must go through <code>crates/ontoref-daemon/src/ui/qa_ncl.rs</code> — no direct file writes from other call sites.</div></div><div class="constraint-card hard"><div class="c-id">qa-schema-typed</div><div class="c-claim"><code>reflection/qa.ncl</code> must conform to the QaStore contract from <code>reflection/schemas/qa.ncl</code> — nickel typecheck must pass.</div></div><div class="constraint-card hard"><div class="c-id">mcp-qa-tools-no-apply-drift</div><div class="c-claim">MCP tools <code>ontoref_qa_list</code> and <code>ontoref_qa_add</code> must never trigger sync apply steps or modify <code>.ontology/</code> files.</div></div><div class="constraint-card hard"><div class="c-id">protocol-not-runtime (axiom)</div><div class="c-claim">ontoref-daemon is optional runtime support — not a protocol requirement. The protocol functions without it. Every module falls back to direct subprocess.</div></div><div class="constraint-card hard"><div class="c-id">notification-barrier-fail-open</div><div class="c-claim">The pre-commit hook must not block git commits when the daemon is unreachable. If <code>GET /notifications/pending</code> fails (connection error, timeout), the hook must pass immediately.</div></div><div class="constraint-card hard"><div class="c-id">ontology-crate-zero-stratumiops-deps (ADR-001)</div><div class="c-claim"><code>ontoref-ontology</code> must never depend on <code>stratum-graph</code>, <code>stratum-state</code>, or <code>stratum-orchestrator</code>. The ontology crate is the protocol's minimal adoption surface and must build standalone.</div></div></div></div><script> const KEY = "ontoref-arch-theme";function getTheme(){return localStorage.getItem(KEY)|| "dark";}function setTheme(t){localStorage.setItem(KEY,t);const btn = document.getElementById("theme-btn");if(t === "light"){document.documentElement.classList.add("light");btn.textContent = "🌙";}else{document.documentElement.classList.remove("light");btn.textContent = "☀️";}}function toggleTheme(){setTheme(getTheme()=== "dark" ? "light" : "dark");}document.addEventListener("DOMContentLoaded",()=> setTheme(getTheme()));</script></body></html>