From a curated list to the books on our shelves

2026-06-10T21:08:08Z by Showboat 0.6.1

From a curated list to the books on our shelves

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.

1 · Your lists, in one directory

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.

2 · Opening one list

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)

3 · Giving every title something to match on

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.

4 · The verdict — and where a librarian comes in

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.

5 · What a librarian’s review added up to

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 177every 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.

6 · What a reading group browses

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).

Proof

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

Where this could go

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.