Measured Behaviour
Published
A change penalty is a table lookup followed by an arithmetic choice. The two fail in opposite directions and one of them leaves a penalty engine that charges a penalty on every ticket, correctly, on the smaller of two numbers.
Sixty tickets on a storm day
The measured batch is sixty tickets moved on one December day after a hub closed. Four published fare families, a fallback rule for codes a tariff amendment added after the build shipped, a waiver code the carrier announced publicly, and the ordinary asymmetry of a storm day: the seats left are the expensive ones, so the difference between the old fare and the new one is usually larger than any published fee.
Correct, the batch collects 13,486.00 dollars. Of that, 12,680.00 is fare difference and 806.00 is published change fees. Twenty tickets carry the waiver and are changed free, twelve are on an amended code and take the carrier's 199-dollar fallback, and 835.00 is refunded on cancellations.
None of the arms below changes a published fee, a fare, a tax or a ticket. Every one of them leaves the four fare families printed correctly on the configuration screen.
The arithmetic choice: a working penalty engine that under-collects
penaltyBasis decides whether the passenger pays the published fee, the fare difference, or the greater of the two. The carrier's setting is the greater of the two. The library's default is fee only, because collecting a fare difference is a commercial decision a library cannot make for you.
Renaming it collects 4,816.00 instead of 13,486.00. The fare-difference line goes to 0.00. Every other figure on the report is unchanged to the cent: the same sixty tickets, the same twenty waivers, the same twelve amended codes, the same 835.00 refunded.
What makes it survive is that a penalty is still charged. Thirty tickets pay a published fee, the engine reports doing so, and the carrier's own reissue rule passes. Nothing about the run looks like a disabled penalty engine, because the penalty engine is not disabled. It is collecting the smaller of two numbers on every ticket where the two differ.
The same object, the other direction
waiverCodes is the list of storm codes the carrier announced it would honour. Renaming it empties the list, so the waiver is not recognised and those twenty passengers are billed.
Measured: 19,149.00 collected against 13,486.00, and waived goes from 20 to 0. That is 5,663 dollars charged to passengers the carrier publicly promised not to charge, during a weather event, on tickets it had already announced a policy for.
One options object, two adjacent lines, and the two failures point in opposite directions. The under-collection is discovered by a revenue accountant reconciling a month; the over-collection is discovered by customers, in public, within hours. Renaming the waiverCode field on the ticket records reaches the identical 19,149.00 from the other side of the boundary.
A lookup that cannot miss
fareRules is the table itself, keyed on fare basis code. A code the table does not carry is not an error -- tariffs are amended constantly and a booking engine that threw on an unknown code would stop selling -- so an unfound code takes the fallback rule.
Rename the table and every ticket is unfound: RULE-NOT-FOUND goes from 12 to 60. Collections actually rise slightly, to 14,232.00, because the flat fallback fee is higher than two of the four published fees. The real damage is elsewhere: refunds collapse from 835.00 to 336.00, because a fare with no rule found is not refundable under this carrier's fallback, and five cancelled tickets that should have had their fare returned got taxes only.
Renaming the fareBasis field on the tickets produces the same numbers by the other route -- the sixth consecutive pass in this series in which an option key and the record field it reads reach one answer.
A guard that stops the desk, and a pair that costs nothing
defaultChangeFeeUsd is the fallback fee for amended codes. The carrier's own reissue rule refuses a batch in which an unfound ticket could be changed for nothing, so renaming that option refuses the whole batch. The reissue desk stops. That is loud, immediate and expensive in its own way.
Now switch the rule off as well. Rename requireFareCheck and defaultChangeFeeUsd together and the result is byte-identical to the correct run on every money figure: 13,486.00 collected, 12,680.00 of it fare difference, 835.00 refunded.
The reason is worth more than the result. The fallback fee never actually binds on this batch, because the fare difference is larger than 199 dollars on every amended-code ticket, and the greater of the two wins. The guard was refusing a configuration whose money impact was zero.
That is the reverse of the usual pattern, where a quiet option switches off a loud one and the pair is the silent disaster. Here the half alone is the outage and the pair is the safe cell. Which way it goes is decided by whether the guard's subject is load-bearing on your data, not by which half makes more noise.
The rest of the surface, read one arm at a time
refundableDefault reverts to refundable, so the amended-code cancellations get their fare back: refunds rise from 835.00 to 1,032.00. Quiet, and in the passenger's favour.
taxUsd on the ticket records produces REFUNDED=NaN -- a figure that survives into a report rather than throwing. cancelled produces REFUNDED=0.00, so nobody who abandoned a ticket gets anything back. paidUsd makes the penalty non-finite and the engine refuses before reissuing anything, which is the safe outcome.
taxRefundable and feeLabel were pinned equal to the library's own defaults on purpose, as controls, and both were inert exactly as predicted. So were the enabling flag and the caller's rule on their own.
What protection alone did, and what to do about it
Protection alone was clean. All five profiles produced output identical to the unprotected run for this area and the four others measured this pass; every result above required member renaming aimed at these particular names.
The build-side answer is the usual one: member renaming is opt-in and regexp-driven, so keep tariff option keys and ticket record fields out of the pattern. If you are shipping a mobile-first reissue flow, the progressive web app guide covers the packaging side.
The design answer costs nothing and helps regardless of obfuscation, because a dropped key over a serialisation hop produces the same miss: make a fare basis the table cannot find an event a person sees rather than a silent fallback, and reconcile the split between fee and fare difference rather than the collected total. The total was within six per cent of correct in the arm that lost 8,670 dollars; the split was not. The same reasoning applies to any table-driven charge, as in inventory reservations.
Frequently asked questions
Does obfuscating a reissue engine change what passengers are charged?
Not by itself. Protection with default settings was byte-identical to the unprotected run on all five profiles. The changes below appeared only under member renaming aimed at the tariff option keys or the ticket record fields.
What was the largest under-collection measured?
Renaming penaltyBasis collected 4,816.00 against a correct 13,486.00. The fare-difference component went to zero while the published change fees were still charged on every applicable ticket, so the engine still looked like a working penalty engine.
Can it charge passengers too much instead?
Yes, and from the same options object. Renaming waiverCodes stopped the storm waiver being recognised and collected 19,149.00 -- about 5,663 dollars billed to passengers the carrier had publicly announced it would not bill.
What happens if the fare rule table itself is renamed?
Every ticket becomes an unfound code: the not-found count went from 12 to 60. Collections rose slightly to 14,232.00 because the fallback fee is higher than two published fees, but refunds collapsed from 835.00 to 336.00 because unfound fares are treated as non-refundable.
Did switching off the carrier's own reissue check make things worse?
Not in this batch, and that is the surprising part. Renaming the fallback fee alone caused the rule to refuse the whole batch. Renaming the fallback fee and the check together produced figures byte-identical to the correct run, because the fare difference exceeded the fallback fee on every amended-code ticket, so the fallback never bound.
Which arms failed closed?
Three, each read individually. paidUsd made the penalty non-finite and the engine refused before reissuing. defaultChangeFeeUsd alone was refused by the carrier's own rule. cancelled produced a zero refund on every abandoned ticket -- quiet in the accounts but loud with customers.
What should we check instead of the collected total?
The split. In the arm that lost 8,670 dollars the collected total was still within six per cent of correct, because thirty tickets were still paying a published fee. The fee-versus-difference breakdown moved from 806.00 and 12,680.00 to 4,816.00 and 0.00, which no reasonable storm day produces.
Related reading