A user asked EKOS to research analytics/ — a real,
unmodified clone of Plausible Analytics, a production Elixir/Phoenix app — and document its
ClickHouse component. The compiler pipeline had never touched this codebase before. It compiled
git history, CI/CD, and dependencies cleanly — and on the one file that actually mattered,
ClickHouse's own DDL, it hit a wall that had nothing to do with this session's config. Every
screen on this page is real terminal output, unedited, including the failures.
$ ekos init Initialized .ekos/ workspace at /home/legion/PycharmProjects/analytics/.ekos $ ekos build Build complete. Files observed (new): 2022 Total objects in ledger: 2022 Connectors re-scanned: 6
Plausible keeps two Ecto repos: Postgres for app/billing state, ClickHouse for the raw
event firehose. RFC 0031's [[recover.sql.dialect-rules]] routes
priv/ingest_repo/** to the clickhouse
dialect and priv/repo/** to postgres —
no code change, just three lines of config pointed at a repo EKOS had zero prior knowledge of.
WARN unknown dialect "clickhouse" configured for
priv/ingest_repo/structure.sql; falling back to generic
WARN sqlparser failed on priv/ingest_repo/structure.sql:
sql parser error: Expected: ',' or ')' after column
definition, found: CODEC at Line: 7, Column: 23;
falling back to empty graph
target/release/ekos on disk predated RFC 0056's
ClickHouse dialect registration — cargo build --release -p ekos against
current main fixed the "unknown dialect" warning in under 30 seconds.
The second warning, the actual parse failure, didn't move.
sqlparser itself doesn't know CODEC.INFO running pass pass=sql-analyzer:priv/ingest_repo/structure.sql
WARN sqlparser failed on priv/ingest_repo/structure.sql:
sql parser error: Expected: ',' or ')' after column
definition, found: CODEC at Line: 7, Column: 23;
falling back to empty graph
"unknown dialect" is gone — proof the fix in §02 worked. The CODEC error is
identical, down to the line and column: `timestamp` DateTime
CODEC(Delta(4), LZ4), line 7 of the real schema. That isolates the fault to
sqlparser::dialect::ClickHouseDialect's own column-option grammar —
it recognizes MATERIALIZED/ALIAS/EPHEMERAL as ClickHouse column options, but CODEC
was never added.
Git history, CI/CD (14 GitHub Actions pipelines),
local docs, and the dependency graph all recovered cleanly — the CODEC gap only cost the one
thing that needed real ClickHouse DDL grammar: structured Table/Column objects for the event-store schema itself.
$ ekos query find "clickhouse" 50 result(s) for 'clickhouse': lib/plausible/clickhouse_repo.ex lib/plausible/clickhouse_event_v2.ex lib/plausible/stats/clickhouse.ex lib/workers/clickhouse_clean_sites.ex ... 46 more — files, migrations, docs, CI $ ekos query find "sessions_v2" 30 result(s) — every migration & data-migration file. Zero ObjectKind::Table objects.
Every Elixir module, migration, and doc that mentions ClickHouse is a real compiled object with real git evidence. What's missing is the one thing a database doc actually needs first: the tables themselves.
Git/CI/dependency facts came from the ledger,
queryable and evidenced. Every schema claim — engines, partition keys, the write-buffer flush
logic, the staged data-migration framework — came from a background research pass reading
structure.sql and the Elixir source directly, because the ledger
had nothing structural to hand it for ClickHouse. The delivered doc says which is which,
in its own words, not after the fact.
18 tables & dictionaries, fully specced 4 Ecto repos → 1 ClickHouse cluster Write path: buffer, flush, RowBinary Read path: query-builder pipeline 6 staged data-migration case studies 54-migration schema-evolution timeline
Every engine/partition/order-key claim in the doc was read straight from priv/ingest_repo/structure.sql and the migration files — and the doc
says so, in a callout naming this exact CODEC gap, so a reader knows which facts are
ledger-grounded and which are a direct read standing in for it.
[[recover.sql.dialect-rules]] at any file-based ClickHouse DDL.# route ClickHouse-only paths to the clickhouse dialect, # everything else stays on generic/ANSI [[recover.sql.dialect-rules]] path-glob = "priv/ingest_repo/**" dialect = "clickhouse" $ ekos build && ekos recover