Skip to content

/work · Day-job platform · Internal · confidential

In progress · working proof of concept

Skills discovery over a résumé corpus

A working proof of concept for answering “who here has done this before?” from approved evidence, whose most valuable design decisions were all about what it refuses to do.

01 · Context

A consultancy's hardest internal question is embarrassingly simple: who here has done this before? The evidence exists (hundreds of résumés, years of projects), but it is scattered across systems, written in inconsistent vocabulary, and searched today by asking a colleague who might remember. The goal was to let someone preparing a proposal find plausible candidates faster and more broadly than that manual process, with every result traceable to approved evidence rather than to a model's impression.

Details of the organization, the people involved, and the corpus are deliberately omitted here: this is live internal work concerning several hundred real employees' documents. It is a working proof of concept, not a shipped product. What follows is the engineering.

02 · What I built

  • A PostgreSQL schema across sixteen plain-SQL migrations covering roster and identity, document parsing, search, provenance, content readiness, canonical document assignment, extraction-run accounting, atomic experience observations, human adjudication of those observations, and retrieval evaluation
  • An authoritative employee roster imported transactionally, keyed on a stable identifier and never merged by name
  • An ingestion CLI rather than a queue service: the smallest thing that could process a corpus and be inspected when it went wrong
  • Retrieval over exact terms and PostgreSQL full-text search, with the vector approach kept as a separately measured alternative
  • A human adjudication path, so extracted claims can be confirmed or rejected by a person and the outcome stored as data
  • Around ninety-seven test files, with integration tests running against a Dockerised database

03 · The senior-engineer part

Three refusals: what the system declines to do, and where, described:

  • The drawing is one canvas split into three zones, side by side. Each zone is a short flow that ends in a refusal. The refusals are drawn as the large accent boxes; the paths where work succeeds are thin lines ending in a small label, because the argument of the picture is that the refusals are the valuable part.
  • Zone one refuses to send data. Before any real document reaches the model provider, a two-key interlock and a third check kept deliberately separate must all pass.
  • Key one is the provider selector. It defaults to a mock provider when unset, and an unknown value throws rather than quietly falling back. There is one selector per model-using stage.
  • Key two is an approval flag that must equal the exact string true. It is an exact string comparison, not a truthiness check, so a wrong-cased value fails closed, and a test exists whose whole purpose is pinning that. One flag is shared by both model-using stages.
  • The third check, credentials, is kept out of the interlock on purpose: it happens inside the provider itself and later, and absent credentials throw before any document is read.
  • If any one of the three fails, the real provider is never constructed, every stage runs against the mock provider, and nothing is read and nothing is sent. Only when all three pass does the one real model call happen.
  • Clearing the approval flag is a kill switch: the real provider becomes unconstructible, with no code change and no deploy.
  • Because the two model-using stages have distinct selectors but share one approval flag, misconfiguring one stage can never enable the other.
  • Zone two refuses to guess identity. An incoming record is matched to the authoritative roster by four ordered rules: a human-authored override file, then source-identifier equality, then a normalized name taken from the filename, then a normalized name taken from the parsed document. Every comparison is exact string equality after normalization, and there is no similarity score anywhere in the matching path.
  • There are three terminal outcomes. Exactly one candidate is matched, which is the thin success line out of the zone. If candidates exist but all of them are former employees, the record is excluded. Two or more candidates and the record is quarantined.
  • The counter-intuitive property, and the most valuable thing in the zone, is that the rules do not fall through past an ambiguity. If rule three finds two candidates the record is quarantined and rule four is never tried, even though rule four would have found exactly one. The only fall-through is no signal at all.
  • A quarantined record goes to a person, who appends a row to the override file. Corrections are append-only and the last row wins, and the correction re-enters at rule one on the next run. That is drawn as a loop back to the top of the zone.
  • Fuzzy matching does exist in the codebase, but it is isolated in a separate suggestions module whose output is labeled review-only, and no assignment path reads it. It is drawn with nothing connected to it, because nothing is.
  • Zone three refuses to rank on what it has not measured. Retrieval runs two channels, exact concept matching and Postgres full-text search, and both feed one person-level union.
  • With two or more required concepts, the primary result keeps only the people matching all of them. If that returns nothing, the fallback list is returned explicitly labeled as relaxed, so requirements are never silently dropped.
  • Ranking uses exactly two signals: how many distinct required concepts a person matched, and then a capped evidence rank. The cap per document is there to stop document length and writing quality leaking into the ranking.
  • Title, seniority, document freshness, model confidence and any composite expertise score are excluded from ranking. The document date is displayed and never scored.
  • The last node in the zone is drawn dashed and faint because it was specified and deliberately not built. Vector retrieval has a written evaluation protocol, the code declares three retrieval modes and implements one, and asking for either unimplemented mode throws, so it fails fast instead of silently falling back to the baseline and mislabelling the result.
  • A two-key interlock before real data reaches a model provider. Processing anything real requires two independent environment settings to agree: the provider selection and an explicit approval flag. One misconfigured variable cannot send hundreds of employees' documents to a third party. The safety property is structural, so it holds regardless of who runs the script or how tired they are.
  • Keyword and full-text search as the baseline, before any vector ranking. The fashionable move is to embed everything and let cosine similarity sort it out. Doing that first means never learning whether it helped. The baseline shipped first; the vector approach is evaluated against it as a separate question with its own measurement.
  • Ranking uses exactly two signals, and adding a third requires measured motivation. Ranking functions accumulate heuristics until nobody can explain a result. Fixing the signal count and requiring evidence to change it keeps every result explicable, which matters enormously when the output is a list of your colleagues.
  • Deterministic identity matching with quarantine, never fuzzy auto-merge. Two people with similar names do not get silently combined. Ambiguity is held aside for a human instead of resolved by a confidence score. Getting this wrong attributes one person's work to another, which is unrecoverable in a system whose whole purpose is credit.

The judgment I'd point at first, though, is upstream of all of them. I had an independent adversarial review run against my own plan. It concluded that the proof of concept was trying to validate eight hypotheses at once (that résumés parse reliably, that they represent expertise, that a model can extract defensible claims, that a taxonomy can normalize vocabulary, that hybrid search ranks people usefully, and so on), and that this was not a proof of concept but a small product program.

It was right. The plan was rewritten around it: one user and one workflow instead of six, the phase split into a narrow credibility prototype and a separate scale demonstration, a retrieval baseline before ranking sophistication, atomic evidence observations instead of a premature universal graph, and — the part most plans omit — explicit stop criteria alongside the success criteria. Commissioning a review that can tell you your plan is too big, and then actually shrinking it, is cheaper at the planning stage than at any later point, and it is the least glamorous thing in this case study.

04 · Stack