← devinhuber.com Original evaluation report, shown as delivered Project breakdown →
Metadata Agent Scorecard · Devin Huber

Prototype scorecard · Global News & Business Content Operations

An indexing agent that cannot invent a subject code

A three-layer metadata pipeline for incoming news: deterministic entity resolution, model-proposed controlled-vocabulary tags, and a conformance guard that decides what is allowed to reach the index. Built and measured against an editor-assigned key.

24 records ingested 22 enriched and scored 65-term controlled vocabulary 5 calibration runs 0 enrichment failures

The four numbers I would manage this to

Straight-through rate is the number everyone asks for. It is meaningless on its own — a pipeline that auto-publishes everything scores 100%. The number that decides whether the threshold is safe is the third one.

Straight-through 25.0% 6 of 24 records published with no human touch.
Editor touch rate 66.7% 16 routed to review. This is the operating cost line.
Silent error rate 16.7% 1 of 6 auto-published records differed from the editor key. Was 37.5% before the completeness layer.
Cost / 1,000 articles $14.26 $0.0143 per record, including the 8.3% later suppressed as duplicates.

Straight-through rate went down from 33.3% and that is the point. The completeness layer moved five under-tagged records out of auto-publish and into the review queue, which is the trade this system exists to let you make deliberately: 8 points of throughput bought a 21-point reduction in errors reaching customers. Both numbers move from one config value, so an editorial director can set that dial rather than accept whatever the model happens to do.

The completeness layer, and why it had to exist

Every silent error in the previous run was an omission — a missing code, never a wrong one. The conformance guard is structurally blind to that: it answers "is every tag on this record allowed?", and a record with three correct tags and one gap passes every check in it.

MeasureValueReading
Records blocked from auto-publish5Held back because a cue fired and its code was absent.
Silent errors prevented5Every blocked record genuinely had a tag error.
Blocked but actually clean0No editor minutes spent on a false alarm.
Gate precision100.0%On 24 records. Expect this to fall on real volume.

The cues are deliberately dumb: place names and demonyms mapped to geography codes, plus regex for regulators, courts and tax. They never add a tag. Adding one would put an unreviewed guess into the index, which is the exact thing this pipeline exists to prevent — so they only withhold auto-publish. That means precision is untouched by design and the entire cost is paid in editor time, which is a number the business can decide about.

The one remaining silent error is arguably mine, not the pipeline's. On A01 the model tagged SUBJ-ANTI and SUBJ-REG because the article says the deal "remains subject to antitrust clearance." My key lists only SUBJ-MNA. I think the model is right and the key is wrong — and I left it in rather than editing the key a third time, because tuning ground truth until the score looks good is how you end up measuring nothing at all. That call belongs to an editorial lead, not to me.

Measured quality, by facet

Scored against a hand-assigned key carried through the pipeline on every record. Precision is codes applied that the key agrees with; recall is codes in the key that were applied.

Facet Precision Recall F1 Exact set Failure mode
COMPANY 100.0% 100.0% 1.000 100.0% None on this set. Both disambiguation traps passed.
GEOGRAPHY 100.0% 95.0% 0.974 90.9% Misses a jurisdiction named only in passing.
INDUSTRY 100.0% 79.3% 0.885 81.8% Will not infer sector from a company it knows.
SUBJECT 93.5% 70.7% 0.806 50.0% Drops secondary subjects; SUBJ-REG most often.

Recall is the weak axis on every facet, and that is the right shape rather than an accident — the confidence floor, the evidence check and the vocabulary membership test all trade recall away to buy precision. A researcher who gets an incomplete result set refines the query; one who gets a wrongly-tagged document stops trusting the index. 11 of the 12 SUBJECT misses landed in the editor queue, where a human sees them. The two SUBJECT false positives are both on one record and both defensible — see the note under the safety metric.

What the guard stopped

Every code the model proposes is tested against the vocabulary before it can reach the index: membership, facet match, verbatim evidence, retirement status, confidence floor.

CheckCountReading
Codes proposed by the model98Across 22 enriched records.
Accepted from the model8315.3% rejection rate.
Inherited from the taxonomy20Broader terms the guard derived, not model output.
Rejected below confidence floor15All 15 rejections were this check.
Hallucinated codes rejected0Model stayed in vocabulary on this set.
Ungrounded evidence rejected0Every quoted span was found verbatim.

Two zeros that need saying out loud: on this set the model did not invent a code or fabricate a justification, so the guard never had to fire in anger. The guard is not there because the model is unreliable today — it is there so the answer to "what happens when it is" is a rejected tag rather than a corrupted index. To prove it live, delete a row from the vocabulary table and re-run: the next record that uses that code is rejected as HALLUCINATED_CODE and routed to a human, with no code change.

