A tiered metal stand displays photo cards of a woman in a bow tie holding wine, plus other professionals near icons for medicine, construction, and cooking.

The sommelier who nearly landed in an AI salary hub

Key measurements

Each measurement, its value, and where and when it was measured.
MeasureValueSource and date
Roles in the salary dataset3,445September 7, 2026 · Salary Explorer index, orbytlabs.ai, which states the role count in its heading and in its page description
Roles that clear the AI gate687September 7, 2026 · AI salary hubs index, orbytlabs.ai, whose first line reads 687 AI roles tracked across 13 categories
Roles in the engineering catch all321September 7, 2026 · AI salary hubs index, orbytlabs.ai, the AI Engineering Roles card, which reads 321 roles tracked
Next biggest hub after the catch all53, AI operations rolesSeptember 7, 2026 · AI salary hubs index, orbytlabs.ai, the AI Operations Roles card, which reads 53 roles tracked and is the largest of the remaining twelve
Distinct salary bands513September 7, 2026 · my own run of the band collision guard over the served catalogue on 2026-09-07; it reads a private repo, so there is no page to open
Titles sharing a band with another title3,199September 7, 2026 · my own run of the same band collision guard, same catalogue, same day; again a private repo with no public artifact behind it
Roles admitted by lowercasing the gate title46, taking 687 to 733September 7, 2026 · my own measurement, re-running the gate with the title folded to lower case on both sides and diffing the two sets of roles; no committed file holds this number and nothing serves it

A sommelier nearly ended up on an AI salary page.

Not as a joke. As the output of a one line fix I sat down to ship and then did not ship. I will come back to him.

Start with the mess. I had a pile of thin AI role pages and they were all competing with each other. Each one covered a single job title. Agentic orchestrator. Knowledge engineer. Retrieval engineer. A number, a range, four paragraphs of prose. None of them was the page anyone actually wanted.

My read was that people ask the category question, not the title question. I have no query log that proves it. That was a design call, and the whole restructure sits on top of it.

So I collapsed them into categories.

That is what the salary hubs are. Thirteen category pages. Six industry verticals, six functional disciplines, one for creative work.

Open AI healthcare roles and you get a category median, a full range, every tracked role ranked by base pay, a city table, and a short set of questions answered by somebody with opinions. Do you need a clinical background to work in healthcare AI. The answer there is no, but it helps, and then it names the profile that keeps losing offers: the generalist who has neither the clinical training nor the modelling depth.

What does the classifier actually do?

There is no database table behind any of this. There is one array called SALARY_HUBS and one function called classifyRoleToHub. It takes a role slug and a role title. It hands back a hub slug, or nothing.

It runs in two steps. First there is a gate. Is this role AI related at all.

The gate is a list of slug patterns and title keywords. Anything starting with ai-. Anything ending in -ai. Anything starting with ml- or llm- or nlp-. Then a keyword list: machine learning, computer vision, retrieval, agentic, robotics, alignment, interpretability, a couple dozen more. A registered nurse fails and gets nothing back. So does an electrician.

Of the 3,445 roles in the dataset, 687 clear that gate.

If a role passes, step two walks the hub array in order and returns the first hub whose slug pattern or title keyword matches. First match wins, and that one sentence is the entire taxonomy. Everything else about the design is a consequence of it.

Why does the order of that array decide everything?

Because with first match, the order of the array is the classification. Move a hub up and roles move with it.

Verticals go first. Healthcare, finance, legal and policy, security, industrial, consumer and commerce. Creative next. Then the disciplines: executive, research, product, design, operations, engineering.

Engineering sits last on purpose, and it is also the catch all. A role that clears the gate and matches nothing more specific lands there. That is why a clinical LLM engineer goes to healthcare and a fraud detection ML engineer goes to finance. Somebody hunting healthcare AI work wants the page about cleared workflows and protected health information, not the page with every AI job on it.

The bill for that arrives as one number. Of the 687 roles in hubs, 321 sit in the catch all. That is six times the next biggest hub. It is also the one hub defined by what it is not, and there is no unclassified bucket anywhere to show up as a hole in a report.

So where does the sommelier come in?

The gate lowercases the role slug before testing it. It never lowercases the title.

Ten of its keywords are lowercase and more than one word. Machine learning. Deep learning. Computer vision. Natural language. Reinforcement learning. Not one of them can match a title in title case, which is how every title in this dataset is written. Those ten have never matched anything. The slug patterns have been carrying the gate on their own.

I did not see it until I read the file to write this post.

The fix is one call to toLowerCase, so I ran it before shipping it. With the case corrected, 733 roles clear the gate instead of 687. Forty six new arrivals. Some are exactly who you would want: Senior Machine Learning Engineer, Staff Machine Learning Engineer, Graph Neural Network Researcher.

The rest are Real Estate Agent, Insurance Agent, Travel Agent, and Sommelier / Beverage Director.

The word agent is in that keyword list, put there for agentic systems. Lowercase both sides and it starts catching people who sell things. Real Estate Agent, Insurance Agent, Travel Agent. Insurance Agent lands in AI finance roles.

The sommelier arrives through a different hole. RAG is in that list too, and lowercased it matches the middle of the word beverage. He lands in AI consumer and commerce roles, filed beside the retail forecasting engineers.

So the case bug has been hiding a second bug, and the one line patch makes the taxonomy worse rather than better. The keyword needs a boundary before the case gets touched. That is a content decision that wanted a measurement in front of it, and now it has one.

What is a hub number, exactly?

A hub shows a low, a median and a high for the whole category. It sorts the roles by base median and takes the middle one, then takes the lowest low and the highest high across the set.

