Three genuinely AI-written passages were run through this product's text engine, back when it decided verdicts from surface statistics. They scored 63.5, 55.9 and 36.8 out of 100. The threshold for calling something AI was 65, so none of the three was flagged. The threshold for calling something human was 35 — so the last one came within 1.8 points of a machine-written document being handed back to somebody with a clean bill of health.
Those numbers are recorded in `inference/app/engines/text_statistical.py`. The obvious response is to move the threshold: 35 is plainly too generous, so make it 25, or 15, and the passage no longer squeaks through. The threshold was not moved. The verdict was removed.
```python def _verdict(score: float, conf: Confidence, word_count: int) -> str: """Score -> verdict. NEVER "human".""" if word_count < 10: return "uncertain" if score >= 65: return "ai" if score <= 35: # Was "human". Now the honest reading: nothing here fired. return "uncertain" if conf.label in ("Very Low", "Low"): return "uncertain" return "mixed" ```
The docstring is trimmed here to the comment that matters. That comment is the whole argument: nothing fired is a different fact from a person wrote this, and the old code reported the second having established only the first.
A low score measures an absence, and absences have several causes
Every text detector measures something about the writing and compares it against what it expects. This engine measured five surface statistics: how much sentence length varies, the share of distinct words in a moving window, the share of very common words, how often three-word sequences repeat, and how much average word length shifts between sentences. A high score means some measurement came out unusual. A low score means none did. Those are not opposites, and treating them as opposites is the mistake.
The file is blunt about what those five were actually reading. Not authorship — register. Plain, varied, informal writing scores low; careful, uniform, formal writing scores high, whoever wrote it. One was even labelled "perplexity" and was never a perplexity; it is lexical diversity under a wrong name.
So three quite different documents produce a low score and nothing distinguishes them: text a person wrote; text a model wrote that someone then paraphrased; text a model wrote plainly in the first place.
A learned classifier decides this lane now; the five statistics are kept at zero weight, as description. Its verdict function says the same thing about itself, and adds why a better model does not fix it: "Nothing in a probability over token statistics is provenance of these characters, and provenance is what a human verdict requires." A stronger model moves the accusation rate. It does not turn a score into a fact about where the characters came from.
The costs of the two errors are not symmetric either. A missed accusation is a false negative: the customer does not learn something they wanted to and can look elsewhere. A false exoneration is a document this product certified as human-written when a machine wrote it, and the person holding it will act on it. The engine may accuse. It may not clear.
What it would take to actually say human
Something in this product can return `human`. It is not a score. It is a Content Credential.
C2PA — the Coalition for Content Provenance and Authenticity — publishes an open specification for attaching a signed record of origin to a media file. The record is called a manifest, and Content Credentials is the consumer-facing name for the same thing. A manifest holds assertions: structured statements about how the file was made. One of those assertions is a list of actions, and an action can carry a `digitalSourceType` — a term from IPTC's published vocabulary saying what kind of process produced the content. `digitalCapture` means a camera sensor. `trainedAlgorithmicMedia` means a generative model. `compositeWithTrainedAlgorithmicMedia` means both were involved.
Two further pieces make the manifest worth anything. The first is a hard binding: a cryptographic hash of the file's actual bytes, stored inside the manifest. Change one byte and the hash stops matching. The second is a signature over the claim, by a certificate that either does or does not chain back to a list of signers somebody is willing to vouch for.
The rung that reads all this, `inference/app/engines/rungs/c2pa_rung.py`, asks those as two independent questions, because collapsing them into one has-credentials boolean hides the interesting case. A valid signature over a different payload proves nothing. A perfect hash match signed by nobody in particular proves only that whoever made the file also made the claim. It fires only when both hold.
The trust bundle is 52 certificates — claim signers and timestamp authorities — from the C2PA's own conformance repository, pinned by sha256. Every certificate in it is licensed to exonerate, so changing that file changes who may have this product call content authentic.
What a capture manifest does not assert
A signed capture manifest says a particular device or application, at a particular moment, asserted that these exact bytes came off a sensor, and staked a certificate on it. That is far more than any classifier can offer. It is still less than the plain word "authentic" suggests.
It does not assert that the scene was real. A camera can photograph a screen. That is why the point estimate for a proof-tier human finding in `policy.ts` is 3 out of 100 rather than 0 — the analog hole, named in the note beside it. Nor does a signature establish that the claim is true, only that the signer made it, which is why the interval half-width at proof tier is 2 and not 0. Someone can sign a lie.
It also does not assert anything simply by existing. A clip from the C2PA's public test files verifies against its exact bytes, names a hardware-attested capture SDK, and still returns `uncertain` here: its active manifest carries no actions and no `digitalSourceType`. A signature over a file that never says how the content was made is not provenance of capture. And a manifest asserting only `humanEdits` says a person edited something, not that a camera made it.
C2PA is also fragile: it is stripped by every re-encode, so anything that has been through a social platform has no manifest. Absence is the common case, not a finding.
The gate, as it is written
The composer that produces an image verdict, `src/services/detection/ladder/compose.ts`, is a pure function over the findings. Two lines in its eligibility check carry the rule:
```ts if (finding.direction === 'human' && finding.id !== 'c2pa') return false if (finding.direction === 'human' && finding.tier !== 'proof') return false ```
The first says only the provenance lane may ever point human. The second says it may do so only at proof tier — a signer on the trust list. The comment beside them says why the asymmetry is deliberate: self-signing a capture claim over an AI image is exactly how you would launder one, and it would arrive as a human verdict at very high confidence. Nobody self-signs a forgery to accuse their own photograph of being generated. So the same manifest, from the same untrusted signer, is still allowed to decide `ai`.
| What the file carries | Direction | Tier | Verdict | | --- | --- | --- | --- | | Trusted signature, capture assertion, nothing generative in the chain | human | proof | human | | The same capture manifest, signer not on the trust list | human | strong | uncertain | | Trusted signature asserting `trainedAlgorithmicMedia` | synthetic | proof | ai | | The same generative manifest, signer not on the trust list | synthetic | strong | ai | | Capture assertion plus a generative ingredient composited in | edited | proof | mixed | | No manifest at all; the pixel classifier scores low | none | none | uncertain |
For pasted text there is no route to `human` at any tier: neither function that can produce a text verdict has `human` in its range, and a block of text carries no manifest to read. The verdict is unreachable by construction.
Two ways this failed open, both found on real files
The rule is easy to state and was twice wrong in implementation, which is why the current version is worth more than the argument for it.
The first failure was scope. The code walked every manifest in the file as one pool. A store holds one active manifest, whose hard binding covers the bytes in front of you, plus a manifest for every ingredient — every other asset composited or edited in. An AI-generated image that embeds a real photograph therefore carries a perfectly genuine capture assertion in its store, belonging to the photograph. That assertion reached the direction logic and exonerated the composite. Ingredient evidence may now move a direction away from `human`, never toward it.
The second failure was vocabulary. The source-type test was two sets — generative terms and capture terms — with everything else discarded. A trusted claim asserting both `digitalCapture` and a synthetic term outside those sets returned `human` at proof tier: the product calling partly-generated content authentic, found on genuinely signed assets rather than reasoned about. Enumerating the missing terms would have fixed those terms and left the next ones; IPTC has already retired three concepts and added others since the vocabulary was first read, so the unrecognised set is the set that grows. Any term the build does not classify now blocks `human` and yields `inconclusive` — it does not accuse either, because a term nobody has read is not evidence of generation.
This makes the product less useful, and that is the trade
Stated plainly: this tool will not clear you. If you are a student, a journalist or a contractor holding work you wrote yourself and you want a document saying so, the text lane cannot produce one, and the image lane can only produce one if your camera signed the file and its maker is on the conformance list. Otherwise the answer is `uncertain`.
The reason to accept that is what the alternative label has historically been worth. OpenAI shipped an AI Text Classifier on 31 January 2023 and published its own evaluation: on a challenge set of English texts it identified 26% of AI-written text as likely AI-written, and labelled human-written text as AI-written 9% of the time. The tool was withdrawn on 20 July 2023, with OpenAI citing its low rate of accuracy. Separately, Liang and colleagues, writing in Patterns in 2023, ran seven widely used GPT detectors over 91 TOEFL essays and 88 essays by US eighth-graders. The detectors handled the US-authored essays with near-perfect accuracy and misclassified the TOEFL essays as AI-generated at a mean false-positive rate of 61.3%.
Our own numbers are not an answer to that. This engine detects 67% of AI-written passages in the evidence corpus — 12 of 18, from a single generator, which is the number to trust least in the whole file — at one wrong accusation across 496 documents written before 2022. The corpus contains no non-native English slice at all, because no permissively licensed one was freely available. That is precisely the population the Patterns study identifies as most at risk, and we have not measured it. The engine is not demonstrably kinder to those writers. It simply does not issue the label that would be most damaging to them when it is wrong the other way.
What "uncertain" reports instead
Refusing to say `human` is only honest if the refusal carries its reasons, so `uncertain` is not one outcome. It carries a machine-readable code, and four of them are versions of "we did not clear this file": `NO_PROVENANCE` when every lane ran and none recovered anything; `MANIFEST_INVALID` when a manifest exists but failed validation; `MANIFEST_UNTRUSTED` when it is intact but the signer chains nowhere we accept; and `MANIFEST_SETTLES_NO_ORIGIN` when the chain verifies completely and never says where the content came from. A reader who cannot tell those apart cannot act on any of them.
When nothing fires, the reported figure is 50 with a band of plus or minus 25 — the midpoint states no preference, and the band is wide because this is a declaration of ignorance, not a measurement. Beneath it, the composer prints one sentence verbatim, every time:
"That is not evidence of human authorship: an AI-generated image that was screenshotted, re-encoded, or passed through social media presents exactly this way."