The other archive. Every item here is a recorded intention: on one particular day it was worth his time, and the time never came. 492 of them, saved between 27 January 2011 and 12 April 2026, still unread on 17 September 2026.
395 sitting in the unread queue, 97 filed into folders and never opened. Twenty of them he thought enough of to star.
public_data.json, built by
scripts/unread/public.py → public_shape() over
data/unread_enriched.jsonl (492 rows, gitignored).
Word total, save span and star count are payload fields
(words, saved_span, starred),
computed from body_words, saved_date and
starred on the same rows.
Bars scaled to 2018 = 101.
262 of 492 unread · 812 of 6,769 read
Both series are drawn as a share of their own corpus on one shared scale, so a long bar means "a big slice of that pile", not "a lot of articles". 2012 is 22 percent of everything he read and 1 percent of what he did not.
The two curves are close to inverses of each other. The years that fill the read archive, 2012 through 2014, left almost nothing behind: seven unread items survive from 2012 against 1,502 finished. The years that fill the backlog, 2016 through 2019, are the years the reading nearly stopped.
2018 is the peak of the queue and it has not moved. The May 2025 export counted 101 unread items saved in 2018; there are 101 today.
The oldest strata behave differently, and the split is exact. All 73 items saved in 2011, 2012 and 2013 sit in folders. Not one of them is in the queue, and the queue holds nothing at all from before 2014. That is two different acts wearing the same label: the queue is where things were dropped, the folders are where things were sorted, named and shelved. The sorted ones are the ones that survived fifteen years unread.
public_data.json →
by_saved_year, from scripts/unread/analysis.py
→ by_saved_year().
Read counts: public_data.json →
read_comparison.by_year, from
analysis.read_corpus_by_year() over
data/archive_index.parquet, rows whose source is in
analysis.READ_IT_LATER_SOURCES (instapaper, matter), grouped
on date_saved —
6,769 of the index's 17,320 rows. The other
10,551 are the legacy document archive and were never saved with an
intention to read later, so they are not the comparison.
Bars scaled to 23 percent.
Share of each corpus's topic mentions · 2,076 unread, 26,912 read
The backlog is a technical education he kept buying and never took. Software Development, Ruby on Rails and Web Development together are 3.2 percent of everything he saved and 0.4 percent of everything he read, an almost eight-fold difference that no amount of enrichment asymmetry explains.
What he actually read is broader and softer: Technology, Entrepreneurship, Social Media, Venture Capital. Social Media is 147 mentions in the read corpus and two in the queue. The pattern is not "he saved hard things and read easy ones" so much as "he saved the things he meant to become, and read the things he was already following".
public_data.json →
topic_comparison, from scripts/unread/analysis.py
→ topic_comparison(): the top 10 subjects of the
unread pile, plus the two the read corpus carries most heavily that
are not already among them, paired at the data layer rather than on this
page. Those two are the bottom two rows, and they are in the saved
pile too, thinly — the plate draws what they are, not zero.
Unread topics come from the 464 rows the prompt's own
CONTENT_VALID guard did not reject; read topics from
analysis.read_corpus_topics() over
data/archive_index.parquet, read-it-later sources only.
Shares are of each corpus's total topic mentions, so the two are comparable
without a per-item denominator. Caveat text is analysis.COMPARISON_CAVEAT,
published verbatim in the payload.
One topic was withheld from the published list by
public.drop_title_shaped() because the string is also the title
of an article in this corpus; the title stays a leak needle. The same
redaction runs over the read column, against both corpora's titles.
Bars scaled to 1.40%.
Inference, not record · every figure on this plate is a machine's guess
Two fields were deliberately not asked of the model. The abandonment band is arithmetic on read progress, and the topic drift is a corpus computation. Asking a model for either would have produced a plausible number that nothing could check.
The two that were asked, why it was saved and whether it has aged out, are genuinely inferential, and both carry guards. The reason may come back empty, and an empty answer is treated as a result rather than a failure: it happened ten times. The model sets its own confidence, and the 21 rows it marked low are excluded from every aggregate on this page. Aged-out is judged only on rows whose text passed the content check, which is why the denominator is 464 and not 492.
The shortlist is ranked on the enrichment rather than on a fresh model pass, so every part of the ranking traces to a stored field. 382 pieces qualify. The ranked list is published privately, where titles are allowed and the ranking can be judged; the public record gets the count.
public_data.json → why_saved
(carrying kind: "inference" in the payload itself) and
still_worth_your_time, from
scripts/unread/analysis.py → why_saved_summary()
and shortlist_eligible_count().
Aged-out and unknown: public_data.json →
aging_curve, summed across years
(analysis.aging_curve()).
The confidence split is why_saved.by_confidence
(analysis.confidence_split()), and it counts every row in the
corpus rather than only the rows that carried a sentence: the 31 graded low
are the 21 excluded plus the 10 the model then declined to answer.
Model: gemini-2.5-flash-lite, full bodies, no character cap.
Top ten hosts are 45 percent · 170 hosts appear exactly once
Hosts ship and article addresses do not. A host is a fact about the archive; a path identifies one article in it, and the whole point of this record is that the articles stay unnamed.
The concentration is the finding. Two hosts are more than a quarter of the queue, and they are also the two hardest to fetch: both bot-block a plain request, which is why the recovery on the cover leans so heavily on the copy Instapaper stored at the moment of saving. The long tail is the other half of the story. 170 hosts contributed exactly one thing he meant to read and never came back to.
public_data.json → by_domain
(top 60 published), distinct_domains and
domain_concentration, from
scripts/unread/analysis.py → by_domain() and
scripts/unread/public.py → _concentration().
Bars scaled to 84.
Which leg of the fetch chain produced the text · not a measure of what is still live
The 26 that resolved nowhere are the only items on this page that can be called lost, and even they are not evenly lost. Four were saved in 2011 and seven in 2025: the old ones died of age, the recent ones are paywalls, JavaScript shells and rate limits. Different failure, same outcome.
Two of them were saved as archive links, to services that now rate-limit the request. The hedge against link rot rotted.
The 26 still count as intentions. They are enriched from their title and description alone, flagged as such, and they appear in every year, host and abandonment figure on this page. They simply carry no topics, which is why the topic plate's denominator is smaller than 492.
public_data.json → survival
and dead_fraction_by_year, from
scripts/unread/analysis.py → survival(). The
unknown-liveness paragraph is analysis.SURVIVAL_NOTE, which the
payload publishes verbatim alongside liveness_measured: false.
The 51-of-100 sample is
docs/2026-09-15-unread-corpus-resolve-rate.md.
Bars scaled to 353.
A second, live backlog · the one above is the Instapaper era, this one is now
The reading rate more than doubled in the last quarter, from about three articles a week to eight, and the queue still grew. That is the whole argument for measuring inflow separately: a backlog that grows while reading accelerates is a saving problem, not a reading problem, and nothing on this page can yet prove which it is.
The two endpoints are not the same kind of measurement. The 2023 figure is counted from an export, filtered to rows marked saved and not read. The 2026 figure is a live count of everything in the queue status. They agree on definition and differ on instrument, which is the usual reason a long-run series has a seam in it.
data/records/meant-to-read/matter_queue.json, vendored from
scripts/matter/queue_snapshot.py in the Article Archive
repository (SEED_2023_DATE = "2023-05-12",
seed_2023() over the May 2023 export, and the live snapshot run
recorded on pull request 27). Its ledger,
data/matter/queue_daily.csv and
data/matter/queue_snapshots.jsonl, does not exist yet: the
launchd job launchd/com.thedetech.article-sync.matter-queue.plist
is shipped and not installed.
Weekly reads: queue_snapshot.compute_weekly_reads() over
derive_date_read() on data/archive_index.parquet,
filtered to source == "matter" (292 rows) so the plate is
Matter-only on both sides. The bundled
--backfill-reads writes an archive-wide series, which would have
mixed the Instapaper era into a Matter plate.
Sparkline scaled to 27.