2026-06-10T21:08:08Z by Showboat 0.6.1
Hand us a reading list — the books your group is reading — and it becomes a named, browsable entry in the library’s catalog-match directory: who curated it, how many titles, and the one number that matters — how many we already own. This walkthrough opens with that directory, then follows three real books under the hood to show how each title is lined up against our shelves. The machine matches what it can be sure of; the ones it isn’t sure of, a librarian reviews — and that human step is the whole story. The honest result: of one award’s 177 titles, we own 169.
Public bibliographic data only · this reads frozen snapshots, never live systems · a discovery surface with no patron data.
Every list we take in — whether a librarian hand-authors it or we pull it from an award like the Newbery — becomes a first-class entry here: named, attributed to whoever curated it, and measured by how much of it we already hold. This is where your list would land.
uv run python docs/demos/_driver.py directory
Beat 1 — your lists: named, attributed, and how much of each we own
───────────────────────────────────────────────────────────────────
list curator entries owned gap pct owned
----------------------------------------------------------------------------
Sample Newbery Starter reading-lists demo 3 3 0 100%
Newbery Honor — (pulled from award) 70 62 8 88.6%
Newbery Medal — (pulled from award) 104 104 0 100%
'Sample Newbery Starter' is a HAND-AUTHORED list — attributed to its curator,
and we own all three titles. The Newbery lists are PULLED from an award, so they
carry no personal curator (an honest blank, never a fabricated name). Hand us your
list and it lands here the same way: named, with your name on it, and the share we
already own. 'owned' is the number that matters. Next we open one up to see how
that number is built — and why a person is part of it.
Let’s open one of those entries — the Newbery Medal and Honor winners — and watch exactly how those “owned” numbers are built. Three of these books are our guides: one the machine matches outright, and two famous ones it can’t be sure of on its own.
uv run python docs/demos/_driver.py list
Beat 2 — going deep on one list: the Newbery winners (174 entries)
──────────────────────────────────────────────────────────────────
by award class:
honor 70
medal 104
the three titles we'll follow:
Bud, Not Buddy Christopher Paul Curtis (medal)
Crispin: The Cross of Lead Avi (medal)
The Giver Lois Lowry (medal)
Before we can match a title, we normalize its identifiers. Watch the real registry run: it cleans and cross-derives ISBNs (a 10-digit ISBN implies its 13-digit twin) and — crucially — synthesizes a title-and-author match that doesn’t care about author order, so a book that arrives with no ISBN at all still has a handle to match on. Notice The Giver carries four editions’ worth of ISBNs — hold that thought.
uv run python docs/demos/_driver.py normalize
Beat 3 — one title's identifiers, normalized by the real registry
─────────────────────────────────────────────────────────────────
The Giver (Lois Lowry)
harvested: 9 raw id(s) -> normalized: 10 (incl. derived + a title-author match)
wikidata Q258953 -> —
isbn13 978-0-395-64566-6 -> 9780395645666
isbn10 0395645662 -> 0395645662
isbn13 978-0-440-90079-5 -> 9780440900795
isbn10 0440900794 -> 0440900794
isbn13 978-1-4420-1496-1 -> 9781442014961
isbn10 1442014962 -> 1442014962
isbn13 978-2-211-02166-1 -> 9782211021661
isbn10 2211021662 -> 2211021662
title_author The Giver|Lois Lowry -> giver|lois lowry
Crispin: The Cross of Lead (Avi)
harvested: 1 raw id(s) -> normalized: 2 (incl. derived + a title-author match)
wikidata Q5186028 -> —
title_author Crispin: The Cross of Lead|Avi -> crispin the cross of lead|avi
ISBN-10/13 cross-derive each other; a title-and-author match is built (author
order doesn't matter — 'Lois Lowry' and 'Lowry, Lois' come out the same) so even
Crispin — which arrives with NO ISBN — still has something to match on.
Now the match. Bud, Not Buddy shares an ISBN with a record on our shelves — the machine is confident, no human needed. But The Giver and Crispin have no ISBN our catalog shares (we hold different editions). Their title-and-author match still finds candidates — but several of them, too many to guess. So instead of faking a match, the system hands them to a librarian, who confirms the right one. That accepted verdict is what turns an uncertain match into an owned book.
uv run python docs/demos/_driver.py match
Beat 4 — the verdict, and where a librarian comes in
────────────────────────────────────────────────────
title record matched on librarian confidence
----------------------------------------------------------------------------
Bud, Not Buddy 1946139 ISBN — confident
Bud, Not Buddy 2545365 title+author — review
Bud, Not Buddy 3597993 title+author — review
Crispin: The Cross of Lead 1819030 title+author accepted adjudicated
Crispin: The Cross of Lead 1912048 title+author — review
The Giver 1422981 title+author accepted adjudicated
The Giver 1481826 title+author — review
The Giver 2545319 title+author — review
The Giver 3419362 title+author — review
The Giver 3706384 title+author — review
Bud matched on a shared ISBN — the machine is CONFIDENT, no human needed (its two
weaker title/author candidates are ignored). The Giver and Crispin had no ISBN our
catalog shares, so the title/author bridge surfaced SEVERAL possible records — too
many to guess. Rather than fake a match, the system handed them to a librarian, who
ACCEPTED the right one. A human verdict promotes 'review' -> 'adjudicated'; it never
relabels a machine-confident match. The other candidates simply stay un-chosen.
Here is the payoff. On its own, the machine could be confident about only 34 of the 177 titles — exact-identifier matches. The rest were either uncertain or looked absent. Then a librarian spent an afternoon reviewing the uncertain ones. The result: we own 169 of 177 — every Newbery Medal winner (100%) and 88.6% of the Honor books. The Giver — a gap to the machine — became an owned book the moment a person confirmed it. And the handful we don’t own becomes a tidy acquisition list.
uv run python docs/demos/_driver.py adjudicate
Beat 5 — what a librarian's review added up to
──────────────────────────────────────────────
Before any human looked, the machine could confidently own 34 of 177
(exact-identifier matches only).
After a librarian reviewed the uncertain ones, we own 169 of 177.
list owned of share
--------------------------------------------
Newbery Medal 104 104 100%
Newbery Honor 62 70 88.6%
Sample Newbery Starter 3 3 100%
The Giver was one of the uncertain ones: no edition we hold shares its ISBNs, but
the title/author bridge surfaced five possible records — too many to guess. A
librarian confirmed the right one. Its journey: gap -> reviewed -> owned.
The 8 titles we still don't own are a tidy acquisition list — all obscure
early Newbery Honor titles, several long out of print:
[honor] Garram the Hunter, A Boy of the Hill Tribes — Herbert Best
[honor] Little Blacknose — Hildegarde Hoyt Swift
[honor] Mountains Are Free — Julia Davis Adams
[honor] Ood-le-uk the Wanderer — Alice Alison Lide; Margaret Alison Johansen
[honor] Pran of Albania — Elizabeth Cleveland Miller
[honor] Queer Person — Ralph Hubbard
[honor] The Dark Star of Itza, The Story of A Pagan Princess — Alida Malkus
[honor] The Fairy Circus — Dorothy P. Lathrop
We name exactly what we're missing; we never fake a match we don't have.
All of this lands in a small, browsable Datasette — a point-and-click data browser. It answers the three questions a reading group actually asks: what do we own (whether the machine was sure or a librarian confirmed it), what’s a gap worth acquiring, and what’s still waiting on a human — now that a librarian has cleared the queue, nothing.
uv run python docs/demos/_driver.py browse
Beat 6 — what a reading group browses (the live Datasette)
──────────────────────────────────────────────────────────
• Owned — the machine's confident matches and the librarian's confirmations
sit side by side; a reader can't tell (and needn't care) which is which:
[medal] ...And Now Miguel — Joseph Krumgold (adjudicated)
[honor] 26 Fairmount Avenue — Tomie dePaola (confident)
[medal] A Gathering of Days — Joan Blos (confident)
[honor] A Girl Named Disaster — Nancy Farmer (adjudicated)
[medal] A Single Shard — Linda Sue Park (confident)
[honor] A Snake Falls to Earth — Darcie Little Badger (confident)
…
• Gaps — the acquisition list from the last step is its own browsable view.
• Review queue — uncertain matches still awaiting a human: 0 (a librarian cleared it).
Every command above is reproducible (showboat verify
re-runs and diffs them), and the identifier registry that powers the
matching ships green.
uv run pytest tests/lists tests/demos/test_reading_lists_demo.py -q 2>&1 | sed -E 's/ in [0-9.]+s//'............................................................... [100%]
63 passed
Today this is a discovery surface — no patron data, nothing private. But picture the next step, posed as open questions, not commitments:
None of that is built or designed. It would touch real patron data, so it stays behind the records-officer and counsel conversation — and it would lean on the privacy-first design we’re building for patron data, which connects a person’s activity without ever storing who they are.
From a curated list to the books on our shelves — the machine matches what it can, a librarian confirms the rest, and we never fake a match we don’t have.
← all walkthroughs · Rendered from 226199c on 2026-06-18 · showboat verify: reproduces. A living artifact — the version ledger is git.