CHPL Lake

the boring parts
a datalake for our specific public library institution

QR code linking to https://rayvoelker.github.io/2026-08/our-own-copy/
rayvoelker.github.io
/2026-08/our-own-copy/

Our Lake, Our Governance

  1. The shape of a lakehouse architecture
  2. The shape of our lake (and how faithfully we follow it)
  3. Examples and what it has answered

Please hold all big questions for the examples / showcase at the end.

A lakekeeps everything as it arrived. A warehousekeeps it tidied up. A lakehousewants both.

So what’s it actually supposed to give you?

The shape of a lakehouse architecture

Six common patterns around data lakes

  1. Land data raw / medallion architecture: bronze is append-only. Silver and gold are for transformations and report consumers.
  2. Open data formats: the Parquet file format — a non-proprietary storage container that allows fast reads, compact storage, and flexibility in what is stored and how that data is described.
  3. Cheap: storage and computing decoupled. Runs on a single machine or many — it scales easily, on few resources.

The shape of a lakehouse architecture (cont.)

The other three are about what it gives back.

  1. It remembers: every version of every record, as of any date you like.
  2. One copy, many uses: everything reads the same files.
  3. New sources land easily: no rebuild to add the next one.

(Typically sold alongside these: live streaming data, and machine-learning features.)

The system forgets. The lake remembers.

It updates records in place, and vendors do not keep the past for us.

  • Records change in place: transit legs, item status and location, the card numbers behind e-resource use. The new value overwrites the old, and nothing wrote down that it changed.
  • Many small sources, not one firehose — all of it on a single server.
  • No subscription, no license — the running cost is close to zero.
  • Strong data protection — the data never leaves our control unless we send it.

What we took, what we skipped, what we added

  • Took, faithfully: land raw data, remember every version, add new sources cheaply.
  • Took by being small: one machine we already own.
  • Declined on purpose: warehouse-scale, many engines, streaming, a place to train models later.
  • Added: privacy, which is not on their list and is a very big point of ours.

What we kept is what matters here: it remembers, and it protects.

Everything so far was what we chose.

Now: what it actually is.

What it costs, and who owns it

  • It runs on one machine we already own. There is no cloud bill for the data, and it is easier to secure and monitor.
  • The files are a plain, open format. Any tool can read them — there is no vendor to leave, because there is no vendor.
  • 215 GB today, across 24 registered sources, each one reporting what it did, every run.
  • Encrypted at rest, backed up for disaster recovery, and destroyable on purpose — part of the design, not bolted on.

What is actually in each layer

Three stages, and the same rule at every step: never edit what came before.

BRONZE · raw
exactly what we were handed, encrypted, never edited
  • every item record, versioned
  • 47.2 million circulation transactions
  • 2.09 million catalog records
  • staff work locations, daily
SILVER · readable
no borrower attached — nothing personal leaves by accident
  • items, with no patron attached
  • transit notes parsed into from, to, and when
  • branches and item types, kept current
GOLD · finished
the answers themselves — rebuilt on a schedule, never hand-edited
  • last copies, by branch
  • the transit backlog — 3,829 items surfaced a month
  • collection pressure by location

Bronze is captured hourly to daily; silver and gold rebuild overnight. Every run reports what it did — and this morning they all ran.

You can always walk backwards.

It remembers, and it protects.

The raw copy is encrypted; the readable copy has no borrower attached.

v1 v2 BRONZE · KEPT FOREVER item.records_full item_id · observed_at ciphertext [BLOB] └─ the whole Sierra item ├─ bibIds · [79] Location ├─ status.code · barcode ├─ [66] Patron No. ├─ [67] Last Patron ├─ [78] Last Checkout └─ varField m (transit) … +8 more columns v3 decrypt · drop the personal details item_id + observed_at carried forward SILVER item.records item_id · observed_at bib_id · location_code status_code … +8 more SILVER item.transit item_id · observed_at transit_to_loc transit_from_login transit_from_class … +4 more the last-copy question reads this the transit question reads this

A transit note is written by a person. The readable copy keeps their login; the published answer keeps a place, not a person.

The reason it does not rot

The standing failure of these projects is a pile nobody trusts.

  • Every run reports what it did — what it read, what it wrote, and whether it actually worked.
  • Every source passes the same checks before it is allowed to run at all.
  • A test that always passes is not a test. Ours can fail — and sometimes do.

The least interesting part of the system, and the reason the rest of it is still true in three years.

You were asked to hold your questions.

Now is the time.

Everything after this is something it has already answered.

What it has answered

All of these are real, all of them are dated, and most of them are from the last few weeks. Pick one and we will open it.

  • Delhi Township closes Aug 29. 751 titles where that branch holds every active copy — 733 of them the only physical item we own.
  • Northern Kentucky borrowing ends Jan 3. Roughly 10,363 cardholders to reach — and we found out early that Sierra alone cannot cleanly identify them.
  • Temporary cards. 5,276 on file; 2,394 already past expiry. Whether they convert or get abandoned becomes measurable in September.
  • Items stuck in transit. 3,829 surfaced a month, with a printable pull sheet for each branch.
  • Loan rules vs. published policy. Where what we tell the public and what the system does disagree.
  • Collection pressure by location. Which shelves are carrying more than their share. Which shelves are bare.
  • Reading lists on the public web. Live, rebuilt nightly.
  • Vendor delivery verification. Proving a file actually arrived when no log survived to say so.
  • Holdings maintenance. With OCLC, moving from manual to scheduled.

Every one of these is the same machinery, pointed at a different question.

Choose Boring Technology

Almost nothing in here is new — and that is the achievement. “Let’s say every company gets about three innovation tokens. You can spend these however you want, but the supply is fixed for a long while.” Dan McKinley, Choose Boring Technology (2015)
mcfunley.com/choose-boring-technology
Everything here is ordinary, durable technology, pointed at questions that are ours.

Ray Voelker
ray.voelker@chpl.org

What we built on

Oldest first. Every date is a public fact you can check.

What it is Since Where it stands
Debian — the operating system 1993 · 33 years we run 12 “bookworm”; security support to June 2028
Postgres — the database 1996 · 30 years #1 database; 55.6% of professional developers
systemd — starts things on a schedule 2010 · 16 years the default on every major Linux
Parquet — the file format 2013 · Apache 2015 the interchange default
Datasette — the data browser 2017 still 1.0-alpha, and we run it in production on purpose
Podman — runs things in containers 2018 · Quadlet 2023 ships natively in Red Hat 9.1 and 10
dbt — the transformation tool Dec 2021 the de-facto standard
DuckDB — the query engine June 2024 ◀ the one bet
DuckLake — the table format April 2026 ◀ the one bet · v1.1 due Sept 2026

Three of these are younger than the problem they solve — DuckLake, Quadlet and Datasette. That is the bet, named.