So it is a summary of role baselines, and those baselines are the part worth saying out loud. Each one is a hand authored band, not a cell lifted from a wage table. There are 513 distinct bands covering 3,445 titles, and 3,199 of those titles share a band with at least one other title. BLS publishes wages for 173 occupations. We serve 3,445 titles. No arithmetic closes that gap without inventing the difference, so the page says so instead of pretending.

Every figure is a computed estimate. The cost of living multiplier, taken from Bureau of Economic Analysis regional price parities, enters only on the city table further down the page and inside the salary calculator. It never touches the headline number.

The published wage data we hold is BLS Occupational Employment and Wage Statistics, plus Department of Labor H-1B filings. An H-1B filing records the floor an employer commits to for a sponsored worker rather than what the market pays, which is why it shows up on comp by employer carrying that qualifier and never inside an estimate.

That rule exists because we broke it. Six pages once said the ranges were pinned to published wage percentiles by seniority level. Specific, checkable, false. Fixing it in one place left it wrong in five, so the disclosure now lives in one module every surface imports, comp by metro included.

Why are the hub questions hand written?

Because generated question text is where a content system starts saying things nobody meant. It fills a template with a statistic. Out comes a sentence that is grammatical, plausible, and about nothing.

The hand written set answers what people actually ask. Do AI engineers still need to know how to train models. The answer on the engineering hub says less than people assume, because most of the work in 2026 is calling APIs, building eval pipelines, designing retrieval and shipping surfaces. That is an argument, not a fact. Somebody can disagree with it, which is the whole point of putting it there.

What will the hubs not do yet?

They are AI only. The gate runs before anything else. Nurses, accountants, electricians and welders all have pages, and not one of them has a hub, so the salary index is still the front door for those.

There is a second, older grouping over the same catalogue, comp by industry, which sorts every role by slug prefix and does cover them. Two taxonomies over one dataset is not something I would design on purpose. Non AI hubs are the pass that collapses them, and I have not built it.

The second thing they will not do is guess. Every hub is prebuilt from the array and the route sets dynamic params to false, so an invented URL gets a 404 from the router instead of a rendered page. We learned that on a sibling route the expensive way. It answered 200 for slugs that were never roles, and each invented URL minted its own cached copy for ninety days.

Counts on the page are computed at build time by running the same classifier the pages run, so the roles tracked line on a card cannot drift from what the hub holds.

The prose is what drifted. My own comments in that file still call it a twelve hub taxonomy, in four places. There are thirteen. The array is right and the rendered count is right and the comment is wrong, which is an on the nose demonstration of why I stopped typing counts into strings. Now it is written down somewhere other than my head, which is most of what the blog is for.

Related reading:

Methodology

I read every number out of the code and then checked each one against the page that serves it, rather than trusting my own reading twice. The role count, the count that clears the AI gate, the size of the engineering catch all and the size of the next hub down are all printed on the two public pages listed below, so anyone can open them and check me. The two band figures came from running the band collision guard over the served catalogue myself on 2026-09-07 and reading what it printed. The lowercased gate count came from re-running the same gate with the title folded to lower case on both sides and diffing the two sets of roles. Those last three are not served anywhere, so they carry my own run as their provenance and nothing stronger.

Limitations

These counts describe what the code returns. They do not show that the taxonomy is any good. Nothing here measures whether somebody hunting healthcare AI work is better served by a hub than by a role page, and no reader data of any kind sits behind the premise that people ask the category question first, so that premise is a design call and stays one. The salary figures are computed estimates built on hand authored bands rather than measured wages, so a hub low, median and high inherits every limit of the baselines underneath it. Three of the numbers here, the band count, the shared band count and the lowercased gate count, come out of a private repo: you cannot open the artifact behind them, and they rest on my run of it. The 733 figure is a counterfactual on top of that. It describes a patch I chose not to ship, not anything the site serves.

Sources

  1. AI salary hubs index, orbytlabs.ai
  2. Salary Explorer index, orbytlabs.ai

Common questions

How does a role get assigned to a hub?

Two steps. A gate asks whether the role is AI related at all, reading slug patterns and title keywords. If the role clears it, the classifier walks the hub list in order and returns the first hub whose pattern matches. First match wins, so the order of that list is the classification. Every role that clears the gate lands in exactly one hub.

Why is there no hub for nurses, electricians or accountants?

The AI gate runs before anything else, and a role with no AI signal returns nothing. Of the 3,445 titles in the dataset, 687 clear that gate today. The rest keep their own salary pages, reachable from the salary index, and they belong to no hub. Hubs for non AI categories are a separate pass I have not built yet.

Are the hub salary figures measured wages?

No. A hub figure is the middle role baseline in the category, plus the lowest low and the highest high across it. Those baselines are hand authored bands rather than wage table cells, and 513 bands cover all 3,445 titles. The published wage data we hold appears separately on role pages as its own labelled benchmark.

How can a title share its number with another title?

Because most of them do. BLS publishes wages for 173 occupations and we serve 3,445 titles, so a band gets reused across neighbouring roles: 3,199 titles share one with at least one other title. Separating them would mean inventing the difference. The pages disclose the sharing instead, on every surface that shows a figure.

Does reading the hubs cost anything?

No. The salary pages are open to anyone, with no account and no card. All three Orbyt products are on an early access waitlist on production right now, so signing up puts you in line rather than straight into the app. Nothing behind that line gates the hub pages, the role pages or the calculator.

Justin Bartak

Founder, CEO and Chief AI Officer of Orbyt Labs

Builds software with AI agents across engineering, product, design and go-to-market. Publishes tests, failures and decisions at Orbyt Labs.

Writes The Machine Speaks with the agents that build the product, and The AI-Native Lens (opens in a new tab).

All of The Machine Speaks