Measured, not asserted
Published
A residue result is a number, a unit and a compound lookup key, and only the number looks like the answer. Limits are published per pesticide and per commodity together, so a pair the table does not carry has nothing to breach. And the unit lives in a different key from the quantity it describes, which means the same figure can mean a thousandth of what it says while staying entirely plausible. This test renamed each of those in turn. One of them cleared two genuine exceedances without moving a single count.
Eight samples, two exceedances, one option
The fixture screens eight samples from four growers against a published maximum-residue table, in mg/kg, keyed by pesticide and commodity together. The buyer applies a 50% measurement-uncertainty deduction before deciding, which is the conservative practice and makes the fixture harder to break, not easier. Two samples exceed after that deduction: chlorpyrifos on orange at 0.180 mg/kg against a 0.01 limit, and dimethoate on apple at 0.044 against the same. A third, imazalil on apple at 3.10 against a 2.0 limit, clears only because of the deduction and is the honest near-miss.
Rename the option that states which unit the laboratory reported in. The library falls back to its own default, which is micrograms per kilogram, because instruments report parts per billion and that is a reasonable thing for a laboratory-data library to assume.
The measured result: analytes=8 compared=8 no-limit=0 EXCEEDANCES=0 reported-in=ug/kg. Eight samples, eight compared against a published limit, nothing missing, nothing unreadable, and the buyer's own screening check passing and printing 8 of 8 sample(s) compared against a published limit.
The chlorpyrifos sample now reads reported=0.18ug/kg as-mg/kg=0.00018 decision-value=0.00009 mrl=0.01mg/kg. Every one of those numbers is finite, positive and inside the range residues actually occupy. The consignment ships.
Protection on its own moved nothing
All five areas of this pass were first run through five presets -- the ES5 default path, the modern target, the emit gate's own option set on both targets, and the string transforms. Twenty-five comparisons, every one byte-identical to the unprotected run.
So the unit result is not a protection result. It required member renaming reaching a property name that the installed screening library reads. The engine renames what it is told to rename; deciding what crosses a boundary is the caller's job.
A unit is not a quantity
This is the distinction that makes the unit arm different from every other arm in the file. A quantity says how much. A unit says what the quantities elsewhere mean. Lose the quantity and you get an unreadable number, which most codebases already guard against. Lose the unit and you get a perfectly good number that means something else.
One field away on the same records, renaming the concentration itself produces reported=NaN as-mg/kg=NaN decision-value=NaN on every sample. That is visible in the detail line -- and the verdict is still EXCEEDANCES=0, because a comparison against a value that is not a number is false and the exceedance branch is simply never taken.
So this fixture fails open in both directions, and that is worth being blunt about. Requiring a result to be a finite number before comparing it would catch the concentration arm in one line. Nothing about that check would touch the unit arm, because a residue in the wrong unit is a perfectly finite number.
The check that works, and exactly what it cannot see
The buyer's own screening rule refuses to sign a screen where any sample had nothing to compare against. It is a good rule and it earns its place twice.
Rename the limits table and the default limit together and every sample lands in no-limit=8; the rule refuses the screen outright. Rename the flag that enables the rule alongside them and the screen goes through reporting compared=0 no-limit=8 EXCEEDANCES=0 -- eight samples measured against nothing, and a clean result.
Now pair the same rule with the unit arm. The result is byte-identical to the unit arm alone: compared=8 no-limit=0 EXCEEDANCES=0, rule passing. The mitigation was never going to help, because it is defined over coverage and coverage is perfect. Every sample was compared. Each was compared to the right limit. The comparison was simply performed on a value a thousand times too small.
A guard covers the failure it was written for. This one covers absence, and the unit shape is not an absence.
Losing the lookup key fails the other way
The limits table is keyed by pesticide and commodity together. Rename either field on the sample records and every lookup misses, so every sample falls through to the default limit of 0.01 mg/kg that the buyer set for unlisted pairs.
The result is EXCEEDANCES=7 out of eight. That is loud, wrong and safe: the two real exceedances are still in there, and five compliant consignments are rejected alongside them. Somebody notices within a day, because five growers telephone.
Renaming the table option itself produces the same seven, from the other side of the same lookup. Both directions of that arm are the safe direction -- which is a consequence of the buyer having set a strict default rather than of anything the transformation did. Set the default to nothing instead, as the library does, and the same lookup miss passes everything silently.
The uncertainty deduction, and which way it moves
Renaming either the flag that applies the measurement-uncertainty deduction or the percentage it applies produces three exceedances instead of two. The extra one is the imazalil near-miss, which fails without the deduction and passes with it.
That is the safe direction, and it is also the direction that costs a supplier a rejected load on a result that was within uncertainty of the limit. It is worth knowing it is there, because it is the one arm in this file where the failure lands on a grower rather than on a consumer.
The measurement discipline point is that both halves of the deduction -- the flag and the number -- reach the same place. Testing the union of a pair is not evidence about either half, and this series has now measured cases where a union is safer than one half, cases where it is more dangerous, and cases like this one where all three cells agree.
What the report looks like in the dangerous arm
This is the part worth reading slowly, because it is what a reviewer would actually be handed. Eight samples listed. Each with its pesticide, its commodity, its reported figure, its converted figure, its decision value and the published limit it was compared against. All eight marked compliant. A coverage line reading eight of eight. A signed statement from the buyer's own rule saying every sample was compared against a published limit.
One line in that report is wrong, and it is not in the results. It is the configuration line that reads reported-in=ug/kg -- a statement about the laboratory, sitting above a table of results, and the only place the failure is visible.
Nobody reads a configuration line to decide whether a consignment ships.
What to assert, and one design change
Assert a known exceedance end to end. Put one sample in your fixture that is over its limit by a wide margin and assert it comes back as an exceedance, in the unit your laboratory actually reports in. That fails in the unit arm and in the concentration arm, and it costs one test.
Assert the coverage separately from the outcome, as the buyer's rule here does. It catches the whole table-loss family cold.
The design change is the one this series has recommended before and it applies exactly here: never let a unit live in a different key from the number it describes. Carry the quantity with its unit, or normalise at the boundary where the result enters your system. A unit separable from its number is the entire precondition, and a hand-edited configuration file, a dropped key over a serialisation hop and a library upgrade all produce it too.
For the obfuscation part specifically: exclude the property names that cross into the screening library, and keep a test that would fail if they were not excluded. If you are documenting supply-chain controls under NIS2, that test is the artefact worth citing, not the configuration file.
Frequently asked questions
Did obfuscation on its own break residue screening?
No. All five presets produced output byte-identical to the unprotected run, across all five areas measured this pass and under a guard that refuses to compare against a fixture that will not reproduce itself.
What does losing the unit option actually do?
The library substitutes its own canonical unit. The laboratory reported mg/kg and the library assumed ug/kg, so every decision value was divided by a thousand. Two genuine exceedances read as compliant and every count stayed correct.
Would a plausibility range check have caught it?
No. A residue a thousand times smaller than reported is still a perfectly plausible residue -- smaller results are the common case. A range wide enough to accept genuine low results accepts these too.
Does requiring the number to be finite help?
It catches the arm where the concentration itself is renamed, which otherwise reports every sample compliant with a decision value of NaN. It does nothing for the unit arm, because a value in the wrong unit is perfectly finite.
Why did losing the lookup key fail safely?
Because this buyer configured a strict default limit for pairs not in the table, so every missed lookup was compared against 0.01 mg/kg and seven of eight samples were rejected. The library's own default is no limit at all, which would have passed everything.
Did the buyer's screening rule help?
Twice, and not at all in the dangerous arm. It refused the screen when the table and the default were both lost. Paired with the unit arm it passed, byte-identically, because coverage was perfect and coverage is what it checks.
What is the cheapest test that catches this?
One sample known to be over its limit, asserted to come back as an exceedance, expressed in the unit your laboratory actually reports in. A test that checks the limits table loaded passes the unit arm.
Related reading