839 lines
41 KiB
HTML
839 lines
41 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 ── */
|
||
|
|
.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); }
|
||
|
|
/* ── Layout ── */
|
||
|
|
.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; }
|
||
|
|
|
||
|
|
/* ── Layer stack ── */
|
||
|
|
.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;
|
||
|
|
}
|
||
|
|
|
||
|
|
/* Layer colours */
|
||
|
|
.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 Components 5-col grid ── */
|
||
|
|
.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 diagram ── */
|
||
|
|
.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 tiers ── */
|
||
|
|
.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);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* ── Constraint callouts ── */
|
||
|
|
.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 headers ── */
|
||
|
|
.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>
|
||
|
|
|
||
|
|
<!-- ── Protocol Layer Stack ── -->
|
||
|
|
<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>
|
||
|
|
|
||
|
|
<!-- ── Request Flows ── -->
|
||
|
|
<div class="flow-section">
|
||
|
|
<div class="section-h">Request Flows</div>
|
||
|
|
|
||
|
|
<!-- Flow 1: CLI path -->
|
||
|
|
<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>
|
||
|
|
|
||
|
|
<!-- Flow 2: MCP/agent path -->
|
||
|
|
<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>
|
||
|
|
|
||
|
|
<!-- Flow 3: pre-commit hook -->
|
||
|
|
<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&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>
|
||
|
|
|
||
|
|
<!-- ── Daemon Components ── -->
|
||
|
|
<div class="section-h">Daemon Components</div>
|
||
|
|
<div class="daemon-detail">
|
||
|
|
|
||
|
|
<!-- Box 1: HTTP API routes -->
|
||
|
|
<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&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=&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&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&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>
|
||
|
|
|
||
|
|
<!-- Box 2: MCP Server -->
|
||
|
|
<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&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>
|
||
|
|
|
||
|
|
<!-- Box 3: Sessions & Actors -->
|
||
|
|
<div class="daemon-box box-sessions">
|
||
|
|
<h3>Sessions & Actor Registry</h3>
|
||
|
|
<ul class="route-list">
|
||
|
|
<li><span class="route-path">ActorRegistry</span><span class="route-desc">backed by DashMap<String, ActorSession></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>
|
||
|
|
|
||
|
|
<!-- Box 4: Notification Store & Search -->
|
||
|
|
<div class="daemon-box box-notify">
|
||
|
|
<h3>Notification Store & 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>
|
||
|
|
|
||
|
|
<!-- Box 5: NCL mutations + SurrealDB -->
|
||
|
|
<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>
|
||
|
|
|
||
|
|
<!-- ── Persistence Tiers ── -->
|
||
|
|
<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>
|
||
|
|
|
||
|
|
<!-- ── Active Constraints ── -->
|
||
|
|
<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><!-- /page -->
|
||
|
|
|
||
|
|
<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>
|