We maintain a corpus of 456 role-specific resume examples in TypeScript. Someone asked me what a good bullet point actually looks like, and rather than answer from taste I decided to measure the thing I already had.
Fifteen minutes later we had a script, a set of numbers, and a conclusion. The conclusion was wrong, because the script had silently read about twelve percent of the data.
This is a post about that failure mode, and then about the numbers I got once the script worked.
Thirty-one TypeScript files, each exporting an array of role objects. One role looks roughly like this:
The interesting field is description. It holds a newline-delimited list of bullets as a single string, so the whole corpus of bullets is sitting there in source, greppable, without a database or an export step.
Nothing exotic. Match description: , then a single-quoted string, allowing escapes so an apostrophe inside the text does not terminate the match early.
It found 199 description strings. I did not question that, because I had no prior for what the number should be. 199 sounded like a lot of text. We computed medians off it, looked at the opener distribution, and started writing.
The number that saved me was on a different line of the same output: roles 456. The slug count was fine. So 456 roles between them had 199 job descriptions, which would mean the overwhelming majority of roles had no work history at all. I knew that was false, because I had rendered these pages.
Some of these files were formatted at a width that keeps the value on the same line:
The pattern had a literal space after the colon. Every record in the second shape failed to match. Not with an error. Not with a warning. The regex simply found fewer things, and a regex that finds fewer things looks exactly like a regex running over a smaller corpus.
The general shape of this bug is worth naming, because it is not really about regexes. A parser that silently skips malformed input converts a crash into a wrong answer. A crash costs you ten minutes. A wrong answer costs you however long you spend believing it, which in my case included a first draft of this post.
Two habits that catch it: Have an expected order of magnitude before you look at the output. 456 roles times three jobs each is well over a thousand. 199 should have been alarming on sight. Cross-check one extracted count against a different one from the same run. Slugs and descriptions come from the same files through different patterns. When one is plausible and the other is not, the pattern is the suspect, not the data.
With the parser fixed: 1,723 description blocks, of which 1,267 use the bullet format, yielding 3,815 individual bullets.
Length. Median 14 words. The 10th percentile is 11, the 90th is 17, the full range is 7 to 25. That is a tighter distribution than I expected, and it is not the product of a style rule, because there was no style rule. It is what a claim plus its evidence happens to cost in English. Under about ten words you have stated a duty. Over about twenty you have written a paragraph that gets skimmed.
Numbers. 89.0 percent of bullets contain at least one digit. 1,081 contain a percentage, 555 contain a currency amount. That leaves 418 bullets with no number in them at all, and reading a sample of those is instructive: they are the ones describing scope rather than outcome, which is a legitimate thing to describe when you cannot quantify it. The failure is not "has no number", it is "has neither a number nor a specific".
Verbs. 332 distinct opening words across 3,815 bullets. The top ten (managed, developed, led, built, created, designed, implemented, conducted, reduced, manage) account for 40.9 percent of all openers. 143 verbs appear exactly once.
That distribution is the interesting part. It is not flat and it should not be flat. A long tail of one-off verbs (architected, migrated, authored) carries the specificity, while a small head of common verbs carries the ordinary work. A resume where every bullet opens with an unusual verb reads like a thesaurus exercise.
Weak openers. 149 bullets, under five percent, begin with supported, assisted or similar. Zero begin with responsible for. That one is a genuine consensus in the corpus rather than something I enforced.
