Files
el/docs/architecture/el-architecture.html
T
bigmerge 409bf57341 track the architecture docs
They were written outside git, so the reasoning that produces the design
had no history and no way to be superseded. capabilities.md and
geometry-vs-code.md are both known stale at this commit; they are tracked
as-is so the corrections are visible as movement rather than as a rewrite.
2026-08-17 04:34:32 -05:00

218 lines
17 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.
<title>The El Architecture</title>
<style>
:root{
--board:#f4f2ec; --board-line:#e5e1d6; --ink:#1c1f26; --ink-soft:#4a5160;
--ink-faint:#8b8f9a; --rule:#d8d3c6; --card:#fbfaf6;
--red:#a8321e; --amber:#9a6a12; --green:#2f6b46; --accent:#1f4e79;
}
@media (prefers-color-scheme: dark){
:root:not([data-theme="light"]){
--board:#14161b; --board-line:#1d212a; --ink:#e8e6df; --ink-soft:#a8adb8;
--ink-faint:#6f7480; --rule:#2a2f3a; --card:#191c23;
--red:#e4785f; --amber:#d9a441; --green:#6fbf8e; --accent:#7fb2e0;
}
}
:root[data-theme="dark"]{
--board:#14161b; --board-line:#1d212a; --ink:#e8e6df; --ink-soft:#a8adb8;
--ink-faint:#6f7480; --rule:#2a2f3a; --card:#191c23;
--red:#e4785f; --amber:#d9a441; --green:#6fbf8e; --accent:#7fb2e0;
}
*{box-sizing:border-box}
body{
margin:0; background:var(--board); color:var(--ink);
font:16px/1.68 ui-serif,Georgia,"Iowan Old Style",Palatino,serif;
background-image:linear-gradient(var(--board-line) 1px,transparent 1px),
linear-gradient(90deg,var(--board-line) 1px,transparent 1px);
background-size:30px 30px;
}
.wrap{max-width:940px;margin:0 auto;padding:56px 24px 96px}
.mono,code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
header{border-bottom:2px solid var(--ink);padding-bottom:20px}
h1{font-size:clamp(2.1rem,5.5vw,3.2rem);margin:0;letter-spacing:-.025em;text-wrap:balance}
.sub{color:var(--ink-soft);font-size:1.08rem;margin:12px 0 0;max-width:64ch}
.meta{font-family:ui-monospace,monospace;font-size:.76rem;color:var(--ink-faint);
text-transform:uppercase;letter-spacing:.1em;margin-top:16px}
h2{font-size:1.5rem;margin:56px 0 8px;letter-spacing:-.015em;text-wrap:balance}
h2 .n{font-family:ui-monospace,monospace;font-size:.78rem;color:var(--accent);
display:block;letter-spacing:.14em;margin-bottom:5px;font-weight:400}
h3{font-size:1.08rem;margin:30px 0 6px}
p{margin:0 0 14px;max-width:72ch}
.lede{color:var(--ink-soft);margin:0 0 20px;font-size:1.04rem}
.card{background:var(--card);border:1px solid var(--rule);border-radius:3px;padding:20px 22px;margin:18px 0}
.scroll{overflow-x:auto}
table{border-collapse:collapse;width:100%;font-size:.9rem;min-width:600px}
th{text-align:left;font-family:ui-monospace,monospace;font-size:.71rem;
text-transform:uppercase;letter-spacing:.09em;color:var(--ink-faint);
border-bottom:1px solid var(--ink);padding:0 14px 8px 0;font-weight:400}
td{padding:11px 14px 11px 0;border-bottom:1px solid var(--rule);vertical-align:top}
td.f{font-weight:600;white-space:nowrap}
td.m{font-family:ui-monospace,monospace;font-size:.83rem;font-variant-numeric:tabular-nums;white-space:nowrap}
.dead{color:var(--red);font-weight:600}
.part{color:var(--amber);font-weight:600}
.ok{color:var(--green);font-weight:600}
blockquote{margin:20px 0;padding:3px 0 3px 22px;border-left:3px solid var(--accent);
color:var(--ink-soft);font-style:italic;max-width:70ch}
ul{margin:0 0 14px;padding-left:22px;max-width:72ch} li{margin-bottom:9px}
code{font-size:.87em;background:var(--card);border:1px solid var(--rule);border-radius:2px;padding:1px 5px}
pre{background:var(--card);border:1px solid var(--rule);border-radius:3px;
padding:16px 18px;overflow-x:auto;font-size:.85rem;line-height:1.55;margin:16px 0}
pre code{background:none;border:0;padding:0}
.q{border-left:3px solid var(--amber);padding:14px 0 14px 20px;margin:20px 0;max-width:72ch}
.q b{display:block;font-size:1.04rem;margin-bottom:5px}
.q span{color:var(--ink-soft);font-size:.94rem}
hr{border:0;border-top:1px solid var(--rule);margin:46px 0}
.foot{color:var(--ink-faint);font-size:.86rem;margin-top:56px;border-top:1px solid var(--rule);padding-top:18px}
.tag{display:inline-block;font-family:ui-monospace,monospace;font-size:.66rem;
letter-spacing:.08em;text-transform:uppercase;border:1px solid var(--rule);
border-radius:2px;padding:2px 7px;color:var(--ink-faint);margin-left:8px;vertical-align:middle}
.flow{display:flex;gap:0;align-items:stretch;flex-wrap:wrap;margin:22px 0}
.flow div{flex:1 1 200px;border:1px solid var(--rule);background:var(--card);padding:16px 18px}
.flow div+div{border-left:0}
.flow h4{margin:0 0 6px;font-size:.96rem}
.flow p{margin:0;font-size:.87rem;color:var(--ink-soft)}
.flow .k{font-family:ui-monospace,monospace;font-size:.72rem;color:var(--accent);
letter-spacing:.1em;text-transform:uppercase;display:block;margin-bottom:4px}
</style>
<div class="wrap">
<header>
<h1>The El Architecture</h1>
<p class="sub">El is a concept-oriented language. This is the architecture that claim commits it to — what is built, what is measured, and what still has no home.</p>
<p class="meta">Working document · no sacred cows · self-hosting, so nothing here is fixed</p>
</header>
<h2><span class="n">01</span>The primitive is the concept</h2>
<p>Language families are named for their primitive. Procedural — procedures. Object-oriented — objects. Functional — functions. Logic — predicates. Every one of them is oriented toward a <em>representation</em> of a concept: the shape a concept gets flattened into so a machine can hold it.</p>
<p>El's primitive is the concept itself. That is why it is the first of its family and intended as the last — once the primitive is the concept, there is no further rung to climb to.</p>
<p>The consequence is architectural rather than stylistic:</p>
<blockquote>A concept with no home in the language does not disappear. It becomes C, or it becomes a convention.</blockquote>
<p>Both forms are measurable. As C: <span class="mono">20,504</span> lines of <code>el_runtime.c</code>, against <span class="mono">9,089</span> lines for the entire self-hosting language — the shim is 2.3× the language it serves, and ~47% of it is engram code that already has six sibling files. As convention, from <code>lang/spec/language.md</code> §18.0 — <em>"these are not four problems, they are one absence, four times"</em>:</p>
<div class="card scroll">
<table>
<thead><tr><th>Concern</th><th>Fragments into</th><th>The convention it became</th></tr></thead>
<tbody>
<tr><td class="f">Process identity</td><td class="m">0 guards</td><td>"check nothing is already running first"</td></tr>
<tr><td class="f">Configuration</td><td class="m">20 env vars</td><td>"remember the right default here"</td></tr>
<tr><td class="f">Durability</td><td class="m">62 sites</td><td>"after you mutate, remember to persist"</td></tr>
<tr><td class="f">Request auth</td><td class="m">10 routes</td><td>"check the token in this handler too"</td></tr>
<tr><td class="f">Index-after-append</td><td class="m">9 of 9 failed</td><td>"after you append, remember to index"</td></tr>
</tbody>
</table>
</div>
<p>The last row is the strongest available evidence about this class of convention: it failed at <b>every single site</b>. A count is what appears where a concept has no home; the size of the count is how far the fragmentation got, not how hard the problem is.</p>
<h2><span class="n">02</span>Geometry is a first-class value — and what follows</h2>
<p class="lede">This is the enabling primitive. Everything else in the architecture is downstream of it.</p>
<p><code>Geometry</code> is an El value, alongside <code>Int</code>, <code>String</code>, <code>List</code>, <code>Map</code> — bound, passed, returned, composed, carrying its own width. Not a library type, not a handle into a store, not a serialization format. <em>Meaning is a value the language computes with directly.</em></p>
<pre><code>let g: Geometry = geometry_new(4)
fn tone_realizer(signal: String) -> Geometry { … }</code></pre>
<p>Landed 2026-08-16 (#141, #144), and the spec is explicit that it belongs to the language rather than the graph: <em>"neither is engram-specific — any program touching any modality needs them; the engram is merely one El program that happens to hold a graph."</em></p>
<p>Five things follow, and together they are the concept-oriented claim made operational:</p>
<h3>A declaration can name a region, not a shape</h3>
<p>If meaning is a value, a name can be bound to a <em>position</em> rather than a struct. <code>cat</code> is not a fixed record; it is a region that resolves against the engram and the surrounding code. <code>cat</code> among animals and <code>cat</code> among shell utilities are different concepts without a namespace, because they are in different neighbourhoods and the distance says so.</p>
<h3>Checking is grounding, not unification</h3>
<p>If a declaration names a region, then verifying a use is asking whether the geometry supports it — a question about position and distance, not about matching a declared shape. This is why §2.3's "a type checker is planned" is likely the wrong name for the missing piece, and naming it wrong would build the wrong thing.</p>
<h3>Dispatch is position, not a tag</h3>
<p>A vtable is a finite set of discrete labels fixed at link time. A region admits graded membership and an open set. So <code>transduce(signal, modality)</code> asks the caller to supply what the signal already carries — what a thing is falls out of where it lands. The modality parameter is a kind-tag, and a registry keyed on it is a lookup table doing by string what geometry does by nearness.</p>
<h3>Types are discovered, not declared</h3>
<p>Reification crystallizes a densely co-wired neighbourhood into a first-class node — the neighbourhood <em>is</em> the name that was missing. Every other family requires a human to see the abstraction in advance and write <code>class Foo</code>. Here the instances arrive and the type falls out, by measurement rather than by insight.</p>
<h3>Enumeration becomes unnecessary</h3>
<p>Five ingest functions differ only in how bytes are acquired — one operation wearing five surfaces. 356 branches in <code>engram_activate_inner</code> are not 356 behaviours. Cyclomatic complexity is a count of the places comprehension ran out and was replaced by an <code>if</code>; where the concept is expressible, the count collapses instead of being redistributed.</p>
<h2><span class="n">03</span>The shape of the language</h2>
<p>Geometry first-class gives El three layers, and it holds all three — which is why there is no separate database driver and no impedance boundary to manage.</p>
<div class="flow">
<div><span class="k">afferent</span><h4>Transduce</h4><p>Signal in, geometry out. Decomposition into components and relations — never conversion to a point. Realizers are ordinary El functions, so a new modality never requires a runtime patch.</p></div>
<div><span class="k">substrate</span><h4>Geometry</h4><p>Meaning as position; relation as distance. Held as values in the language and persisted in the graph. One coordinate system, so entities are commensurable and the operators compose.</p></div>
<div><span class="k">efferent</span><h4>Realize</h4><p><code>plan(frame) → realize(spec, profile)</code>, where a surface <em>is</em> a profile. Text, speech, music, image are profiles of one projection — and so is source code.</p></div>
</div>
<p>The efferent side is why the recursive property below is possible at all: if source is a surface, then emitting a corrected file is projection, and the file becomes an artifact of the geometry rather than the thing you edit.</p>
<h2><span class="n">04</span>Decomposition is by faculty</h2>
<p class="lede">Not by file, module, or subsystem — by what the system does.</p>
<p>Each faculty is a concept. Where it has no home in El it leaks: into C, into a Swift binary, into a shell script with a <code>curl</code> timeout, into a convention nobody performs. State below is measured, not asserted.</p>
<div class="card scroll">
<table>
<thead><tr><th>Faculty</th><th>State</th><th>Measured</th><th>Where it leaked</th></tr></thead>
<tbody>
<tr><td class="f">Ingest <span class="tag">take in</span></td><td class="dead">dead</td><td class="m">2 min → 0 nodes</td><td>separate process uploading bytes over HTTP to a process with direct fs access; five functions where there is one</td></tr>
<tr><td class="f">Recall <span class="tag">remember</span></td><td class="dead">dead</td><td class="m">self ranked 8th</td><td>lexical substring scan; empty on 23 of 24 multi-token queries</td></tr>
<tr><td class="f">Transduce <span class="tag">perceive</span></td><td class="dead">dead</td><td class="m">1 node, 0 edges</td><td>intake flattens signal to a point; <code>realized:false</code>; caller must declare the modality</td></tr>
<tr><td class="f">Think <span class="tag">reason</span></td><td class="dead">dead</td><td class="m">direction [0,0,…]</td><td>null gradient from any anchor and any faculty, byte-identical; confidence at the uninformed prior</td></tr>
<tr><td class="f">Realize <span class="tag">express</span></td><td class="part">partial</td><td class="m">13-word lexicon</td><td>organ was 939 lines of Swift beside the language; voice read from a file path</td></tr>
<tr><td class="f">Body <span class="tag">substrate</span></td><td class="part">partial</td><td class="m">CC 356 / 1,626 ln</td><td><code>engram_activate_inner</code> — recall itself, 356 unexamined paths</td></tr>
<tr><td class="f">Persist <span class="tag">endure</span></td><td class="ok">live</td><td class="m">13,562 / 13,562</td><td>works — every signal placed in geometry at intake, no backlog</td></tr>
</tbody>
</table>
</div>
<h2><span class="n">05</span>The recursive property</h2>
<p>El's compiler is written in El. Every concept the language gains, the compiler can then be written <em>in</em> — so the tool improves the tool, and <code>codegen.el</code> at 4,661 lines gets shorter as the language gets better at expressing what it does. The fixpoint — stage2 ≡ stage3, byte-identical — makes each turn provable rather than hopeful, and the verifier answers in <span class="mono">2.9s</span>.</p>
<p>This sets the ordering criterion, and it is not size of payoff:</p>
<blockquote>Order by leverage on the <em>next</em> iteration. Which concept, added to El, most increases the ability to add the following one?</blockquote>
<p>A small early gain that compounds beats a large one that does not. And it bounds itself correctly — unbounded in depth, bounded in rate, because nothing lands that the compiler and the fixpoint have not passed.</p>
<h2><span class="n">06</span>What has no home yet</h2>
<p>Reserved in the lexer, no parse form. These are not a feature backlog — they are the concepts the architecture above requires and does not yet hold, which is why each is currently a convention or a block of C.</p>
<div class="card scroll">
<table>
<thead><tr><th>Reserved</th><th>Concept</th><th>Currently lives as</th></tr></thead>
<tbody>
<tr><td class="m">retry · times · fallback · reason</td><td>resilience</td><td>a shell script with a 10s <code>curl</code> timeout; 254 restarts in 3 days</td></tr>
<tr><td class="m">requires · deploy · to · via · target</td><td>deployment</td><td>YAML in another repository</td></tr>
<tr><td class="m">sealed</td><td>capability scope</td><td>consent checks written by hand</td></tr>
<tr><td class="m">protocol · impl</td><td>one operation, many realizations</td><td>five ingest functions; eight faculty routes on one builtin</td></tr>
<tr><td class="m">activate · where</td><td>retrieval</td><td>traversals written by hand</td></tr>
<tr><td class="m">test · seed · assert</td><td>verification</td><td>a framework; 5 of 13 native suites failing</td></tr>
<tr><td class="m">parallel · trace</td><td>concurrency</td><td>pthreads in C</td></tr>
</tbody>
</table>
</div>
<p>Plus, from the spec's own status: annotations parsed and skipped, <code>match</code> parsed and emitting nothing, <code>?</code> a no-op, <code>%</code> unlexed, structs as <code>ElMap</code>, enums as strings, selective import unenforced.</p>
<h2><span class="n">07</span>Open</h2>
<div class="q"><b>What does a declaration bind to, exactly?</b><span>If <code>cat</code> names a region that shifts and completes against context, what is written at the declaration site and what is resolved at use? This is the centre and it is unspecified.</span></div>
<div class="q"><b>Is the faculty list right?</b><span>Seven, derived from what broke. Derived-from-failure is a biased sample — it finds what is loud, not what is absent. Which faculty is missing entirely and therefore never failed?</span></div>
<div class="q"><b>Which concept has the highest leverage on the next turn?</b><span>The prologue/epilogue seam (§19.3 names it as the prerequisite; its stated blocker has expired; it collapses 62 + 10 convention sites), <code>protocol</code>/<code>impl</code>, or resolution itself. The §05 criterion should decide this, not preference.</span></div>
<div class="q"><b>What seam makes cognition non-optional?</b><span>"Use the ops" is itself a convention — present every turn, enforced by nothing, ~100% failure across a full session. A stronger instruction is still a convention. What makes reasoning outside the substrate <em>fail</em>, the way <code>@manager</code> makes <code>dharma_emit</code> outside the boundary a compile error rather than a lint?</span></div>
<hr>
<p class="foot">Every number here is measured or quoted from <code>lang/spec/language.md</code>. Nothing is inferred and presented as fact. El is self-hosting: all of this can change and be rebuilt.</p>
</div>