Measured, not asserted

Does obfuscation break operating expense reconciliation?

A CAM reconciliation is not a calculation, it is a composition. Four adjustments are applied to one pool of money: drop what the lease does not let the landlord recover, gross variable costs up to a stated occupancy, add the administrative fee, and cap the controllable expenses at the negotiated increase over the base year. Every one of those steps is arithmetically trivial and completely uncontroversial. The order is not. This test renamed the option that carries the order, against a real obfuscation engine. All four adjustments still ran. Each ran exactly once. Each ran on the correct operands, over all eight expense lines, and the run reconciled. One tenant's year-end bill went up by 15,351.46.

Four steps that do not commute

The fixture is one year of a shopping centre's operating expenses: eight general-ledger lines, two of them excluded from recovery by the lease, three of them controllable and therefore inside the cap, four of them variable and therefore grossed up from the centre's actual 82% occupancy to the 95% the lease specifies. The administrative fee is 15% of the recoverable pool and lands in the controllable bucket, which is where a management fee belongs and what puts it on the same side of the cap. The controllable cap is 4% over a base of 402,000.

The lease order is exclude, grossUp, adminFee, cap. The cap is the last word: the fee is inside the ceiling. The library's default order is exclude, grossUp, cap, adminFee, which is what most platforms ship and is not unreasonable -- it treats the cap as the last word on the expenses and the fee as a service charge computed afterwards. It is simply not what this lease says.

Correct: controllable 418,080.00, non-controllable 1,176,048.78, recoverable 1,594,128.78, and against a 6.42% share and 96,400.00 of estimates already paid, TENANT-DUE=5943.07.

Rename the option that carries the order and the run produces controllable 657,199.32, recoverable 1,833,248.10, TENANT-DUE=21294.53. The fee escaped the ceiling. Across the building that is the fee on the capped amount, 239,119.32 of it.

Everything a reconciliation report checks is identical in both runs

This is the part that makes the shape worth writing about. The tenant's own reconciliation rule in the fixture is the rule anybody would write: every expense line must have been considered, and every configured adjustment must have been applied. In the correct run it prints recon-check(8 of 8 expense line(s) considered, 4 of 4 adjustment(s) applied). In the reordered run it prints the same sentence, word for word.

It cannot do anything else. Both runs consider eight lines of eight. Both apply four adjustments of four. Both name the same four adjustments. Both exclude the same two lines. foots=true in both, because every dollar of the recoverable pool is either billed to this tenant or carried by the other shares and that is true whatever the pool turns out to be.

The step trace does differ -- the correct run prints adminFee(242107.32) -> cap(418080.00 binding, cut 262027.32) and the failing one prints cap(418080.00 binding, cut 19920.00) -> adminFee(239119.32) -- but that is a diagnostic display, not an assertion, and nothing in the file compares it to anything.

Switching the rule off changes nothing at all. ^(requireReconCheck|adjustmentOrder)$ and ^(reconRule|adjustmentOrder)$ both produced output byte-identical to renaming the order alone: the same 21,294.53. The rule was contributing nothing to remove, because it is defined over population and count, and the order disturbs neither.

Whether the order matters at all is a property of the year, not of the pipeline

The fixture runs two years through the same configuration, and the second one is the negative control for the whole experiment. 2025 is a lighter year: the same eight categories, the same four adjustments, the same order -- but the controllable pool never reaches the ceiling.

In that year the reordered run is TENANT-DUE=13327.90, identical to the correct run to the cent. The cap does not bind, so the last two steps commute, so the order is invisible.

That is the uncomfortable half of this finding and it generalises far past obfuscation. A test suite built on a normal year cannot see this class of defect at all, because in a normal year the two orders agree. The years in which the composition order is observable are exactly the years in which the cap binds, which are the expensive years. Put a binding cap in the fixture or the entire class is invisible by construction.

The same answer from four different names, and the opposite answer from three more

The cap is reachable from several directions and they all arrive in the same place. Renaming the cap percentage, renaming the base amount it is measured against, renaming both together, and renaming the controllable flag that decides which expenses are inside the cap at all -- four different patterns -- each produced TENANT-DUE=22765.22. The cap simply stops binding.

Gross-up goes the other way and is reachable from three. Renaming the gross-up target, renaming it together with the occupancy it is measured from, and renaming the variable flag that decides which lines are grossed up each produced TENANT-DUE=1831.14. Renaming the occupancy alone produced 534.30. Those are the under-billing direction: the landlord recovers less than the lease allows, and the only party who would notice is the one being under-charged.

