data.adamthede.com A record of the reading practice

What I meant to read

Saved, never read
492

395 sitting in the unread queue, 97 filed into folders and never opened. Twenty of them he thought enough of to star.

Years spanned
16
2011 to 2026. Nothing at all was saved in 2021.
Words recovered
1,086,902
Across the 466 whose text came back. A median of 1,479 each.
Oldest save
27 Jan 2011
Still in the queue after fifteen years and seven months.
Sources
218
Distinct hosts. 170 of them appear exactly once.
How the text was recovered
Stored copy 353
Wayback snapshot 90
Direct fetch 23
No text anywhere 26
The backlog, by the year it was saved
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
Cover. Counts and years from 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.
Plate 01

Half the backlog was saved between 2016 and 2019, a four-year band that produced 12 percent of everything he finished.

262 of 492 unread · 812 of 6,769 read

■ Unread, share of 492 ■ Read, share of 6,769
2010 0 269
2011 52 360
2012 7 1,502
2013 14 854
2014 31 1,096
2015 12 372
2016 53 237
2017 57 133
2018 101 237
2019 51 205
2020 15 194
2021 0 13
2022 1 150
2023 19 378
2024 7 215
2025 32 391
2026 40 163

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.

Read the note

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.

Plate 01. Unread counts: 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.
Plate 02

Ruby on Rails is ten times heavier in what he saved than in what he read. Technology he read more than he saved.

Share of each corpus's topic mentions · 2,076 unread, 26,912 read

■ Unread ■ Read Chip = how many times heavier in the unread pile
Software Development 6.1× 1.40% 0.23%
Ruby on Rails 10.2× 1.06% 0.10%
Personal Development 2.5× 0.96% 0.38%
Artificial Intelligence 1.4× 0.87% 0.61%
Innovation 2.1× 0.87% 0.41%
Entrepreneurship 0.9× 0.77% 0.88%
Web Development 8.8× 0.72% 0.08%
Self-Improvement 4.6× 0.58% 0.13%
Technology 0.6× 0.58% 0.99%
Business Strategy 1.0× 0.53% 0.51%
Social Media 0.2× 0.10% 0.55%
Venture Capital 0.4× 0.19% 0.44%
The unread summaries were generated from full article bodies; the read corpus's were generated under a 10,000-character cap, which 28 of 79 sampled bodies exceed. The unread side therefore saw more of each article than the read side did, and a topic present on one and absent on the other may be a difference in how much text the model read rather than a difference in what was saved. Topic density is close: 4.47 topics per unread article against 3.98 per read one.
Read the note

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

Plate 02. 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%.
Plate 03

A model was asked why each piece was saved. It answered for 461 of 492, and judged 82 of them past their moment.

Inference, not record · every figure on this plate is a machine's guess

What the inference produced
Counted 461
Excluded, low confidence 21
Declined to infer 10
How sure it said it was
High 371
Medium 90
Low 31
Judged aged out
82
of the 464 it could read. 17.7 percent.
Could not be judged
28
Text the guard flagged as not an article.
Still worth the time
382
Qualify for a shortlist that stays private.
What this plate cannot show There is no taxonomy of reasons. The model returns one sentence per article, and a sentence about an unread article is an item-level string, so it does not ship. What is publishable is how often it answered and how sure it said it was. The reasons themselves live on the private side of the record.
Read the method

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.

Plate 03. 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.
Plate 04

218 hosts feed the backlog, and one newspaper is 17 percent of it.

Top ten hosts are 45 percent · 170 hosts appear exactly once

nytimes.com 84
medium.com 50
x.com 16
blakemasters.com 14
businessinsider.com 14
brainpickings.org 12
theatlantic.com 8
theguardian.com 8
newyorker.com 7
fastcodesign.com 6
medium.freecodecamp.org 6
en.wikipedia.org 5
tennessean.com 5
Distinct hosts
218
Across 492 saves.
Top host's share
17.1%
One newspaper, 84 items.
Seen once only
170
78 percent of the hosts.
Read the note

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.

Plate 04. 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.
Plate 05

Text came back for 466 of the 492, and three quarters of it came from a copy stored at the moment of saving rather than from the web.

Which leg of the fetch chain produced the text · not a measure of what is still live

Instapaper's stored copy 353
Wayback snapshot 90
Direct fetch 23
No text anywhere 26
Stated exactly as the data supports it This is which leg of the fetch chain produced the text, not whether the URL is still live. The chain short-circuits: the direct fetch runs only where Instapaper held no stored text, so every item Instapaper resolved was never probed against its own URL at all. A live-web survival figure needs a separate probe of all 492 and is not reported here. For scale, a 100-item sample measured while planning this record found 51 URLs still serving their own article. This chain cannot reproduce that number and does not try.
Read the note

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.

Plate 05. 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.
Plate 06 · Matter only

The current reading queue grew from 431 to 510 across three years while reading ran at about three articles a week.

A second, live backlog · the one above is the Instapaper era, this one is now

12 May 2023
431
Queue at the export. 941,221 words.
16 Sep 2026
510
Queue today. 1,306,734 words. 64 started and set down.
Saves per week
—
Not measured. The ledger has no inflow column yet.
Articles read per week, last 52 weeks
2025-W39peak 272026-W38
Reads, last 52 weeks
178
3.4 a week.
Reads, last 13 weeks
104
8.0 a week. The rate more than doubled.
Net queue growth
+0.45
Items a week, across 174.7 weeks.
When this plate becomes readable Two points is a line, not a trend. The nightly snapshot that records queue size, inflow and outflow shipped on 16 September 2026 and is not yet installed. The first measured inflow and outflow pair arrives on the second night after it runs, a four-week average becomes meaningful at about week five, and the saves-versus-reads crossing this plate is really asking about needs roughly eight weeks of nights. Until then the queue line is drawn between the only two observations that exist, and the saves-per-week figure is left blank rather than reconstructed from them.
Read the note

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.

Plate 06. Queue endpoints and weekly reads: 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.