Measured, not asserted
Published
A change order is priced by looking a trade tier up in a negotiated markup schedule. A tier the schedule cannot find is not an error -- it falls back to the unnegotiated rate. This test measured both directions: losing the schedule over-priced a package by $82,100.00 and was caught cold by the contract's markup ceiling, while losing two keys inside the schedule deleted $57,900.00 of the contractor's overhead and profit and sailed through the same ceiling untouched. Then a separate experiment removed the ceiling as well, using nothing but the way a contract maximum actually reaches the code.
The direct costs are measured; the markups are negotiated
Pricing extra work has two halves and they have completely different provenance. The direct cost is a quantity somebody surveyed: so many cubic metres of rock, so many hours of rework. The markup is a schedule somebody negotiated, tier by tier, before the job started: 10% overhead and 5% profit on self-performed work, 5% and 5% for a first-tier subcontractor, 5% and nothing for a second-tier one.
Only the second kind can be lost without any number looking wrong. A direct cost that goes missing is a hole in a quantity. A markup that goes missing is a percentage that has reverted to a different, equally plausible percentage.
The fixture is four change orders on a $24,000,000.00 contract, $560,000.00 of direct cost between them. On the negotiated tiers they price at $617,900.00 -- $204,600.00, $105,800.00, $56,700.00 and $250,800.00 -- which is over the project officer's $500,000.00 delegated authority and goes to the owner's board.
The pricing engine is copied in unprotected. Its own defaults are what a library ships when nobody has given it a schedule: an empty markup table, and an unlisted tier priced at 15% overhead and 10% profit, because that is what an unnegotiated markup costs.
Protection on its own moved nothing
All five areas of this pass were run through five presets before any renaming -- the ES5 default path, the modern target, the emit gate's own option set on both targets, and the string transforms. Twenty-five comparisons, all byte-identical to the unprotected run.
Everything below required member renaming aimed at a name the installed pricing engine also reads.
Losing the schedule over-prices the package, and the ceiling catches it
Renaming the markup table makes every tier unfindable, so all four change orders fall back to the unlisted 25%. The contract's own markup rule refused the package outright: change-order-rejected(markup-check(CO-011 priced at 25% against a contract maximum of 15%)).
Two other routes reach the same place and are caught the same way. Renaming the tier names as bracket keys, and renaming the field on each change order that says which tier it belongs to, both produce the same 25% and the same refusal. That is a mitigation genuinely doing its job against three independent attacks.
Add the flag that enables it, though, and the package prices at package-total=$700000.00 markup-on-package=$140000.00. That is $82,100.00 above the negotiated price, and the verdict does not change -- the package still needs the owner's board, because both figures are over $500,000.00. The governance step fires normally and a board approves a number nobody negotiated. Replacing the contract's rule with the library's builtin instead of switching it off produces the same $700,000.00 with the word "checked" surviving in the output.
Losing two keys inside the schedule under-prices it, and the ceiling cannot see it
The markup schedule is a table whose rows are objects, and each row has an overhead key and a profit key. Rename those keys and the table stays visibly present in the configuration dump under new names, matching nothing that reads it.
Renaming the overhead key alone prices the package at $585,300.00. The profit key alone gives $592,600.00. Both together give package-total=$560000.00 markup-on-package=$0.00 -- the contractor's entire overhead and profit, $57,900.00, deleted, with every direct cost exactly right and the package footing perfectly.
None of these was caught. The contract's markup rule is a ceiling: it refuses a markup above the maximum. Zero is not above the maximum. The guard passed and printed a true sentence about a package that had just had the contractor's margin removed.
That asymmetry is the point. One options object contains three names whose loss over-prices the owner by $82,100.00 and is refused three different ways, and two names whose loss under-prices the contractor by $57,900.00 and is refused by nothing. The guard was written by one party to the contract and it protects that party. A ceiling is structurally incapable of noticing that somebody was paid too little.
The approval threshold: every dollar correct, and the authority gone
One arm is cleaner than any of the above. Renaming the option carrying the owner's delegated authority reverts it to the library's default of no threshold at all, and the package reads package-total=$617900.00 markup-on-package=$57900.00 => APPROVED UNDER DELEGATED AUTHORITY.
Every figure is exactly right. All four change orders are priced on the negotiated tiers, to the cent. The markup is correct. The contract's markup rule ran and passed, truthfully. The only thing that changed is that a $617,900.00 package which the owner's own delegation of authority sends to the board was approved by a project officer authorised to $500,000.00.
Nothing in the output is wrong. Nothing is missing, nothing is undefined, nothing is implausible. A control that exists to decide who may approve is not a property of the answer, and no check defined over the answer can see that it did not run.
The experiment: what happens when the ceiling comes from the contract
One arm in the main run measured no change at all, and it was the one carrying the contract's markup maximum. The explanation is structural: in the fixture that maximum is written on a record this bundle owns and read only by this bundle's own markup rule, so a rename moves both sides together and nothing crosses a boundary.
That reading is blind, not safe, and the discipline this series follows is to run the operation such a name governs rather than accept an inert result. So a separate experiment was built with its own negative control: the same ceiling, the same contract, the same over-pricing route, in two arms. In one the maximum is typed into the bundle. In the other it is parsed out of the contract register the owner transmits -- which is how a contract maximum actually reaches a contract administration system, because it is a term of the executed contract and not a constant in somebody's source file.
The negative control refused correctly, exactly as the main run reported. The experimental arm produced ceiling-from-register=undefined% and approved the package: package-total=$700000.00, every change order at the unnegotiated 25%, and the guard's own explanation reading checked by markup-check(CO-014 at 25% is within the undefined% contract maximum).
The guard ran. The guard passed. The guard printed its reasoning, and its reasoning names a ceiling that does not exist. The only control that caught the over-pricing route in the whole file evaporates the moment the contract terms come from the contract. Both member-renaming presets produced this identically.
What to do about it
Write the constraint as a floor as well as a ceiling. A markup rule that refuses anything above the maximum should also refuse anything that does not match the tier the change order was submitted under. The first protects the owner and the second protects the contractor, and a contract that only enforces one of them will only ever detect errors in one direction.
Make a missed lookup an error rather than a fallback. A tier the schedule cannot find should stop the pricing, not quote it at the unnegotiated rate. That single change turns three of the arms in this article from silent over-pricing into a refusal, and it is worth having regardless of obfuscation -- a mistyped tier name in a configuration file produces the same miss.
Validate values that arrive from outside the bundle at the boundary. The experiment above is not really about renaming; it is about a threshold that can be undefined. Require the contract maximum to be a finite number before comparing anything against it, and treat a non-finite ceiling as a refusal rather than as a comparison that quietly returns false.
Then assert the price. Run one known change order package end to end and assert the priced total, the tier each order resolved to, and whether it needed the board. That fails in every arm in this article. Checking that a markup schedule is configured passes in most of them, and the populated configuration dump in the sub-key arms is evidence that entries exist, never that anything finds them.
Organisations working to NIS2-style risk management obligations will recognise the shape: the requirement is not to obfuscate, it is to be able to show that the control you documented is the control that ran.
Frequently asked questions
Did obfuscation change any change order price on its own?
No. Five areas ran through five presets with every protected output byte-identical to the unprotected run. Every failure here required member renaming aimed at a name the installed pricing engine also reads.
What happened when the markup schedule was renamed?
Every tier became unfindable and all four change orders fell back to the unnegotiated 15% overhead plus 10% profit, pricing the package at $700,000.00 instead of $617,900.00. The contract's markup ceiling refused it -- until the flag enabling that ceiling was renamed too.
Why did renaming the keys inside the schedule go the other way?
Because a percentage the engine cannot read is taken as nothing owed. Renaming the overhead and profit keys left the table visibly present under new names and matching nothing, so the package priced at $560,000.00 with $0.00 of markup -- the contractor's entire $57,900.00 margin deleted.
Why did the contract's markup rule not catch that?
It is a ceiling. It refuses a markup above the contract maximum, and zero is not above the maximum. A ceiling written by one party to a contract is structurally unable to notice that the other party was paid too little.
What was the approval threshold arm?
Renaming the option carrying the owner's delegated authority reverted it to no threshold at all. Every dollar stayed exactly right and a $617,900.00 package was approved under a $500,000.00 delegation. The answer was correct; only the question of who may approve it moved.
What did the purpose-built experiment show?
That the ceiling protecting all of this vanishes when the contract maximum arrives from the contract rather than the source file. Parsed from the owner's register, the renamed read returned undefined, the package was approved at $700,000.00, and the guard printed that 25% is within the undefined% contract maximum.
What is the cheapest test that would have caught this?
Price one known change order package end to end and assert the total, the tier each order resolved to, and whether it needed the owner's board. That fails in every arm here. Checking that a markup schedule is configured passes in most of them.
Related reading