Skip to content
NissanBossPublic

About

How many people you could still be: reads what an account has said about itself, applies every fact to the real population it describes, and says how many people still fit all of it. Calibrated against the US census, and the figures are in the README.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lineup

How many people you could still be.

A lineup, at a police station, is a row of people who all fit the description, and a witness has to pick one out. Every post an account writes adds a line to the description.

    [LINEUP ] About 150 people fit everything this account has said
             somewhere between 42 and 510

             everyone alive                                8,200,000,000
             lives in a city of 540,000                          540,000
             gave an age                                          14,000
             gave a job                                              250
             gave a relationship status                              150

    [COSTS  ] What cost the most, and where it was said
             lives in a city of 540,000                  divides by 15,000
               1 post says it, first comments.csv row 3, 2024-01-05

             gave a job                                  divides by 57
               2 posts say it, first comments.csv row 6, 2023-09-01

That is five sentences out of 1,284 comments: a city, an age, a job said twice and a husband. None of them is personal on its own.

The problem

Nobody gives themselves away in one post. They give away a city in one, an age in another, a job and a daughter's birthday in a third, and each of those is harmless by itself and a filter when somebody puts them together.

The arithmetic is old. In 2000, Latanya Sweeney showed that a postcode, a date of birth and a sex are enough to single out 87% of Americans. What changed is the cost of putting the pieces together. In February 2026, a paper by Lermen, Paleka, Swanson, Aerni, Carlini and Tramèr had language model agents read pseudonymous accounts, pull out facts like these, search for who fits them and check the answer. They named two accounts in three, right nine times in ten, for one to four dollars an account.

Deanonymising somebody used to take a person an afternoon. It now takes a script a few seconds, and it can be pointed at everybody.

What already exists

Almost all of it is on the other side.

Beyond Memorization and the February 2026 paper are the attacks, published as research. Sherlock and Maigret find where else a username has been used, which is the first thing anybody hunting an account does.

On the defending side, Presidio and the tools like it find names, addresses and phone numbers: the things that identify somebody by themselves. None of them looks at the things that only identify somebody in combination, which are the ones people post freely. A 2024 paper by Dou and colleagues trained a model to spot those in a single post and soften them, which is the closest thing to this, and it works one post at a time and never says how exposed the account is as a whole. EFF's Cover Your Tracks does exactly that kind of counting for a browser's fingerprint, in bits. Nothing does it for what you have said.

Lineup is the attacker's arithmetic, done for the person who owns the account, before anybody else does it.

How it counts

It reads an account the way it was published. Point it at the archive Reddit, X or Mastodon hands over, at Hacker News comments saved from its API, or at a folder of text. Only the account's own words count: a line quoting the comment being answered is somebody else, a retweet or a boost is somebody else's post, and the private parts of an export (messages, the email on the account, the addresses it logged in from) are left alone, because a stranger cannot read them either.

It reads what you say about yourself, in English and in Spanish. Where you live and where you are from, your age, man or woman, your job, your partner, how many children and how old they are, grandchildren, pets, your height, your hand, your degree, your health, your sexuality, the languages you speak. It reads statements the way a person would: "if I were a pilot" is not a pilot, "my 10 year old laptop" is not a child, "I'm 25 years into my career" is not an age, and "I'm a huge Doctor Who fan" is not a doctor.

Spanish gives away one thing English never does. "Estoy cansada", "soy enfermera" and "estoy harto" all agree with whoever is speaking, so somebody who never states their sex has usually stated it forty times without noticing. Lineup counts that grammar as votes, and only believes it when there are three or more and four in five of them agree.

Each fact is applied to the real population it describes. The count starts from the place, spread across ages and sexes the way that country's people are, using the UN's figures for 2025. Every fact after that multiplies each age and sex by the share of people it is true of: the BLS's share of each job held by women, the Census Bureau's share of each age that is married, and so on. Keeping age and sex apart is what makes the count honest about facts that depend on each other. Nearly nine in ten nurses are women, and almost nobody is a grandparent at twenty five.

