Measured Behaviour
Published
Every failure shape we have measured in this series so far has been a property of a record: a value, a unit, a date, a direction. A movement standstill is none of those. It is a property of a PLACE - and we measured what happens to a control when the thing it is about stops existing.
A control that is about a place, not an animal
When stock arrives on a holding, the holding freezes. Not the animal that arrived - the holding, and everything standing on it, for the length of the incubation window of whatever might have come with the consignment. Six days for cattle and sheep, twenty for pigs, in the rules we modelled.
The reason is the whole design. The disease that may have travelled in does not stay in the animal that carried it. It spreads to the resident stock, over an incubation period, and only then becomes detectable. Freezing the arriving animal is not a weaker version of that control. It is a different control, and it protects nothing, because the arriving animal is the one beast on the farm that is not yet infectious. The same collapse reached through an identifier rather than a place is measured in the traceability article in this series.
We built two holdings over a seventy-day window. One bought-in bullock lands on the first farm on day 10, so that farm is frozen to day 17. A consignment into an approved isolation unit lands on the second farm, which is therefore not frozen at all. Pigs land on the first farm on day 30, freezing it again to day 51.
Six departures follow. Twelve resident cattle on day 12. The bullock itself on day 13. Twenty head straight to the abattoir on day 14, which is exempt. Thirty resident sheep off the second farm on day 13. Sixty resident pigs on day 35. Eight cattle on day 60, long after everything has closed. The correct run refuses three, permits three, moves 58 head, and lets nothing off a restricted holding.
The subject of a control has nowhere to fail
A mis-read number is still a number, and you can check it against another number. A mis-read date can be checked against a calendar. Neither of those is available here, because what a standstill is about - a holding under restriction - is not written on any of the records the decision is made from.
The twelve resident cattle that walked off on day 12 appear on no arrival record anywhere. They were born on that farm. There is no row to inspect, no field to compare, and no reconciliation that fails, because they were never part of anything that had to reconcile.
So when we renamed the option that says the restriction is a property of the holding, the library fell back to its default: the restriction is a property of the arriving animal. That is a defensible reading. It is even a true statement about that animal. It is simply about the wrong thing.
What renaming the restriction scope actually did
Protected on both member-renaming presets, the numbers agree. Arrivals stayed at 3, departures at 6, and nothing became uncountable. Permitted went from 3 to 5. Refused went from 3 to 1. Head moved went from 58 to 130. And the counter held outside the bundle - head that left a holding while that holding was really under restriction - went from 0 to 72.
The single refusal that survives is the bullock. It arrived, so it is on the arrival list, so the animal-level restriction reaches it and stops it on day 13 exactly as it should. Every individual decision the run made is correct on the record in front of it. What has gone is not an answer; it is the subject the answers were about.
The keeper's own movement check passed. It asserts that every departure was either permitted or refused and that the head count reconciles, and both of those held. A control that has ceased to exist does not produce an unbalanced ledger. It produces a balanced one with fewer refusals in it.
And the enforcement line still read 'enforced'. The system was not switched off. It was still refusing movements, still issuing licences, still logging a standstill window of exactly the right length. The only configuration line that moved was the one naming the scope - which is precisely the line nobody reads, because everyone reads the one above it that says whether the control is on.
The wide pattern hid the narrow one
We pre-registered a contrast before running it. Renaming the enabling flag - the option that says whether standstills are enforced at all - should be the obvious, loud failure, and it is: permitted 6, refused 0, 131 head moved, 73 of them off a restricted holding.
Renaming both the flag and the scope together produced counters identical to renaming the flag alone. That is what we predicted and it landed exactly. A standstill that is not enforced does not care what it is a property of, so the second name contributes nothing once the first is gone.
The consequence is the part worth keeping. A broad, realistic 'rename the whole options object' pattern would have produced the loud result and nothing else. The quiet result - a control that still reports itself enforced, still refuses movements, and has silently stopped being about the farm - is only reachable under a narrow, careful, well-intentioned pattern that touches one name. The dangerous cells in a matrix like this are not at the wide end.
The record field failed in the opposite direction
We expected the record field naming the holding to produce the same collapse and it did not. It produced the reverse.
With that field renamed, every arrival and every departure keys off the same absent value, so the two farms merge into one. The second farm - the one that took its stock into an approved isolation unit and was never restricted - inherits the first farm's standstill. Permitted fell from 3 to 2, refused rose from 3 to 4, and head moved fell from 58 to 28. Thirty sheep that were entitled to move did not.
That is a real cost and it fails in the safe direction, which is why it is worth reporting rather than filing away. Two names on the same control, both lost the same way, and the option opens the gate while the record field jams it shut. Neither direction is predictable from how important the name sounds. It is decided by whether the lost name identified the thing being restricted or merely distinguished one instance of it from another.
What to do about it
Obfuscation itself is not the problem here. We protected this bundle on five profiles - the ES5 target, the modern target, both emit-gate configurations and the string-encoding profile - and all five behaved identically to the unprotected original, measured twice and diffed. Every result above needed member renaming aimed at a specific name.
So the first rule is the boring one: scope member renaming to names you own on both sides of every boundary, and exclude anything that reaches an installed library's option object or a record another system wrote - the member renaming options carry the regexp that does it.
The second is specific to controls of this shape. If a control is about something that is not a record - a place, a batch, a session, a tenant - then no amount of per-record validation will notice when it stops being about that thing. Write a test that moves something which was NEVER the subject of the event: stock that arrived on no lorry, a user who joined no session, a file that entered no batch. Our negative control moved only animals that had arrived, and in that fixture the defective run is byte-identical to the correct one on every counter. The same discipline applied to a veterinary withdrawal period is in the withdrawal-period article.
Third, put the counter where the control claims to act. Head permitted and head refused both reconcile in every arm here. Head that left a restricted holding, measured against a register the software did not compute, is the only line that moved - and it is the line that describes what the control is for.
Frequently asked questions
Does JavaScript obfuscation break movement standstill enforcement?
Not on its own. We protected the same standstill bundle on five profiles - the ES5 target, the modern target, both emit-gate configurations and the string-encoding profile - and all five behaved identically to the unprotected original, measured twice and diffed. Everything below required member renaming pointed at specific property names.
What happened when the restriction scope option was renamed?
The library fell back to its default, which restricts the arriving animal rather than the holding. Permitted movements went from 3 to 5, refused from 3 to 1, head moved from 58 to 130, and 72 head left a farm that was under a standstill. The bought-in animal was still correctly stopped.
Did the system report that the standstill was switched off?
No, and that is the point. The effective configuration still read 'enforced', the window was still exactly six days for cattle and twenty for pigs, and the run still refused a movement. The only line that moved was the one naming what the restriction is a property of, which is not the line anyone checks.
Is this the same as renaming the field that says which holding an arrival landed on?
No - that failed in the opposite direction. With the holding field renamed, every holding merged into one, an unrestricted farm inherited a restriction it never had, and head moved fell from 58 to 28. The option opens the gate; the record field jams it shut.
Why would a test suite miss this?
Because the obvious test moves the animal you just moved in, and that animal is stopped in both runs. In our negative control - where the only departures are of animals that arrived - the defective run is byte-identical to the correct one on every counter. The resident stock that exposes the defect appears on no arrival record at all.
Would a broad renaming pattern have shown this up?
It would have hidden it. Renaming the enabling flag and the scope together gives counters identical to renaming the flag alone, because a standstill that is not enforced does not care what it is about. The quiet result is only reachable under a narrow pattern that touches one name.
What should we change in a system built this way?
Scope member renaming to names you own on both sides. Then test the control against a subject that was never the event: stock that arrived on no lorry, a user who joined no session, a record that entered no batch. And measure the thing the control exists to prevent - head off a restricted holding - against a register your software did not compute.
Related reading