Measured Behaviour
Published
The permitted occupancy of a space is the LESSER of two computed numbers. That single word is the whole difficulty: a change that doubles the limit that was not binding produces a byte-identical verdict, a moved audit line, and the kind of finding a reviewer closes as cosmetic. We measured two such findings, and then measured them together.
Two numbers, one answer, and only one of them is visible
How many people a space may hold is decided twice. Once by area: the floor area divided by an occupancy load factor for the use - 0.3 square metres per person in a bar, 6 in an office, 30 in a store. Once by exits: the total width of the escape doors multiplied by the people a millimetre of door can pass, with the largest door assumed to be the one that is unusable, because the fire may be at it. The permitted number is whichever calculation gives less.
We built six spaces in one mixed-use building on one night. A first-floor bar where six hundred would fit by area but the exits pass a hundred and eighty. An office floor let for a reception where the area binds and the exits do not. A seated hall where fixed seating overrides the area calculation outright. A retail unit with one proper door and one 700mm service door that is not an escape route. A basement store and a small office suite working late.
The correct run admits two of the six at the numbers sold, refuses four, and nobody is admitted over the capacity the approved fire strategy gives their space. Seventy people are let in. That is the baseline, and every area, door width and ticket count in it survives every arm below intact.
The two findings a reviewer closes as cosmetic
Two options decide the exit calculation. One says the largest exit is assumed unavailable. The other says how many people a millimetre of door width passes - five millimetres per person here, against the vendor's two.
Rename either one on its own and the bar's permitted number goes up, and nothing happens. Admitted stays at 2, refused stays at 4, seventy people are still let in, and the counter stays at zero. The only thing that moves is a printed figure in the audit line: the space that was over its limit by three hundred and twenty is now over it by a hundred under one of them and by fifty under the other, and it is still over it. The other calculation was binding.
This is exactly the finding a reviewer closes. Two independent arms, both producing a value diff with no behaviour change, both in a system whose own capacity check passes cleanly. We have seen the same signature before and it has meant "defence in depth working as intended" often enough to be believable.
Rename both together and the bar admits five hundred people into a space the fire strategy rates for a hundred and eighty. Admitted goes from 2 to 3. People admitted goes from 70 to 570. And the counter held outside the bundle - people admitted above the capacity their space actually has - goes from 0 to 320. Over a forty-night season that is 12,800 admissions over capacity.
Neither half raised the exit capacity far enough to cross the area limit. Together they raised it past both. That is what "the lesser of two numbers" does to a matrix of single-name arms: it hides the pair behind two clean halves.
Four names, one figure, and what that means for an audit
The area calculation has more than one way to go wrong, and they converge. Renaming the load-factor table, renaming the record field that says what the space is used for, renaming the floor area itself, and renaming the option that excludes ancillary area from the count all produce the SAME counters: admitted 3, 260 people let in, 40 over the true capacity.
They get there by four different routes. The table goes empty, so there is no factor. The use class stops matching a row, so there is no factor. The floor area becomes a value that is not a number, so the comparison against it is false and the limit is never applied. The ancillary exclusion reverts to the vendor's "count it all", so the same office floor is 1,160 square metres instead of 900. Four names, four mechanisms, one figure.
The consequence for an audit is the part worth keeping. Two of those four are options and show up in a configuration dump; two are record fields and show up nowhere. If your assurance for this control is "we diff the effective configuration against policy", you are covering half the ways it fails, and the half you are not covering is not the smaller half.
The fixed-seating field is the largest single arm in the area. Rename it and the hall stops being limited by its seat count and falls back to an area calculation that permits six hundred - 630 people admitted, 160 of them over the true capacity. A hall does not hold more people because the code forgot how many seats it has.
The arms that fail loudly, and why that is the good outcome
Not everything here fails open. Renaming the record field that carries a door's width makes every door unmeasurable, so no door counts as an exit, so every space in the building is refused. Renaming the list of exits does the same. Those are catastrophic in the operational sense and harmless in the safety sense: the venue does not open, somebody phones at nine in the morning, and it is fixed before lunch.
The direction is not luck and it is not a property of how important the field sounds. A capacity test asks "is this crowd too big?" and refuses when the answer is yes. A number that cannot be read makes that comparison false, so the refusal is skipped and the space is admitted. A door width that cannot be read makes the capacity zero, and zero refuses everything. The same missing value opens one gate and closes another depending on which side of the comparison it landed on.
Two options in this file are worth naming together for the same reason. Losing the minimum exit width and losing the second-exit requirement produce identical counters - admitted 3, 120 people over capacity - by opposite logic. The first lets a 700mm service door count, which gives the unit two exits and satisfies the rule. The second removes the rule. Same figure, and an auditor reading the schedule cannot tell them apart.
What the quiet weeknight test does not see
The negative control here is the building as it usually is: the same six spaces, the same doors, the numbers the operator expects when nothing is on. Five of six admitted, one refused for having a single countable exit, nobody over capacity.
Every arm that RAISES a capacity is inert in that control, and the reason has nothing to do with the obfuscator. When the expected number is nowhere near either limit, it does not matter which limit binds or how far it moves. The two arms it does catch are the ones that stop a space being occupied at all - and those are the loud ones that get fixed anyway.
The same trap runs through escape route travel distances, where a one-corridor fixture cannot see a leg leave a sum, and through fire system impairment permits, where a properly raised permit cannot demonstrate that a compensatory clause matters. In all three the fixture that fails to see it is the fixture a careful engineer writes first.
What to do about it
Scope member renaming with a regexp that names what you mean to rename, and keep out of it any name that appears on both sides of a MINIMUM. When an answer is the lesser of two computed numbers, single-name testing is structurally weak: each name can only be shown to matter when its own calculation is the binding one, and which one binds changes from space to space.
Test the pairs. The union of two options that pull the same way is not covered by testing each option, and this pass produced two clean halves and a union that let three hundred and twenty extra people into a bar. If a control is computed as a minimum, the arms worth running are the combinations, not the singletons.
And require the inputs to be finite before comparing them. A floor area that cannot be read is not a floor area of zero and it is not an unlimited one; it is an unassessed space, and refusing to give it a capacity is one line of code that would have removed one of the four arms above entirely.
Frequently asked questions
Does obfuscation change a building's permitted occupancy?
Not by itself. Protecting the model on five presets without member renaming produced byte-identical output. What changed the permitted numbers was member renaming reaching the names the two capacity calculations read.
What was the worst single result?
Two options that were each individually inert - the largest-exit discount and the persons-per-millimetre rate. Renamed together they took a bar from 180 permitted to 600, admitted 500 against a true capacity of 180, and put 320 people over capacity on one night.
Why did each half look harmless?
Because the permitted number is the LESSER of an area limit and an exit limit. Each half raised the exit limit without raising it past the area limit, so the verdict did not move and only a printed figure changed.
Which arms failed safely?
The ones that made a door width or an exit list unreadable. Those drive the exit capacity to zero, which refuses every space in the building - operationally severe, immediately noticed, and safe.
Can a configuration audit cover this?
Only partly. Of the four names that produced the identical area-limit failure, two are options that appear in a configuration dump and two are record fields that appear nowhere. The record half leaves no trace outside the answer.
Does the application's own capacity check help?
No. It asserts that every space was admitted or refused and that the numbers reconcile. Both hold in every arm, because both are statements about the capacities the run computed rather than about the capacities the space has.
What is the cheapest mitigation?
Two things. Require every input to a capacity calculation to be finite before comparing it, and test the COMBINATIONS of options that feed the same limit rather than testing each option alone. Neither costs anything at design time.
Related reading