What broke, and what I changed

Four runs against the same key. Each finding came from the scorecard, not from reading outputs by eye — which is the point of building the scorecard first.

Run 1

The confidence gate was measuring the wrong statistic

Auto-publish required the minimum confidence across every applied tag to clear 0.85. But a correctly applied broader term is legitimately tagged near 0.60, so a single valid roll-up disqualified an otherwise clean record. 87.5% of the queue went to human review.

Gate now tests the lead tag of each required facet → editor touch 87.5% to 58.3%
Run 2

I had asked the model to do the taxonomy's job

The prompt told the model to add broader terms alongside narrower ones. It applied that inconsistently in both directions — adding IND-TECH where the key did not want it, omitting GEO-EU where it did. The vocabulary already encodes broader/narrower, so this never needed a judgement call.

Roll-up moved into the guard, ground truth closed under the same function → GEOGRAPHY F1 0.899 to 0.962
Run 3

The fix for run 2 introduced its own regression

"Return only the most specific code" was read as "return one code", and the model started dropping co-equal secondary subjects. An environmental enforcement action is also a regulatory action; neither is the other's ancestor. One instruction was doing two jobs.

Rule split into two explicit halves → SUBJECT recall 65.9% to 70.7%, precision to 100%
Run 4

The scorecard was reporting a negative rejection rate

Codes applied included taxonomy-inherited broader terms; codes proposed did not. The metric compared two different populations. A reporting bug, but the kind that quietly makes a dashboard untrustworthy.

Rejection rate now counts model-originated codes only → 15.3%, inherited reported separately
Run 5

Nothing in the pipeline could detect a missing tag

Every error that reached auto-publish was an omission, and the guard only tests tags that are present. A record can be three-quarters right and pass every check. So the fix was not a better prompt — it was a second question the system had never been asked: does this record look under-tagged?

Deterministic completeness cues block auto-publish → silent error rate 37.5% to 16.7%, review queue precision 78.6% to 87.5%

Four of these five findings were defects in how I measured, not in what the model produced. That ratio is normal and it is the argument for building the scorecard before tuning anything: without a key carried through every record, run 1's 87.5% touch rate looks like a model problem and gets answered with prompt engineering that would never have fixed it.

Review queue quality

A queue full of records a human would not have changed teaches editors to click through, and then the gate protects nothing. This is the metric that stops the threshold from being set too conservatively.

MeasureValueWhat it means
Review queue precision87.5%14 of 16 routed records genuinely needed a human.
Unnecessary reviews2Records a human would have approved unchanged.
Duplicates suppressed28.3% of the queue; both correctly matched to their tier-1 canonical.
Enrichment failures0Failures route to specialist review; there is no path from error to auto-publish.

Both unnecessary reviews were triggered by the same thing — an INDUSTRY lead tag between 0.70 and 0.85 on a record that was otherwise correct. That is a per-facet threshold problem, not a model problem, and it is the first thing I would tune with a larger key. Note that adding the completeness layer raised queue precision rather than diluting it: every record it added to the queue belonged there.

Taxonomy gaps the run surfaced

The pipeline reports concepts it could not express, which turns taxonomy change requests into an evidenced queue rather than an argument.

An earlier prompt revision produced 21 gap reports on 24 records by flagging every uncodeable detail — figures, dates, sub-aspects of concepts already coded. Tightening the instruction to "a central subject with no code at all" took it to one or two per run. A gap report that cries wolf costs a taxonomist real time, so its precision matters as much as the tagging does.

Ninety days, three gates

Each phase ends at a measurement, not a date. Nothing widens until the previous gate holds for two consecutive weeks on live volume.

Days 1–30

Shadow mode

Runs on live ingest and writes to a staging index nobody reads. Editors tag as they do today; the two outputs are compared nightly. Builds the golden set as a by-product of work already happening, at 300–500 records per language.

Gate Precision ≥ 97% per facet and a signed-off key large enough to detect a 3-point drift.
Days 31–60

One desk, live

Auto-publish enabled for a single content stream with the highest measured precision. Editors get a one-click reject that writes straight back to the key. Thresholds tuned per facet using the review-queue precision number, not per pipeline.

Gate Silent error rate under 2% and review queue precision above 70% — editors must not learn to rubber-stamp.
Days 61–90

Widen and hand over

Extend to the remaining streams and offshore shifts, with the scorecard sliced by vendor, shift and time zone. Taxonomy governance takes ownership of the vocabulary table; the pipeline stops being something engineering has to redeploy.

Gate Quality holds within 2 points across every shift, and a taxonomist has shipped a vocabulary change with no engineering involvement.

What this prototype does not yet tell me

Stated plainly, because the gap between a 24-record prototype and a global content operation is where the actual work is.