Measured, not asserted

Does obfuscation break contribution limit enforcement?

An excess deferral has to be refunded by April 15 or the participant is taxed on it twice and the plan's qualified status is at risk. The limit that produces it is two numbers on one object, and in this test they failed in opposite directions: losing the catch-up age manufactured a $6,900.00 excess for somebody who was comfortably inside their limit, and losing the annual limit alongside the check in front of it made a real $1,800.00 excess vanish. Renaming all three at once produced a clean, loud refusal -- which is why the widest pattern is the one that shows you the least.

Two caps, one object, opposite defaults

The statutory limit on elective deferrals has two parts. Everybody gets a base limit. Participants who reach 50 during the plan year get catch-up room on top of it. The fixture uses $23,000 and $7,500, so a 46-year-old's cap is $23,000 and a 57-year-old's is $30,500.

P-51204 is 46 and deferred $24,800.00 across three payroll periods: a $1,800.00 excess that must be refunded. P-51391 is 57 and deferred $29,900.00: inside the limit, nothing owed.

The limit engine is copied in unprotected. Its defaults are the ones a library ships when it has not been told a plan's numbers, and they do not all point the same way. The annual limit defaults to infinity, which is permissive: no cap, so no excess. The catch-up age defaults to infinity too, which is restrictive: nobody ever qualifies. Two options, one object, opposite directions.

Protection on its own moved nothing

Twenty-five comparisons across five areas and five presets, every protected run byte-identical to the unprotected one. Everything below required member renaming reaching a name the installed engine reads.

An excess that was never deferred

Renaming the catch-up age reverts it to infinity, so the 57-year-old is no longer catch-up eligible and their cap drops from $30,500 to $23,000. The result: age=57 deferred=$29900.00 cap=$23000 refund=$6900.00 => EXCESS DEFERRAL, REFUND DUE BY APRIL 15.

That participant deferred a lawful amount and the plan is about to send them $6,900.00 back, with the tax reporting that goes with it. And the check passed: checked by cap-check($29900.00 against a $23000 cap at age 57). The age is printed, correctly, immediately next to the cap that ignored it.

Renaming the catch-up amount rather than the age produces the identical $6,900.00, by the other route. So does renaming the participant's age on the record, which reads age=undefined and reaches the same figure. Three distinct names, one wrong refund.

None of these is catastrophic in isolation -- a refund of money the participant was entitled to defer is recoverable, and somebody will complain. It is the direction the plan's own defaults happen to push, and it is the loud half of this area.

The quiet half, and the pattern that hides it

Renaming the annual limit on its own is caught. The plan's rule refuses to certify a year whose deferral total was not compared against a finite cap, and it says so: year-rejected(cap-check(the plan has no finite annual limit, so no excess could have been computed)).

Rename it together with the flag that enables that rule and the refusal is gone: deferred=$24800.00 cap=$Infinity refund=$0.00 => WITHIN THE ANNUAL LIMIT, unchecked. The $1,800.00 excess is not reported, not refunded, and not visible. The participant carries a deferral the statute does not allow into their tax return, and the plan carries an operational failure into its next audit.

Now the part that changes how you should read any matrix like this one. Renaming the annual limit and the catch-up age together is behaviourally identical to renaming the annual limit alone: a clean, loud rejection. So is renaming all three caps at once. The dangerous cells are not at the wide end.

That is the practical consequence. Had this area been probed only with the broad, realistic "rename the whole options object" pattern, it would have produced a refusal on every account and looked like a fail-safe design. Both real failures -- the invented refund and the vanished one -- appear only under narrower, more careful, better-intentioned patterns.

What failed loudly, and one NaN that costs nothing

The deferral amounts themselves failed closed. Renaming the per-period deferred amount produced non-finite-deferral(refused before the cap test), because those amounts accumulate into a total the engine checks for finiteness before it compares anything.

One arm is a genuine non-event and is included because half of reading a matrix honestly is naming the arms that do nothing. Renaming the pensionable compensation field prints countable-comp=$NaN and leaves both verdicts and both refund amounts exactly correct. The figure is displayed, it is visibly broken, and no decision in the file depends on it.

Renaming the payroll period number is the same class: periods=[undefined/undefined/undefined] with the money untouched. The excess is right and the record of which periods produced it is gone. These are the arms a reviewer greping for undefined will find, and they are not the ones that matter.

What this means if you protect a payroll or benefits front end

Keep member renaming off the boundary: a MemberRegexp matching your internal names and excluding every option key and record field an installed library reads. That is the whole mitigation for the mechanism.

Then test the halves. A matrix that only ever renames whole objects will report this area as safe, because the widest pattern here produces the loudest refusal. Probe each option on its own, and probe each one paired with the flag in front of your own check, because that pair is where the silent results live.

Finally, phrase the check so it cannot be skipped by the thing it is checking. A rule sitting behind an enabling flag that can be lost by the same pattern is not a control, it is a control-shaped comment. Certifying a year is exactly the kind of assertion FedRAMP and CMMC controls for JavaScript expect to be evidenced rather than assumed, and the protected build certified both participants correctly on all five presets.

Frequently asked questions

Did obfuscation change any contribution limit result on its own?

No. Twenty-five comparisons across five areas and five presets, all byte-identical to the unprotected run. Every failure required member renaming reaching a name the installed limit engine also reads.

How did losing the catch-up age hurt somebody who was inside the limit?

It reverted to a default under which nobody is catch-up eligible, so a 57-year-old's cap fell from $30,500 to $23,000 and the plan reported a $6,900.00 excess deferral requiring a refund. The participant's age printed correctly on the same line as the cap that ignored it.

What made a real excess disappear?

Renaming the annual limit together with the flag enabling the plan's own cap check. The limit reverted to infinity, no excess could exist, and a genuine $1,800.00 excess deferral read WITHIN THE ANNUAL LIMIT. Renaming the limit alone was refused outright.

Why does the widest rename pattern look safest here?

Because the annual limit is consulted first and its loss produces a loud refusal. Renaming every cap at once is behaviourally identical to renaming the annual limit alone. Both genuine failures show up only under narrower patterns, which is why halves have to be tested and not just unions.

Which names failed safely?

The deferral amounts. They accumulate into a total the engine checks for finiteness, so renaming them refused the whole certification before any cap was consulted.

Were there arms that changed nothing?

Yes. Renaming the pensionable compensation field printed a NaN on the statement and left both verdicts and both refunds exactly right. Renaming the payroll period number blanked the period list and touched no money. Neither affects a decision.

What is the cheapest test that would have caught this?

Certify two known participants -- one over the base limit, one relying on catch-up room -- and assert both refund amounts to the cent. That fails in every dangerous arm here, including the ones a whole-object rename pattern hides.

Related reading