kogral/docs/diagrams/config-composition.svg

134 lines
6.8 KiB
XML
Raw Normal View History

2026-01-23 16:11:07 +00:00
<?xml version="1.0" encoding="UTF-8"?>
<svg width="800" height="900" xmlns="http://www.w3.org/2000/svg">
<defs>
<style>
.layer-box { fill: #e8f4f8; stroke: #1976d2; stroke-width: 2; }
.schema-box { fill: #fff3e0; stroke: #f57c00; stroke-width: 2; }
.result-box { fill: #e8f5e9; stroke: #388e3c; stroke-width: 2; }
.file-box { fill: white; stroke: #666; stroke-width: 1; }
.text { font-family: 'Courier New', monospace; font-size: 12px; fill: #333; }
.title { font-family: Arial, sans-serif; font-size: 16px; font-weight: bold; fill: #333; }
.label { font-family: Arial, sans-serif; font-size: 13px; fill: #666; }
.arrow { stroke: #666; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
.merge-arrow { stroke: #1976d2; stroke-width: 3; fill: none; marker-end: url(#bluearrow); }
.code { font-family: 'Courier New', monospace; font-size: 11px; fill: #333; }
</style>
<marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
<polygon points="0 0, 10 3, 0 6" fill="#666" />
</marker>
<marker id="bluearrow" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
<polygon points="0 0, 10 3, 0 6" fill="#1976d2" />
</marker>
</defs>
<!-- Title -->
<text x="400" y="30" class="title" text-anchor="middle" font-size="20">Configuration Composition Flow</text>
<text x="400" y="52" class="label" text-anchor="middle">Nickel Schema → Validated Config → Rust Struct</text>
<!-- Layer 1: Schema Contracts -->
<rect x="50" y="80" width="700" height="120" class="schema-box" rx="8"/>
<text x="400" y="105" class="title" text-anchor="middle">Layer 1: Schema Contracts (Type Definitions)</text>
<rect x="70" y="120" width="300" height="60" class="file-box" rx="4"/>
<text x="80" y="140" class="text">schemas/contracts.ncl</text>
<text x="80" y="158" class="code">KbConfig = {</text>
<text x="90" y="172" class="code"> graph | GraphConfig,</text>
<text x="90" y="186" class="code"> storage | StorageConfig,</text>
<rect x="430" y="120" width="300" height="60" class="file-box" rx="4"/>
<text x="440" y="140" class="text">Defines types:</text>
<text x="440" y="158" class="code">StorageType = [| 'filesystem,</text>
<text x="440" y="172" class="code"> 'memory, 'surrealdb |]</text>
<!-- Arrow down -->
<path d="M 400 200 L 400 220" class="arrow"/>
<text x="410" y="215" class="label">validates</text>
<!-- Layer 2: Defaults -->
<rect x="50" y="220" width="700" height="120" class="layer-box" rx="8"/>
<text x="400" y="245" class="title" text-anchor="middle">Layer 2: Default Values</text>
<rect x="70" y="260" width="660" height="60" class="file-box" rx="4"/>
<text x="80" y="280" class="text">schemas/defaults.ncl</text>
<text x="80" y="298" class="code">base = {</text>
<text x="90" y="312" class="code"> storage = { primary = 'filesystem, secondary = { enabled = false } },</text>
<text x="90" y="326" class="code"> embeddings = { provider = 'fastembed, model = "BAAI/bge-small-en-v1.5" },</text>
<!-- Arrow down -->
<path d="M 400 340 L 400 360" class="arrow"/>
<text x="410" y="355" class="label">base for</text>
<!-- Layer 3: Mode Overlay -->
<rect x="50" y="360" width="700" height="160" class="layer-box" rx="8"/>
<text x="400" y="385" class="title" text-anchor="middle">Layer 3: Mode Overlay (Environment-Specific)</text>
<!-- Dev mode -->
<rect x="70" y="400" width="200" height="100" class="file-box" rx="4"/>
<text x="80" y="420" class="text">modes/dev.ncl</text>
<text x="80" y="438" class="code">storage = {</text>
<text x="85" y="452" class="code"> primary = 'filesystem,</text>
<text x="85" y="466" class="code"> secondary.enabled</text>
<text x="85" y="480" class="code"> = false</text>
<text x="80" y="494" class="code">}</text>
<!-- Prod mode -->
<rect x="290" y="400" width="200" height="100" class="file-box" rx="4"/>
<text x="300" y="420" class="text">modes/prod.ncl</text>
<text x="300" y="438" class="code">storage = {</text>
<text x="305" y="452" class="code"> primary = 'filesystem,</text>
<text x="305" y="466" class="code"> secondary.enabled</text>
<text x="305" y="480" class="code"> = true</text>
<text x="300" y="494" class="code">}</text>
<!-- Test mode -->
<rect x="510" y="400" width="200" height="100" class="file-box" rx="4"/>
<text x="520" y="420" class="text">modes/test.ncl</text>
<text x="520" y="438" class="code">storage = {</text>
<text x="525" y="452" class="code"> primary = 'memory,</text>
<text x="525" y="466" class="code"> secondary.enabled</text>
<text x="525" y="480" class="code"> = false</text>
<text x="520" y="494" class="code">}</text>
<!-- Arrow down -->
<path d="M 400 520 L 400 540" class="arrow"/>
<text x="410" y="535" class="label">select one</text>
<!-- Layer 4: User Customization -->
<rect x="50" y="540" width="700" height="100" class="layer-box" rx="8"/>
<text x="400" y="565" class="title" text-anchor="middle">Layer 4: User Customization (Project-Specific)</text>
<rect x="70" y="580" width="660" height="40" class="file-box" rx="4"/>
<text x="80" y="600" class="text">.kogral-config/core/kogral.ncl</text>
<text x="80" y="614" class="code">{ graph = { name = "my-project" }, embeddings = { model = "custom-model" } }</text>
<!-- Merge operation -->
<rect x="250" y="660" width="300" height="60" fill="#fff9c4" stroke="#f57f17" stroke-width="2" rx="6"/>
<text x="400" y="680" class="title" text-anchor="middle">Composition (helpers.ncl)</text>
<text x="400" y="700" class="code" text-anchor="middle">merge_with_override(defaults,</text>
<text x="400" y="714" class="code" text-anchor="middle"> mode_overlay, user_custom)</text>
<!-- Arrow from user to merge -->
<path d="M 400 640 L 400 660" class="merge-arrow"/>
<!-- Arrow from merge down -->
<path d="M 400 720 L 400 740" class="merge-arrow"/>
<text x="410" y="735" class="label" fill="#1976d2" font-weight="bold">nickel export</text>
<!-- Result: JSON -->
<rect x="50" y="740" width="700" height="80" class="result-box" rx="8"/>
<text x="400" y="765" class="title" text-anchor="middle">Exported JSON (.kogral-config/targets/kogral-core.json)</text>
<rect x="70" y="780" width="660" height="25" class="file-box" rx="4"/>
<text x="80" y="798" class="code">{"graph":{"name":"my-project"},"storage":{"primary":"filesystem"},...}</text>
<!-- Arrow down -->
<path d="M 400 820 L 400 840" class="arrow"/>
<text x="410" y="835" class="label">serde deserialize</text>
<!-- Final: Rust Struct -->
<rect x="150" y="840" width="500" height="50" fill="#f3e5f5" stroke="#7b1fa2" stroke-width="2" rx="6"/>
<text x="400" y="860" class="title" text-anchor="middle">Rust: KbConfig Struct</text>
<text x="400" y="878" class="code" text-anchor="middle">let config = KbConfig::from_file(".kogral-config/targets/kogral-core.json")?;</text>
</svg>