Generated Architecture.md for a real, 2,000+ file
Elixir/Phoenix + React codebase and it read as unprofessional: flat bullet lists, no backend,
frontend, or database decomposition, and the one real diagram an unreadable single row of boxes.
Six increments later, the same command produces real per-language AST decomposition, a real
System Decomposition view, readable diagrams, and real cross-tier edges — all live-verified
against the same real project, nothing mocked. This is the Alpha: shipped and working, honest
about what's still deferred.
EKOS's only two real AST-based decomposition analyzers were for Rust and Python. Elixir — 100% of this project's backend — and JS/TS — its entire frontend — got nothing but a crude declaration-prefix scan: bare symbol name strings, no relationships, no module hierarchy, no KIR objects at all. The one real diagram that did exist (System Context, RFC 0073) had a real, separately-tracked bug: a wide layer rendered as one unreadably long row rather than wrapping.
## Components - File: 1847 - Person: 124 - Table: 15 // flat counts, no // backend/frontend split // at all ## System Context [46 boxes, one row, 8296px wide]
INFO elixir-analyzer complete pass=elixir-analyzer:analytics
files=1231 modules=1355 symbols=4810
No mature Elixir-grammar Rust crate exists — a real, bounded, hand-written
structural scanner instead. defmodule → real
Custom("ElixirModule") objects; def/defp → real Custom("ElixirSymbol") objects, tagged
public/private from the real keyword, not
guessed; alias/import/use/require → real internal module-to-module
DependsOn edges — the actual "restore links and relationships"
deliverable. Spot-checked two known real files directly against the compiled ledger: exact
function lists, exact dependency edges, matching the real source read directly.
Picked oxc_parser over swc_ecma_parser after a real live comparison of both crates' license,
API shape, and maturity — not a coin flip. First live run against the real project found 18 of
291 real files failing to parse: every one a real .js file containing
real JSX (lazy-loader.js's own <div ref={ref}>), which a bare-extension guess doesn't enable JSX for.
Fixed by forcing JSX on for JavaScript, deliberately left off for .ts
(real generic-assertion ambiguity) — parse success went from 93.8% to 99.3%,
re-verified against the same real files, not assumed fixed.
Convention-based classification (.ex/.rs/.py → Backend, .js/.ts/.css →
Frontend, real Table/source_system data →
Database), with a real ekos.toml override escape hatch for when the
convention gets a project's layout wrong — never a silent misclassification with no way out.
This is the direct answer to "which components does it have and how do they relate," the most
directly requested deliverable of the whole effort — this is the literal SVG file the pipeline
writes to disk, embedded here unmodified.
| Before | After |
|---|---|
| 46-node layer, one row, 8296px wide | wraps at 8 nodes/row, 1488×470px |
| no standalone Crate Topology diagram | new crate-topology.svg — 44 real crates, reusing the same SVG renderer unmodified |
| crate w/ no matching rollup: silently vanished | "2 crate(s) have no matching subsystem rollup ... ekos-benchmark, ekos-integration-tests" |
The topological DAG layering itself was already correct — the bug was treating "one DAG layer" and "one visual row" as always the same thing. A purely visual wrap fixed it, verified live against EKOS's own self-dogfooded architecture docs (the real Rust workspace needed to actually exercise a 46-node layer).
use Ecto.Repo, otp_app: :plausible, adapter: Ecto.Adapters.ClickHouse, read_only: true
No new pass — extended elixir_analyzer.rs to read a
real, in-source signal already there. Found a real duplication bug before shipping: this project
declares 5 separate ClickHouse-adapter Repo modules, which would have each
re-pushed a duplicate "ClickHouse" object without extending the existing cross-file dedup — fixed
before it ever reached the ledger. Verified via ekl: all 6 real
ClickHouse-adapter modules and all 3 real Postgres-adapter modules resolve to one real object per
database, no duplicates.
## Plausible.Auth.Password (ElixirModule) ### SameAs - ← PlausibleWeb.Plugins.API.Schemas.Funnel.CreateRequest — confidence=1.00 // a password-hashing module and an // API schema, "the same real thing"?
Picking this exact real module as a deck example surfaced it: `ElixirModule`/
`ElixirSymbol`/`JsModule`/`JsSymbol` (RFC 0081/0085) were never added to the identity resolver's
own documented exclusion list — the identical failure six other object kinds had already hit and
been fixed for. Direct CKM inspection found the real scale: one canonical module
had 1,236 real false `SameAs` edges. Chasing why a first fix attempt didn't change anything
surfaced a second, bigger bug: docs-generated/ was never excluded from
this project's own `[observe] paths` — every build was re-ingesting EKOS's own past output as
real source, feeding old errors back into the pipeline. Fixed both; a full clean rebuild dropped
the ledger from 127,676 contaminated objects to 8,787 real ones, and this exact module's page to
its real 3 relationships, nothing else.
| Real, shipped | Deliberately deferred |
|---|---|
| Elixir backend: modules, functions, real deps | Phoenix role tagging (controller/LiveView/context) — designed, cut over a real dedup-ordering risk |
| JS/TS frontend: modules, symbols, 99.3% parse rate | Relative import resolution (./Dashboard → its real file) |
| Real Backend/Frontend/Database decomposition view | Per-table precision on cross-tier edges (adapter-level today, not per-table) |
| Readable diagrams, real Crate Topology SVG | Frontend → Backend edges — explicitly lower-confidence, never attempted |
| Real Backend → Database edges (Ecto adapters) | 2/291 real TS files still fail under the pinned oxc_parser 0.133.0 |
| Identity resolver exclusion list, self-referential docs ingestion — both fixed | Residual fuzzy `SameAs` candidates (Document/Technology/Pipeline) — RFC 0060's own already-tracked territory |
Nothing in the right column is a bug hidden from this deck — every one is named, scoped, and reasoned about in its own RFC or devlog. That's the actual meaning of "Alpha" here: real, live-verified, evidence-backed work, with a real, honest map of what comes next.
$ git clone https://github.com/plausible/analytics $ cd analytics && ekos init $ ekos build && ekos recover && ekos resolve && ekos compile && ekos commit $ ekos docs generate --layout curated $ open docs-generated/Architecture.md
| Full workspace gate | Result |
|---|---|
cargo build/test/clippy -D warnings/fmt --check | Clean, every increment |
| New tests this effort | 60+ new tests across 6 RFCs, each built from real fixtures or a real bug found live |