Measured, not asserted

Does obfuscation break roaming and fair-use limits?

Two names decide what a roaming session costs and neither of them is a quantity. The zone table says which commercial band the session is priced in; the data unit says what every usage figure means. A unit is not a number -- it is the statement that gives the numbers their meaning -- and it is separable from the numbers it describes, sitting one key away in the same configuration object. This test renamed both against a real obfuscation engine. One of them was caught cold by the operator's own check. The other took the run's revenue down by 99.9% and switched off the fair-use control, while every figure printed stayed finite, plausible and inside any range a reviewer would think to bound.

A number in the wrong unit is a perfectly good number

The fixture meters eight roaming sessions across five countries against three commercial zones. The operator records usage in megabytes; the metering library's canonical unit is kilobytes, and the operator says so with a single configuration key. Correct answer: all eight sessions priced in a published zone, two of them past a fair-use allowance, four throttled, 802.38 charged.

The zone table and the unit sit in the same object, three lines apart. They fail completely differently.

Rename the unit and the library assumes the figures it was handed are already canonical. A 3,120 MB session in Japan is read as 3,120 KB -- about three megabytes. The run reports OVER-FAIR-USE=0 THROTTLED=0 TOTAL-CHARGED=0.74 against a correct 802.38. Nobody exceeded anything. Nobody was throttled. The operator's own usage rule prints usage-check(8 of 8 session(s) priced in a published zone), which is entirely true and entirely beside the point.

Every number on that output line is finite. Every number is plausible for a small session. A range check on usage would pass. The standard mitigation for a lost numeric field -- require it to be finite before comparing it -- is structurally blind here, because a quantity in the wrong unit is not a broken number.

Losing the value fails closed; losing its meaning fails open

One field away on the same record sits the usage figure itself. Rename it and the run is refused: non-finite-usage(refused before metering). Undefined enters the arithmetic, propagates as NaN, and the library's own finiteness guard stops the whole thing before a bill is produced.

So the two adjacent names fail in opposite directions. The number fails closed and loud; the unit that says what the number means fails open and silent. The severity of the open direction is the conversion ratio, and the ratio was chosen by the library vendor, not by the operator: kilobytes to megabytes is 1,024, and there is nothing the caller can do about it.

Renaming both together also refuses, which is the same masking effect this series has measured repeatedly -- a loud failure in front of a quiet one hides the quiet one. Test the halves.

The same check catches one route cold and is blind to the other

The operator's usage rule refuses any run in which a session was priced on the library's default zone rather than a published one. It is a good rule and it works.

Rename the zone table and the run is refused. Rename the country code on the session records and the run is refused. Rename only the quoted keys of the three expensive countries -- so that the cheap zone-one traffic is untouched and only the zone-three sessions fall to the default -- and the run is still refused. Three independent routes to the zone failure, all three caught.

That same rule, in the unit arm, prints a passing sentence. It is not a weak rule; it is a rule about a different quantity. Coverage was never disturbed by the unit, so pairing the rule with the unit rename produced output byte-identical to the unit rename alone -- and so did replacing the rule with the library's builtin. The mitigation is exactly as effective switched on as switched off, for the same reason as in a rate deck: it is defined over something the failure does not touch.

A name that is a value in one table and a key in another

One arm is worth reporting because it shows that a rename pattern matches names, not roles. The zone identifiers appear twice in the configuration: as string values in the country-to-zone table, and as keys in the allowance table.

Rename them and the country table is untouched -- string values are data, not member names -- so every session still maps to a zone and the coverage rule reports eight of eight in a published zone. But the allowance lookup now misses every entry, so there is no included allowance, no fair-use ceiling and no rate. TOTAL-CHARGED=0.

The run reports a fully covered, fully zoned, entirely free month. This is the same shape as the rate deck's specificity failure arriving from the opposite direction: the configuration screen shows entries exist, never that anything finds them.

The money can be right while the policy control is dead