An age survives time. "I'm 34" written in 2019 is somebody around 41 now, so every age becomes a range of birth years, and two ages said years apart either agree on one or get reported as not adding up. That is one of the ways a made-up persona gets caught.

It reads a clock. Everybody sleeps, and almost nobody posts while they do. The longest quiet stretch in a few hundred timestamps is a night, and the middle of a night is about four in the morning wherever you are. That places an account in a band of timezones without it ever naming a place, and when it has named one, Lineup says if the two disagree.

The answer comes with a range. Every step has a spread, how far off it could be, and there is a cost added for every fact after the first, because facts are not independent and the count treats them as if they were. The range printed is the one that should hold the true number nine times in ten. The calibration below says how often it does.

The calibration

Every figure is checked against records where the true answer is known.

Against the US census. The Census Bureau publishes a one percent sample of real people, weighted to add up to the whole population. For each person in it who was in work, Lineup was asked how many people in their state share their five years of age, their sex, their job and whether they are married, and the answer was compared with the census's own count.

state people compared median of Lineup against the census 90% of people between inside the printed range
California 112,755 0.80 0.31 and 1.72 96%
Oregon 2,312 0.60 0.27 and 1.18 96%

The count leans low, and part of that is the question itself. A real person is more likely to be in a combination that is commoner than chance would make it, because that is what commoner means, so counting facts as if they were independent comes out low more often than high, and more so with every fact added: age, sex and job alone come to 0.88 in California, and whether somebody is married takes it to 0.80.

Low is the direction it should lean. It tells somebody they are easier to find than they are, never harder. Tell makes the same judgement: being told you are identifiable when you are not costs some care, and being told you are safe when you are not costs the identity.

The same check caught the worst mistake the tables had. A state's population was first estimated from its share of its country's towns, which put California at 58 million against the 39 million the census counts. Regions now carry their counted population in the twenty countries most likely to be run from, and the estimate is only used elsewhere.

Against SynthPAI. SynthPAI is 7,800 Reddit comments written by language models playing 300 invented people, with the facts about each written down. Every fact Lineup read from it was right: thirteen out of thirteen. For any one kind of fact it found one for at most seven of the three hundred people, and that is the honest limit of this program, below.

The census data and SynthPAI cannot live in this repository. The CI downloads both on every push and runs the same checks, so the numbers above cannot quietly stop being true.

What the report says

  • LINEUP is the count, with every step of how it got there.
  • COSTS is each fact in order of how much it cut, where it was first said, and how many posts say it. That last number is the one that matters for deleting anything: a fact said in nine posts is still said after one of them goes.
  • CLASHES is two things the account said that cannot both be true: two ages that do not add up across the years, or a place that is not in the timezones the account keeps.
  • ALSO is what it said that there is no table to count against: a named employer, a named university, a move from one city to another. Any one of these can end the lineup by itself.
  • UNREAD is what could not be read, printed first, because a count built on half an export is half a count.
  • DRAFT, with --draft, is what posting something would cost, before it is posted.

The report masks what it found unless you pass --reveal: it says "lives in a city of 540,000" and not the city, and it never quotes a post. That is so it can be pasted somewhere to ask for help without carrying the facts it is warning you about.

Running it

lineup reddit-export.zip
lineup twitter-archive.zip
lineup mastodon-export.zip
lineup posts/

Reddit, X and Mastodon all let you download your data from their settings, and Lineup reads the archive as it comes, without unpacking it. A folder of .txt or .md files is read as one post per file.

Hacker News has no export. This saves your last thousand comments and your profile, and Lineup reads both:

curl -o hn.json "https://hn.algolia.com/api/v1/search_by_date?tags=comment,author_YOURNAME&hitsPerPage=1000"
curl -o hn-profile.json "https://hn.algolia.com/api/v1/users/YOURNAME"
lineup hn.json hn-profile.json