The exclusions are the quietest cell. Renaming the whole category table produced 38413.58 -- the tenant now paying a share of a 240,000 capital item and an 88,000 leasing commission the lease excludes outright. Renaming only the two excluded category keys produced 27000.67, and renaming the recoverable flag inside every entry produced exactly the same number by a completely different route. Renaming just the single narrowest key, capital, produced 21351.07: one line item, silently recovered, in a run that is otherwise correct.

Renaming the record field each line is classified by, category, reached 38413.58 -- byte-identical to losing the whole option. The option side and the record side arrive at the same answer, which is a pattern this series has now measured in five consecutive domains. If you are mapping this onto financial-reporting controls generally, our SOX and GLBA notes cover where the client-side half of that sits.

The number fails closed; the meaning fails open

One arm in this area is loud, and it is the one that matters least. Renaming amount, the number on each expense line, produced recon-check(the reconciled total is not a number) and the reconciliation was refused before anything was billed. Nothing is quieter than a value that cannot be read: the arithmetic stops.

That contrast has now held for twenty-one consecutive failure shapes in this series. Lose the VALUE and the system refuses. Lose the MEANING -- which category a line belongs to, which order the adjustments compose in, which side of the cap the fee lands on -- and the system produces a confident, well-formed, fully reconciled answer that is wrong.

Renaming the line code was inert, as was the pinned money label. Not every field on a record is load-bearing, and guessing which ones are is what the measurement replaces.

What to change, whether or not you obfuscate

Assert the composition, not the population. Every check in this fixture is defined over items and counts, and every one of them passes in every arm above. An assertion that would have caught it is arithmetic on the result: the capped controllable total must equal the ceiling exactly when the cap binds, and the administrative fee must be inside it. Write the invariant the lease actually states, not the invariant that the pipeline ran.

Make an unreadable or unspecified adjustment order an error rather than a fallback to the vendor's. A library's default order is a reasonable guess about a lease it has never seen; it should never be the silent answer when the caller intended to specify one.

Put a binding cap and a binding gross-up in the fixture. If the test year is a year in which no clamp is active, every ordering of the pipeline gives the same number and the suite is blind to this whole class by construction.

And if you use member renaming, keep the pattern narrow and explicit, and keep the option object that carries pipeline structure out of it entirely. Renaming identifiers, strings and control flow is unaffected by any of this.

How this was measured

Five commercial-real-estate 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 five areas produced output byte-identical to the unprotected run on all five presets, twenty-five for twenty-five. Protection on its own changed nothing, which is the finding that lets the rest of the article be about renaming specifically.

The member-renaming column is sixty-nine patterns run on two presets, one hundred and thirty-eight verdicts. One hundred and twenty-eight moved the output; ten did not, and all ten are the five arms deliberately pinned equal to the library's own default, measured on both presets. Nothing threw, nothing was vacuous, and the ES5 and modern targets agreed on every arm.

Before any of that, every option key and every record field in the fixture was deleted in the unprotected world to confirm it changes the answer at all. Ninety arms plus one union arm, zero structurally blind on the first run. An arm that cannot move is not evidence of safety.

Every figure quoted above came from executing the protected artifact and reading the fields that decide the outcome, not from a diff summary.

Frequently asked questions

Did obfuscation on its own break the reconciliation?

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 with a pattern that reached the names the reconciliation is made of: the option carrying the adjustment order, the category table and the flags inside it, the cap and its base, and the record field each expense line is classified by.

How can every adjustment run and the answer still be wrong?

Because the four adjustments do not commute. A cap applied after the administrative fee is a ceiling on what the tenant pays; a cap applied before it is a ceiling on something else and the fee is charged on top. Same steps, same operands, same count, different money.

Why did the reconciliation check not catch it?

It is defined over population and count -- every line considered, every adjustment applied -- and the reordering disturbs neither. It printed 8 of 8 expense lines and 4 of 4 adjustments in both runs, word for word.

Would a lighter expense year have shown this?

No, and that is the sharp part. In the fixture's light year the cap never binds, the last two steps commute, and the reordered run is identical to the cent. The order is only observable in the years the cap binds, which are the expensive years.

Which arm was loud?

Renaming the numeric amount on each expense line. The total became non-numeric and the reconciliation was refused before anything was billed. Losing a value fails closed; losing a meaning fails open.

What is the safest way to use member renaming here?

Keep the pattern narrow and explicit and exclude any options object that carries pipeline structure, category tables or thresholds. Renaming identifiers and control flow is unaffected by all of this.

Related reading