Swept Aug 31, 2026, 07:30 UTC
How the machine works.
The Index is the public face of a program that runs every night. This page is that program in plain language: what it reads, what it checks, what it kills, how it scores what survives, and the things it will not guess. Every rule below is one the site actually runs on, so if a number anywhere surprises you, the reason it is that number is on this page.
The nightly sweep
Every night the machine reads company job feeds directly from the applicant tracking system each company publishes: 45 boards on this sweep. It works in one order and always the same order. Pull every posting the feed carries. Check every posting it already knows about, at the source, one request per posting. Kill the ones that fail a rule. Score what survives. Write the night down.
One clock. Every timestamp on this site is the moment that sweep finished, Aug 31, 2026, 07:30 UTC, and nothing on any page is computed from the time in your browser. A page that told you the time on your own machine would be telling you about your machine. The stamp is what the claim on every row is dated to, so it is the same string everywhere, read from one field.
What we read
Source-direct means the record came from the board the company itself publishes, read by us, on the night the record is dated. We do not read aggregators. Where an aggregate source carries a posting the company's own board and directory do not, the source wins and the posting does not appear on the index. It appears on the kill list instead, with what we looked for and did not find.
- Ashby
- 56
- Greenhouse
- 17
The marks, and how to read them
Three states, and a mark never appears further than one screen from this legend. Two of them are live states and they carry the same colour, because they say the same thing about the posting: it was there when we looked.
- Verified this sweep
- Re-verified
- Closed
- Verified this sweep
- The machine loaded this posting at its source during this sweep and it was there.
- Re-verified
- The same, and we have now confirmed it on more than one sweep. The mark carries a notch so the two live states can be told apart without colour.
- Closed
- The posting is gone from its source. The record keeps its page and its history and loses its apply path. The mark is grey, not red: a closed posting is an honest archive record.
Red is never a row mark on this site. It belongs to the kill count and to the per-rule counts beside it, which are readings about what the rules found rather than verdicts on a row. There is no ghost rate here: killed over pulled reads as a rate of deception, and it was dropped on the same day the age rule was. And the two typefaces are a rule, not a mood: numbers, timestamps, statuses, scores and source names are set in the mono face because a machine produced them. Everything else, including every absence, is set in the human face, because "No date shown" is us saying what we do not know rather than a machine stating a reading.
Re-verification and windows
A posting is checked again on every sweep after the one that found it, and it is checked at its source rather than against our own copy. Postings we have now confirmed on more than one sweep read as re-verified rather than as verified, which is the mark changing to say that the confirmation is now ours as well as theirs.
Nothing expires here, and something used to. A posting was once taken off this list purely for passing a fixed age. That rule was withdrawn, because it inferred an employer's intent from a duration, and because senior and specialist searches legitimately stay open far longer than any fixed window allows for. A posting now leaves this list when it leaves its board, or when one of the five kill rules below fires on something the employer actually did. Age is shown, sorted, filtered and plotted against the average lifespan quoted in those rules, and it decides nothing.
Where a record carries a window of its own, the row shows its age against it rather than as a bare number, so you can see which clock the row is being measured on. This sweep's records carry no longer window, so no row shows an age measured against one.
The kill rules
A kill is a posting we stop showing and start citing. Killing is done by rule and never by opinion, and every kill is published with the observations and dates it was decided on. The reason column states what was seen. It does not state why anyone did anything, because a feed does not carry intent and we will not print a claim we cannot evidence.
How long a killed posting was open is computed as the date we recorded the kill minus the date the source first published it. It is never stored, because a stored duration and the dates it came from are two sources of truth that drift.
The machine knows which rule fired on each kill: kill_reason() decides between the families below and emits the answer with the record as kill_rule. The export carries that field, and every rule is counted every night, zeroes included, because a rule missing from a summary reads as a rule that was never run. These are the same counts /kills and the report render, from the same reading, so the three pages cannot disagree.
-
repost churn
0A req that left the boards and came back under a new identifier, freshly dated, with its title, location, remote flag, employment type, posted pay and description byte for byte the ones it had before.
It compares tonight against closed records carrying a content fingerprint, and the machine only started writing that field on August 19. It reports nothing until the archive has the records to compare, and that zero is a result rather than a rule missing from the page.
-
misrepresented
0The location the employer printed offers remote and nothing else, and the posting's own description states an in-office requirement, with no remote option anywhere in its text.
-
zombie
0The posting is still listed past a closing date the employer printed themselves, with an explicit four digit year beside it.
-
phantom
0The posting's own link is gone at source: a 404 or 410, or a redirect away from the posting's own identifier, confirmed on a second request.
Ashby answers 200 for postings that do not exist, and Ashby is about four fifths of the boards we read, so phantom cannot be established there at all. A rule that cannot see is told to say nothing rather than to guess.
-
touched, not refreshed
0The published date moved while the title, location, remote flag, employment type, posted pay and description all stayed byte for byte identical.
Every rule ran and every rule found nothing. That is the whole result, printed rather than summarised away. No bars are drawn beside these counts, because a track of length zero reads as a measurement of zero and this is an absence of findings.
The alternative was available and was refused: we could read our own reason prose back through a keyword matcher and group the kills by what the words looked like. That would be this website inventing a classification and presenting it as the machine's finding, on the page whose whole authority is that the machine found it.
Why we do not kill on age
We used to. A rule called evergreen killed a posting for having been listed longer than a fixed window, and it is retired, because it inferred an employer's intent from a duration on the one site whose whole spine is that we report observations and never intent. That was our reasoning. It is also, word for word in substance, the reasoning of the only peer-reviewed paper the field has produced, which is worth showing rather than claiming.
On whether a duration can produce a finding at all:
While one could get data on how many jobs are posted and left for a period of more than 30 days or are continuously posted throughout the year, these cannot robustly be categorized as ghost jobs because the hiring firm can argue that they have difficulty finding good candidates.
The defence Ng names is not hypothetical and it is not rare. Our own cited figure for how long a real search takes is the reason: a senior role open ninety days is an ordinary search and not evidence of anything, and any threshold short enough to catch a ghost is short enough to catch a hundred honest ones. The definition itself says so.
On what the definition of a ghost job excludes:
Jobs which take a long time to hire, which may be due to stringent checks of job candidates do not fall under this definition.
A rule that cannot tell a slow hire from a ghost cannot implement that definition. Which is the whole argument against age, and it is why every rule we do run points at something an employer did rather than at how long they took: a deadline they published and then ignored, a sentence in their own posting that contradicts their own location field, a URL that does not resolve, a date that moved while every other byte stayed identical.
The United States counts a job opening in JOLTS when an employer is actively recruiting and the job could start within 30 days. Both halves are statements about what an employer intends, and Ng's point is that neither can be checked from outside. Ghost jobs are therefore inside the official vacancy statistics rather than outside them, which is a larger problem than any job board has, and not one this machine claims to solve.
Ng, Ghost Jobs, arXiv 2410.21771, 2024, page 3
Sites that publish a ghost rate derived from a thirty day cutoff are doing the thing the field's only paper says cannot be done. We have no such number and will not have one. What we publish instead is a list of postings that each did something specific, with the observation and the date it was made, and a reader who disagrees with any single row can check it at source tonight.
Rubric v1, with weights
Every posting that survives the night is scored out of 100. Five components, fixed weights, published here so the rubric is checkable rather than mysterious.
- Title scope
- Weight 30
- How close the posted title and its scope are to the kind of work this index covers.
- Remote and geography
- Weight 25
- Whether the posting is remote, and how tightly its geography is drawn.
- Compensation
- Weight 20
- Whether a range is posted at all, and what it is. A posting with no range scores lower.
- Freshness
- Weight 15
- How recently the source published or refreshed it, measured from a date we can show.
- Apply friction
- Weight 10
- How hard the apply path is: account required, form length, where the click lands.
One consequence worth stating plainly: Fit blends the rubric with freshness, so a sort named Fit is not a sort by seniority, and the index says so where the sort is. A second: where a component falls outside its own weight, the value is printed and no bar is drawn beside it, because a bar is a measurement against a stated maximum and a clipped bar would draw a picture of a number that is not there.
Posted, first seen, and age
Two dates, two different facts, and conflating them is the most common way a job board misleads without lying.
- Posted
- The date the source itself shows. It is the employer's claim about the posting's age, and very few boards publish one: 66 of the verified rows in this sweep carry it. Where the source shows nothing, the cell reads "No date shown".
- First seen
- The sweep on which we first found the posting. It is our own observation and it belongs to us rather than to the employer, which is what will eventually make it the most useful date on the page.
First seen is a column on the index, and it renders because the archive can now support it. Most of the rows in this sweep carry a date older than the sweep that rendered them, so the column says something different per row instead of repeating one date. 0 of the verified rows were first seen on this sweep, and those cells read "No date shown" rather than tonight's date, because a row we met tonight has no first-seen history to show. The switch is an observation about the data on every build, never a count of nights: three sweeps of a machine that saw nothing new would have satisfied a counter and still printed one repeated date.
An age renders only when the record carries the date it was computed from. That rule has two edges and both matter. A posting we first saw on this sweep has no measurable age: we know it exists, we do not know how long it has existed, and counting from tonight would render a zero that reads as "posted today" about an employer we cannot evidence.
What we archive
Everything, and we do not take it down. A posting that closes keeps its page, its provenance and its history, and loses its apply path: no closed page anywhere on this site offers a way to apply, because that would be a door we know is locked. A kill keeps its dates and its receipts. The archive is most of the point. A market that forgets what it advertised last year cannot be held to it, and a record of what was open, when, and for how long is the only way any of this is checkable a year from now.
What we refuse to infer
The list below is the part of the method that costs us features. Each entry is something the site could show, that a reader would probably like, and that we cannot source. They ship the day the data does.
- Motive
- A duration is a measurement. A motive is a claim about a state of mind, and no feed carries one.
- A kill rule on a kill
- The families are named above. Attaching one to a record here would mean classifying by reading our own words back, which is not the same thing as the machine's answer even when it agrees.
- A role family
- The index filters by location, by whether a range is posted, and by freshness, because each of those is a field the record holds. There is no role family filter, because there is no role family field: deriving one by reading job titles would be a classification of ours wearing the machine's clothes.
- An age with no date behind it
- Covered above, and it is the rule the rest of them are a family of. A number whose provenance we cannot show does not go on the page.
- Somebody else's measurement, drawn as ours
- A duration that came from outside reporting never draws a bar against the reference line, because the bar is a measurement and we would not have one.
- Reasoning we did not receive
- The fit panel prints the five component values and the arithmetic that makes the total. It writes no sentence explaining a component, because the machine has not sent one and writing it here would be inventing the machine's reasoning on the panel that exists to show it.
Corrections
Every page here is a claim about a company on a given night. Claims get answered, and the sweep runs nightly, so an answer really does land the same night.
Posting still live and we got it wrong? Tell us and we will re-verify tonight.
The rest of the receipts are on the other pages, not restated here. The kill list carries what died this sweep and why. Not here, on purpose carries what this site refuses to build, and each refusal's cost.