Measured, not asserted

Does obfuscation break rate index effective dates?

Every failure shape this series has measured ends in a value that is missing, unreadable, implausible, or drawn from the wrong set of records. A published rate table offers none of those. Every row in it is real, and that turns out to be the problem.

A reset is a lookup, not a calculation

When an adjustable-rate mortgage resets, the note does not ask the servicer to compute anything clever. It says: take the value of the named index that was in force a stated number of days before the reset date, add the margin, round to the nearest eighth, and let the caps trim the result. The arithmetic is three operations. The lookup is the whole of it.

The sample here holds five genuine publications of one index across four years -- 0.030%, 2.190%, 5.310%, 4.640% and 4.330% -- and two loans that reset on the same day. Loan A's periodic cap binds on this reset; loan B's does not. Two loans, on purpose: this series learned last pass that masking is a property of a record and not of a file.

Correctly configured, the engine selects the 1 November 2024 publication at 4.640%, adds the 2.75% margin, rounds 7.390 to 7.375, and reports: loan A capped to 6.875% and loan B left at 7.375%. Protection alone, across five presets, changed none of it.

Renaming the date sent both loans down two points

effectiveFrom is a field on the index rows, so unlike an option key it genuinely can go missing. When it does, no row can be dated, no row can be established as in force, and the engine does what a rate engine has to do rather than returning nothing: it falls back to the first entry in the series, its initial published value.

That value is 0.030%. It is not an error, not a placeholder and not a corrupted read -- it is what the index actually was in March 2021. Adding the margin gives 2.780, rounding gives 2.750, and the periodic caps then trim both loans up to their floors. Loan A reset from 4.875% to 2.875%. Loan B reset from 6.750% to 4.750%.

Read the two output lines and there is nothing to see. Both say capped(periodic -2.00), which is true. Both say checked by published-range-check(0-15%), which is also true. Two loans that between them were producing $48,090 a year of interest now produce $24,575, and every figure on the screen is a real number that the system arrived at correctly.

The check that could not fail

The servicer in this sample runs the defence that the previous round of these measurements concluded was the cheapest available: a bound on what values are plausible. It refuses any index value outside the range the series has actually published, nought to fifteen per cent.

It accepted 0.030% without hesitation, and the arm that proves the point is the one where both the field and that check were renamed together. The rates came out byte-identical to the arm where only the field moved. The bound made no difference at all, because it could not have.

This is what makes a wrong-row failure different in kind. A plausibility bound works by asking whether a value could be real. Every row of a published series IS real. The bound is satisfied by construction, not by luck, and no amount of tightening helps: narrowing the band to something like three-to-eight per cent would have refused the correct 4.640% in a year when rates were low, and would still have accepted a wrong row from any year when they were not.

The option side, and the cap that hid it

The other half of the same concept is the option key. lookbackDays says how far back to look; the note says forty-five days and the library's own default is zero. Renaming it moved the selection from the 1 November 2024 publication to the 1 June 2025 one -- 4.640% to 4.330%, both genuine.

On loan B that is a real difference: 7.375% became 7.125%, about $670 a year. On loan A it is not a difference at all. The result was 6.875% either way, because the periodic cap binds and trims both candidates to the same ceiling. One loan was affected and one was completely masked, from a single lost name in a single file.

So a spot check on one loan proves nothing about the next one, and which loan you happen to check is decided by whether its cap binds -- a property of that borrower's rate history, not of your code. The cap arm itself is worth noting too: renaming periodicCapPct alone moved loan A up to 7.375% and about $2,060 a year in the other direction, and combining it with the date field sent both loans all the way to the 2.750% lifetime floor.

What failed loudly, and what to do about it

The honest negatives are clear. Renaming ratePct, the index number itself, produced non-finite-index(refused before reset). Renaming the margin produced non-finite-fully-indexed(refused before reset). Renaming series, the key that selects the table at all, produced no-such-series(SOFR-30A). Renaming the current note rate threw a TypeError before any money moved. Every one of those is loud, immediate and safe.

One arm was neither. Renaming balanceUsd produced reset(...) on $undefined = $NaN USD/yr with the reset reported successful: the engine checks that the index is finite and never checks the interest it computes from it. Guard the number you are about to act on, not only the number you read in.

The mitigation is a design point and it is worth having whether or not you obfuscate anything, because a dropped key over a serialisation hop or a hand-edited fixture produces the same miss. Make a selection that cannot be dated an error rather than a fallback: refuse to reset a loan when no row can be established as in force, rather than reaching for the first row in the table. Then check the selection itself -- assert that the row applied is the row the note points at -- because checking the value it carries can only ever tell you that the value is a real one, and every row in the table is.

Frequently asked questions

Does obfuscation change how a rate reset is calculated?

Not on its own. Across five presets and five areas measured this pass, protection alone left every output identical -- twenty-five comparisons, no differences. What changed behaviour was member renaming, a separate opt-in option whose pattern you write yourself.

What actually went wrong in the measured case?

Renaming the field that carries each index row's effective date meant no row could be established as in force, so the engine fell back to the first published value in the series -- 0.030%, a genuine rate from 2021. Two loans reset to 2.875% and 4.750% instead of 6.875% and 7.375%.

Why did the plausibility check not catch it?

Because it could not. That check asks whether a value could be a real published rate, and 0.030% is one. Measuring the arm with the check switched off produced byte-identical rates, which is the proof: the bound was satisfied by construction rather than by luck.

Could a tighter range have caught it?

No. Narrowing the band enough to exclude 0.030% would have refused correct values from any low-rate year, and would still accept a wrong row drawn from a high-rate one. Every row in a published series is plausible, which is what makes this different from a missing or non-finite value.

Was the damage visible in the output?

Not in any way a reviewer would notice. Both loans reported a capped periodic adjustment, which was true, and both reported that the value had passed the range check, which was also true. The rates were ordinary mortgage rates.

Does checking one loan tell you about the others?

No. Renaming the lookback option changed loan B by about $670 a year and left loan A byte-identical, because loan A's periodic cap binds and trims both candidate rates to the same ceiling. Which loan reveals the fault depends on that borrower's rate history, not on your code.

What is the practical mitigation?

Make an undatable selection an error rather than a fallback to the first row, and assert which row was applied rather than only whether its value looks sensible. Then keep option keys and record fields that an installed library reads out of your rename pattern.

Related reading