The allowance entries carry three separate numbers and they are not interchangeable. Renaming the fair-use figure left TOTAL-CHARGED=802.38 -- exactly correct, to the cent -- while OVER-FAIR-USE went from 2 to 0 and THROTTLED from 4 to 0. The figure finance reconciles is right. The control that exists to stop a subscriber consuming an unbounded amount of somebody else's network is simply not there.

Renaming the included allowance produced the mirror: the fair-use control fires correctly on the right two sessions and four subscribers are throttled exactly as they should be, and the bill is zero. Renaming the per-megabyte rate gives a NaN total, which is loud. Renaming the throttle threshold leaves everything correct except that nobody is throttled.

Four numbers, one object, four different answers. Which of them is dangerous is not a property of how important the name sounds -- fair use sounds like the important one and it is the arm where the invoice is perfect.

There is a data-protection edge to this too. Roaming records are location data about identifiable subscribers, and a metering run that silently reads them in the wrong unit is still processing them; our GDPR notes for JavaScript front ends cover where that sits.

What to change, whether or not you obfuscate

Never let a unit live in a different key from the number it describes. Carry the quantity with its unit as one value, or normalise at the boundary where usage enters the system, so there is no configuration key whose loss can silently rescale everything. This is the single highest-value change here and it is worth making regardless of obfuscation, because a hand-edited config, a dropped key over a serialisation hop and a library upgrade all produce the identical failure.

Publish a coverage figure defined over the result rather than the configuration. "Eight of eight sessions priced in a published zone" is a statement about the lookup; "the largest session this month was 13.5 GB" is a statement about the data, and only the second one moves when the unit does.

Assert an expected order of magnitude on aggregate consumption. Total canonical kilobytes for the run is a number your network operations team already knows independently, and comparing the two catches a 1,024-fold rescale instantly.

Test the halves of every option pair, not just the union. Renaming the unit and the usage figure together refuses loudly; renaming the unit alone does not. The dangerous cell was at the narrow end.

How this was measured

Five telecommunications areas were driven through the real obfuscation engine on five presets -- the ES5 default, the modern target, the emit gate's option set on both targets, and the string transforms. All twenty-five combinations produced output byte-identical to the unprotected run.

The member-renaming column is ninety-six patterns on two presets: one hundred and ninety-two verdicts, one hundred and seventy-eight of them moving the output. The fourteen that did not are the seven options pinned equal to the library's own default, measured twice. Two of those seven are in this area -- the default zone and the usage label -- and both were predicted inert before the run and measured inert, which is the prediction holding rather than a blind arm.

Every option key and record field was first deleted in the unprotected world to prove it changes the answer at all, ninety-two arms in total, with no structurally blind arms left by the time the renaming column was run.

All figures were read by executing the protected artifact and reading the whole line.

Frequently asked questions

Did obfuscation on its own break roaming metering?

No. Five presets -- the ES5 default, the modern target, the emit gate's option set on both targets, and the string transforms -- all produced output byte-identical to the unprotected run across all five areas measured this pass.

What actually broke it, then?

Member renaming reaching the key that declares what unit the usage figures are in, the zone table, or the individual numbers inside the allowance entries.

Why is a lost unit worse than a lost number?

A lost number becomes NaN and the library's finiteness guard refuses the run loudly. A lost unit leaves every number finite and plausible and simply rescales them, in this case by a factor of 1,024, so nothing looks wrong.

Did the operator's own coverage check help?

It caught the zone failure cold, three different ways. It was completely blind to the unit failure, and pairing it with the unit rename was byte-identical to the rename alone.

Which allowance field is the dangerous one?

Not the one that sounds important. Renaming the fair-use figure left the invoice correct to the cent and silently switched off throttling entirely; renaming the included allowance left throttling correct and made the invoice zero.

What is the fix?

Keep a quantity and its unit in one value, or normalise at the boundary where usage enters. A unit that is separable from its number is the entire precondition for this failure.

Can I still obfuscate a charging engine?

Yes. Keep configuration objects and lookup tables out of member-renaming patterns; identifier renaming, string encoding and control-flow transforms are unaffected.

Related reading