Engineering··14 min read
How we tell a resume from a pitch deck: the upload check that refuses non-resumes, and why it isn't an LLM
HiringAnt now refuses decks, letters, books, invoices, statements, contracts, marksheets and job descriptions at upload, before anything is stored, and says what the file looked like. Here is how the rule-based check weighs the evidence.

Co-Founder & CTO HiringAnt
Since October 2026, HiringAnt refuses any upload that is not a resume, before the file is stored or an application exists, and tells the person what the file looked like instead. That covers pitch decks, cover letters, offer and relieving letters, books, research papers, invoices, bank statements, contracts, marksheets and job descriptions. The judgement is a small rule-based check that reads a document's structure and weighs evidence for "resume" against evidence for each of those other kinds. No model is called to make it.
Below: what went wrong, why rules rather than a model, how the evidence is weighed, where it runs and what it won't do. The thresholds, weights and keyword lists stay private, for a reason given at the end.
Key takeaways
- Before, an application stored the file first; screening noticed it was not a resume only after the candidate saw "Applied".
- Now every new upload is judged first. A refused file creates nothing: no stored file, no application, no notification.
- The check reads structure, not vocabulary: headings on their own line, date ranges, biodata fields, the shape of a deck or a letter.
- No single word refuses a file, contact details are never required, and strong resume structure always wins.
- The refusal names the kind ("This looks like a presentation, not a resume") so the person can fix it in one try.
- It does not judge resume quality, verify anything a resume claims, or re-judge a resume already on a profile.
What went wrong when someone uploaded a pitch deck as a resume?
The order of operations was wrong. When a candidate applied with a new file, the route stored it, created the application and moved on. "Is this actually a resume?" was asked later, inside background screening, just before the model would score it against the job.
By then everything visible had happened. The candidate saw "Applied". The employer had a new applicant whose attachment could be a pitch deck, or the job description the candidate had downloaded a minute earlier. Screening then refused the file, correctly, where nobody was looking.
The screening check had a second problem. It was a bag of substrings, looking for fragments such as "experience", "bsc" and "cv" anywhere in the text. That is wrong in both directions. "Subscription" contains "bsc". "cv" hides inside ordinary words. A pitch deck, an offer letter and a cover letter all contain "experience" somewhere, so they passed. And a real resume written without the expected English vocabulary, such as a terse driver's CV or one in Hindi, could fail.
So the fix had two halves: move the question to the front of every upload, and make the answer worth trusting there.
The same check, moved from the end of the pipeline to the front of it.
Why not just ask an LLM whether it's a resume?
Language models do most of the work further down this pipeline: screening, matching and the interviewer. For this one yes-or-no decision at the door, we chose plain code. What follows are tradeoffs, not a claim that a model would do worse. We have not run a model classifier against the same test set, so we cannot say how it would compare.
What rules give us here:
- It runs locally on text we have already extracted. Extraction happens anyway. The judgement adds no network call, no tokens and no third party seeing the document. The comment in our parser states the aim: answer "locally and for free, before anything is stored or billed".
- The same file always gets the same verdict. So tests can pin down the exact kind a document is refused as, and a regression shows up as a failing test, not as drift.
- The reason is inspectable. Every verdict carries the evidence that decided it: counts, and the names of markers from fixed lists. We can log that without logging a word of the document.
What rules cost us:
- They read form, not meaning. A table of markers only knows the kinds someone wrote a table for. We handle the rest with a backstop: a document long enough to judge that shows no resume evidence at all is refused, whatever it is.
- They can be gamed by someone who knows the lists. That is why the lists are not in this post.
- They need maintenance. Each new miss becomes a test case and, usually, a change to a table.
For a gate whose worst failure is turning a real candidate away, we wanted a decision we could read, test and reproduce exactly. The model still reads the resume. It just reads it after we know it is one.
How does the check decide a file is a resume?
It looks for structure that resumes have and most other documents do not, and grades it from none to strong. Four kinds of evidence count.
Headings on a line of their own. "Work Experience", "Education", "Projects", "Declaration" and their equivalents across domains, plus Hindi headings such as शिक्षा and अनुभव. They are matched as whole words on a short line, or as the label before a colon. Any other word on the line must be filler like "work" or "technical", so "Work Experience" is a heading and "Experience at Google" is not. Headings a job description also uses, such as "Skills", count for less than ones only a resume has, such as "Projects". A "Contact" heading counts for nothing: decks, letters and invoices have one too.
Employment date ranges. "2019 – Present", "Jan 2020 - Mar 2022", "06/2019 to 03/2022", "2015 से 2018".
Specific biodata fields. Father's name, date of birth, marital status: the fields of an Indian biodata-style resume. Generic ones such as "Name" and "Mobile" don't count; invoices have them too.
A career phrase, backed up. "8 years of experience", "6 saal ka anubhav", "expected CTC". Cover letters and job descriptions say some of these too, so a career phrase counts only alongside a degree, contact details or biodata, which is what a terse CV with no headings still has.
Contact details are a signal, never a requirement. Candidates remove them for privacy, and recruiters strip them before forwarding a CV.
Here is how a short biodata-style resume from our test set reads to the check:
- BIO-DATA (the document names itself)
- Father's Name: Ramesh Patel (biodata field)
- Date of Birth: 12/05/1996 (biodata field)
- Marital Status: Married (biodata field)
- Educational Qualification (heading)
- B.Com, MS University Baroda, 2017 (degree, as a whole word)
- Work Experience (heading)
- Accounts Assistant, Shree Traders, Vadodara (2017 - 2021) (date range)
- Accountant, Patel Agro Industries, Anand (2021 - Present) (date range)
- Declaration (heading only a resume has)
That is strong resume evidence, and nothing in it reads as anything else.
What gives away a deck, a letter or a job description?
Each kind of document that people upload by mistake has its own table of evidence. Some markers must be a whole heading line ("Agenda", "Traction", "Table of Contents", "About the role"). Others can sit anywhere in the text, matched as whole words ("tax invoice", "opening balance", "hereinafter"). Each distinct marker counts once, however often it repeats, and markers carry different weights. "ISBN" says "book" more firmly than "edition" does.
Some evidence is not a word at all:
- Decks are recognised partly by layout. Most pages landscape and sparse reads as slides; either alone is an ordinary resume. Near-empty pages and slide numbering add evidence too. A deck exported in portrait has to be caught on its text alone, and a test checks that it is.
- Books add evidence for chapter headings.
- Research papers are judged by their section structure: abstract, methods, results, discussion. Without that structure, "et al." and a DOI are just an academic CV's publication list, and the paper score is capped.
- Letters add evidence for a salutation ("Dear Hiring Manager,"), a sign-off on its own line and a subject line. A refused letter is then split into a cover letter or an offer or experience letter, depending on which phrases it used, so the message can say which.
- Contracts add evidence for an "Agreement" title and a repeated "shall".
Eleven ways a file is refused, and one way in. The tells shown are examples, not the lists.
How does it weigh one against the other?
The check takes the strongest "something else" reading and sets it against the resume evidence. A non-resume kind has two bars: strong, and a higher overwhelming.
- Strong resume evidence always wins. Nothing refuses a document with clear resume structure.
- Moderate resume evidence is refused only when another kind is overwhelming.
- Weak or no resume evidence is refused when another kind is strong.
- No resume evidence at all is refused even when no kind is strong. This is the backstop for the documents nobody wrote a table for: an essay, a short story, a recipe, meeting minutes, a product brochure.
Two adjustments sit on top. A very short document, such as a three-slide deck or a four-line offer letter, needs fewer markers to reach strong; the overwhelming bar never moves. And text too short to judge at all is let through, because guessing would refuse a genuinely terse resume.
The shape of the decision. The levels are qualitative; the numbers behind them are not published.
Every bias in that table leans the same way. A false refusal turns a real candidate away. A false pass lets a stray document through; on an application, background screening still has its own check behind this one. We chose to make the first rarer at the cost of the second.
Which edge cases did we test, and what happens with Indian resumes?
The check's main test file runs 85 test cases. At its core are 52 whole documents, built as real PDF, DOCX and TXT files and read back through the same extractor an upload uses: 25 resumes that must be accepted and 27 non-resumes that must be refused as a named kind. They are synthetic, written for the tests, not taken from anyone's upload. Some of what they pin down:
- "Subscription" is not a B.Sc. Degrees are matched as whole words only. "cv" inside another word is not a CV.
- No single word refuses a file. A resume with "Agenda", "Abstract", "Dear Sir," or "Invoice" at the top still passes.
- A product manager's skills column is not a deck, though "Roadmap", "Go-to-Market" and "Business Model" read like slide titles.
- A cover letter on top of a resume is a resume. The structure underneath wins.
- Indian biodata-style resumes pass, with Father's Name, Date of Birth, Marital Status, Religion and a Declaration.
- Marksheets are refused. A CBSE marks statement has parents' names and a roll number, and is refused as "a marksheet or certificate". Biodata fields alone, contact details alone or a degree certificate alone are not treated as resumes.
- Terse CVs with no headings pass when a career phrase is backed by something else, in English or Hinglish:
Suresh Yadav. Heavy vehicle driver, 6 saal ka anubhav. Worked with VRL Logistics and Gati. Licence HMV. Phone 9826012345, Indore.
- Hindi resumes pass as TXT, DOCX and PDF. The PDF case runs where a Devanagari font is installed.
- Unusual shapes pass: landscape, two-column, a 6-page senior resume, a 7-page academic CV.
- Hostile text stays fast. The check reads up to 200,000 characters of whatever a stranger uploaded. Our email and phone patterns had unbounded repetition and went superlinear on long unbroken runs: 1.4 seconds at 20,000 characters, on the screening path too. They are now bounded, and tests feed in 200,000 digits, spaceless CJK text and runs of symbols, failing if any takes more than a few seconds. The bound is loose on purpose: it catches the quadratic, it is not a benchmark.
Where does the check run?
On every path where a new resume file enters the product, before the file is stored or anything is created from it:
- Job applications: applying with a new file, and both resume-submit routes.
- The candidate's profile resume, including during onboarding.
- The resume library.
- Discover, our job matching, and the job agents that run on it.
- AI Job Search at /ai-job-search, the signed-out version, before a trial is opened.
- Resume Studio import, where a deck would otherwise come back as a "resume" built from slide titles.
- Employer imports: bulk upload, Google Drive and Gmail. Here each file is judged on its own, and a refused file is skipped while the rest of the batch carries on.
Scans hold no text we can read. On an application or an employer import they still go through, because a person reads those and can read a scan we cannot. Where we need the text, as in Discover, AI Job Search and Resume Studio, an unreadable file is refused with a message saying it may be a scanned image. Stored resumes are not re-judged when reused; they were judged on the way in. And the work runs off the server's main event loop, so one large upload does not hold up everyone else.
What does the person see when a file is refused?
A message that names what the file looked like and what to do, kept under 140 characters (a test checks) so it reads on a phone. Two of them, word for word:
This looks like a presentation, not a resume. Upload your CV as a PDF, DOCX or TXT.
This looks like a job description, not a resume. Upload your own CV as a PDF, DOCX or TXT.
A document that matches no known kind gets a general "doesn't look like a resume" message. In the apply dialog the reason appears under the upload box, and a fixed file can be picked again.
An employer's bulk upload report lists the skipped files with their reasons, written for the person who ran the import rather than for the file's owner:
cv.pdf: Not a resume — this looks like a presentation
We log the kind, the file extension, the counts and the names of matched markers from our own lists. Never the document's text, and never the filename, which is usually the person's name.
What does the check deliberately not do?
- It does not judge whether a resume is good. A thin resume is still a resume. Quality is screening's job, against a specific role.
- It does not verify anything. It cannot tell a true resume from an invented one. That is what interviews are for.
- It does not require contact details, English, or any particular layout.
- It does not call a model or send the file anywhere to make the decision.
- It does not change how other documents are read. Text extraction itself never judges, so job description PDFs are read exactly as before.
What we have not published
The thresholds, the weights, the bars for each kind and the full marker lists. This is a gate, and a published rulebook is an instruction manual for walking a pitch deck through it. The approach is the part worth sharing; the constants are not.
Nor are we quoting a refusal rate or an accuracy figure. The check shipped in October 2026 and we do not yet have production numbers worth stating. The tests show what it is built to do on cases we wrote, not how often real uploads are refused. When we have that number, with a sample size, we will publish it.
Frequently asked questions
My real resume was refused. What should I do?
Read the message first: it says what the file looked like, which may mean the wrong file was picked, such as a cover letter or the job description. If it really is your resume, try a plainer PDF or DOCX export of it. A layout that turns headings into images leaves the check less structure to read.
Can I upload my cover letter and resume as one file?
Yes. A cover letter on top of a resume is still accepted, because the resume structure underneath outweighs the letter. A cover letter on its own is refused.
Does this check whether my resume is ATS-friendly?
No. It only asks whether the file is a resume at all. Whether a resume reads well to software and to recruiters is a separate question, covered in the guide below.

Avanish Patidar
Co-Founder & CTO HiringAnt
AI engineer, builder, and lifelong learner passionate about turning ambitious ideas into real products. I spend my time building AI agents, voice interviewers, and recruitment systems that help people discover better opportunities and companies hire exceptional talent. Driven by curiosity, innovatio
LinkedIn





