Cold Chain

Does obfuscation break cold chain delivery rules?

A temperature band looks like two guards on one line and it is nothing of the sort. This pass protected a cold-chain acceptance engine and renamed its property names a group at a time. Losing the lower bound signed for a vaccine that spent over three hours below freezing, while the upper bound went on reporting perfectly. And the two fields that looked safest in the whole file turned out to be safe only because of how the test data was built.

The payload, and the four rules protecting it

The sample decides whether a temperature-controlled delivery may be signed for and enter usable stock. A band of two to eight degrees defines the acceptable range. Excursions outside it are summed, and a budget of sixty minutes tolerates brief ones. Delivery windows are defined per service. A temperature log is required, and the depot's own verifier checks the logger's seal and the continuity of its record.

Unprotected, six hours between four and five degrees is signed for. A vaccine that spent 200 minutes at minus three is refused. One that spent 180 minutes at nineteen degrees is refused. A twenty-five minute excursion to eleven degrees is inside the budget and signed for. A midnight pharmacy delivery is refused by the window rule, a broken logger seal by the verifier, and a ninety-minute hole in the record by the same verifier's continuity check.

Every figure in this article is one a protected sample printed.

A two-sided band is not defence in depth

Renaming minTempC alone signs for the frozen vaccine. The configuration prints the band as (none) .. 8C, the 200 minutes at minus three are no longer counted as an excursion at all, and the acceptance line reads excursion=0 min worst=none. The cooked shipment in the same run is still correctly refused, because the upper bound is intact.

Renaming maxTempC alone is the mirror image: the shipment that spent three hours at nineteen degrees is signed for, the frozen one is still refused, and the band prints 2C .. (none). Renaming both signs for everything.

It would be easy to file this alongside the redundancy findings in this series, where two layers guard the same case and each alone holds. This is not that shape, and the difference is worth being precise about. The two comparisons guard disjoint cases: a frozen vial and a cooked vial are different accidents. So there is no redundancy to fall back on and no masking to detect -- each half has its own victim, and the surviving half keeps reporting correctly about the cases it can still see. Two comparisons on one line look like two guards and behave like two independent single points of failure.

The quietest arm prints the evidence in the acceptance

Renaming maxExcursionMinutes is the arm I would least expect anybody to find. The band is intact. The excursion is detected. The duration is measured. The worst temperature is recorded. All of it is printed -- excursion=200 min worst=-3C -- inside the line that says the shipment was signed for.

Nothing is missing and nothing is wrong except the comparison that was supposed to act on it. The budget reverted to the library default of none, so any excursion is tolerated, and a payload that spent over three hours below freezing entered usable stock with a complete and accurate record of having done so.

That is the failure mode this series keeps finding most dangerous, and here it is in its clearest form: the telemetry is not lying, it is not degraded, and it is not silent. It is fully correct, and it is filed under acceptances. Any monitoring built on 'do we have temperature data' answers yes. Only monitoring built on 'were any excursions refused' would notice.

Renaming tempC, the reading field itself, is the opposite: no excursion is detected at all, so the record is not merely mis-acted-upon but empty. Everything is signed for with excursion=0 min worst=none, including the shipment that spent three hours at nineteen degrees.

The two fields that were safe only because of the test data

Two arms in this file measured no change at all on either target: the logger's sealBroken flag and its gapMinutes count. Both had already been shown to matter -- deleting either one changes the outcome -- so neither was a dead branch. They measured unchanged because the depot's own verifier is the only thing that reads them, and it lives in the same file that writes them. A rename moved the write and the read together, so the comparison was truthful and told me nothing.

A logger record does not arrive in code. It arrives as text from the scanner, the courier API or the depot's own database, and is parsed. So I built the identical records both ways in one file -- one set as object literals, one set parsed from JSON -- with the same verifier, the same options and the same readings, and renamed the same two fields.

The in-code records stayed correctly refused, which is the control that makes the rest of it readable. The parsed records were signed for. A logger whose seal was broken in transit entered usable stock; so did the one with a ninety-minute hole in its record. Byte-identical on both targets. The arm that looked safest in the whole file was the second-worst result in it, and the only reason it looked safe was that my test data was built in the same file as the code reading it.

The log requirement, and a refusal that says the logger was fine

Renaming requireTempLog accepts both logger faults: the broken seal and the ninety-minute gap are both signed for, because the flag in front of the verifier is consulted first and the verifier is never reached. Renaming logVerifier replaces it with the library's built-in, which believes the log, and produces the same two acceptances. The union is identical to the flag alone.

Renaming intact, the field the verifier answers in, fails closed and produces the inverted line: every delivery is refused with temperature-log-rejected(logger-sealed-and-continuous). The reason describes a healthy logger and the delivery is rejected on the strength of it.

Renaming deliveryWindows is the ordinary case for completeness: the midnight pharmacy delivery is signed for. That one is at least the kind of thing an operations team notices, because deliveries start being accepted at hours nobody staffs.

What protection alone did, and what to do about it

Nothing. The file was protected on five profiles -- the ES5 default, the modern target, both emit-gate configurations and the string-encoding profile -- and produced byte-identical output on all five. Every acceptance and refusal matched exactly. Renaming identifiers and encoding strings does not disturb an acceptance engine.

Every result above required member renaming, which is off by default and needs a regular expression naming the members it may rewrite. Keep that pattern anchored to names your own code owns on both sides -- and note what the follow-up above showed about that rule. A name your code owns on both sides is safe inside the process, and stops being safe the moment the record arrives from outside it. Test with data in the shape production actually delivers.

Then assert refusals with their reasons, on both sides of the band. Take the frozen payload and the cooked payload and assert that each is refused, that the excursion minutes are the ones you expect, and that the band printed in the decision is the band you configured. A suite that checks only that compliant deliveries are accepted passes in every arm in this article.

Frequently asked questions

Does obfuscating a logistics app change which deliveries are accepted?

Not by itself. The sample was protected on five profiles including the ES5 default, the modern target and string encoding, and produced identical decisions on all five. Every result in this article required member renaming, which is off unless you enable it and supply a pattern.

Is a two-sided temperature band a form of defence in depth?

No. The two comparisons guard different accidents -- a frozen payload and a cooked one -- so neither backs the other up. Renaming the lower bound signed for a vaccine that spent 200 minutes below freezing while the upper bound went on reporting correctly about shipments it could still see.

What was the quietest failure measured?

Losing the excursion budget. The band still worked, the excursion was detected, and the acceptance line printed excursion=200 min worst=-3C -- accurate, complete, and filed as a shipment signed for. Monitoring that asks whether temperature data exists answers yes.

Why did two logger fields appear unaffected by renaming?

Because the verifier reading them lived in the same file that wrote them, so the rename moved both sides together. Rebuilding the identical records as parsed JSON, which is how they actually arrive, showed a broken logger seal and a ninety-minute record gap both being signed for.

Does that mean self-owned property names are safe to rename?

Only while both the write and the read stay inside the protected file. As soon as the record arrives from a scanner, an API or a database, only the read moves, and the check silently stops matching. Test with data in the shape production delivers, not data built in the same file as the code.

What does temperature-log-rejected(logger-sealed-and-continuous) mean?

A rename. The verifier ran, found the logger healthy, and the engine read its verdict out of a field whose name had moved, so every delivery was refused with a reason describing a healthy logger. A refusal whose reason asserts success is a rename signature.

What should a cold-chain test suite assert?

Refusals with their reasons on both sides of the band: the frozen payload and the cooked payload each refused, with the excursion minutes and the configured band asserted exactly. Checking only that compliant deliveries are accepted passes in every arm above.

Related reading