Two accounts given together are counted as one, which is what somebody who linked them would have:

lineup reddit-export.zip hn.json

And before posting something:

lineup --draft reply.txt reddit-export.zip

It says what the draft would cost and what the same thing costs said less exactly: the region instead of the town, the decade instead of the age, the field instead of the job. Leaving a fact out costs nothing. Saying something false instead takes you out of the lineup altogether, as long as it is false the same way every time and points at a crowd rather than at one real person, because the attack only works by trusting what an account says.

--reveal prints the places, the jobs and the words they came from.

Exit code is 1 when the lineup is under a thousand people, 3 when nothing could be read, 0 otherwise.

Windows marks anything that came from the internet, so the first run may bring up a blue "Windows protected your PC" box. Right click the zip, Properties, tick Unblock at the bottom, and then extract it.

What it cannot do

It reads statements, not hints. A language model reading the same posts also gets the dialect, the local references, the slang, what somebody knows and what they get wrong, and it gets more than this does. On SynthPAI, whose comments were written to hint rather than say, Lineup found almost nothing, and that dataset was built to test models precisely because they find a lot. So the number this prints is what you have said in so many words, and the real lineup is shorter. The one thing worse than that would be the other way round.

English and Spanish only. Posts in other languages count towards the account's languages, and the report says they were not read.

The job figures are American. The BLS table is the only one that breaks jobs down this finely and by sex, and the same share of each job is used everywhere. A nurse is rarer in some countries than others. The share of people who are married, parents, left-handed or diabetic comes from the US and Europe and is right to within a factor of two in most places this is likely to be run.

Regions are counted in twenty countries. The US, Canada, Mexico, the UK, Ireland, Spain, Portugal, France, Germany, Italy, the Netherlands, Argentina, Chile, Colombia, Peru, Venezuela, Ecuador, Uruguay, Australia and New Zealand. Elsewhere a region's population is estimated from its towns, which overstates the urban ones.

Some things it knows are there and cannot count. A named employer, a school, a move. They go in ALSO and not in the number.

It is not the only thing that links accounts. How you write links them too, and Tell measures that. When you commit links them, and Alibi reads that. Photos, usernames used twice and the people you follow are not here.

A fact it misreads is counted. Sarcasm, fiction, a line of a song. --reveal shows every sentence a fact came from, so each one can be judged.

It only reads

Nothing is written, nothing is sent anywhere, no other program is run, and there is no model in it. Tests read the source and fail the build if a call that writes a file, an import of net, an import of os/exec or anything that looks like a model turns up.

That matters more here than in anything else. The thing this is pointed at is the account somebody is trying to keep separate from their name, and checking whether it can be traced by sending its posts to somebody else's model would be the leak itself. A count also has to be something a person can check: every number in the report is a table in data/, or a share in the source with where it came from written beside it, and a multiplication.

The data

table from licence
people by age and sex, 2025 UN World Population Prospects 2024 CC BY 3.0 IGO
towns of 1,000 people or more, regions GeoNames CC BY 4.0
languages by country, names in English and Spanish Unicode CLDR Unicode License v3
jobs by sex, 2025 US Bureau of Labor Statistics, CPS table 11 public domain

The calibration also uses the American Community Survey microdata (public domain) and SynthPAI (CC BY-NC-SA 4.0). Neither is in the repository or in the program.

To rebuild the tables from the sources:

sh data/fetch.sh
go run ./data/build

The builder is the only code in the repository that writes a file, and it is not part of the program.

Building

Needs Go and nothing else. No dependencies at all.

go build -o lineup .
go test ./...

Licence

MIT. Do what you like with it.

About

How many people you could still be: reads what an account has said about itself, applies every fact to the real population it describes, and says how many people still fit all of it. Calibrated against the US census, and the figures are in the README.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages