Measured Behaviour
Published
A bycatch cap is a limit on a stock you are not fishing for, reached by a fishery that is entirely legal, and the moment it is reached the legal fishery stops. Everything difficult about it is on the input side: the fish that went back over the side, and the hauls no observer was aboard for. We measured what a rename does to both.
Two questions that look like bookkeeping
We built one week of a real fishery. Two vessels, ten hauls, 37,150kg of target fish between them, and bycatch of three capped species - cod at 1,200kg, skate at 300kg, halibut at 150kg. Every haul is legal. Every kilogram recorded was really on the deck. Five of the ten hauls had no observer aboard, which is what a forty per cent coverage programme looks like in practice.
The correct run charges 2,010kg against the caps, closes all three stocks inside the week, and stops two hauls that would otherwise have been made - so only 29,400kg of that target catch is ever taken. That is the cap working: an entirely legal fishery halted because a stock nobody was targeting has had enough.
Two options decide whether the cap is ever reached, and both of them read like accounting preferences rather than controls. Does a fish that went back over the side count? And what do you do about the hauls nobody watched? This programme answers yes and carry the observed rate across in full. The library's defaults answer no and nothing.
Protection alone changed neither. Five profiles - ES5, modern, both emit-gate configurations, string encoding - all produced identical output. The failures start when member renaming reaches the configuration object, which is what a broad RenameMembers pattern does. The mechanics are in Protect Members.
Each half alone, then both
We wrote this prediction down before measuring, because it is the opposite of a shape we had measured twice before: two options that pull the same way, consulted at different points, where neither can remove the other's subject. If that holds, the union has to be worse than either half.
Renaming the discards key alone took charged bycatch from 2,010kg to 1,340kg. All three caps stayed open, all ten hauls went ahead, and the fleet's charged bycatch rate fell from 6.84 per cent to 3.61 per cent.
Renaming the unobserved-uplift key alone took it to 1,265kg by a completely different route: the five hauls nobody watched now contribute nothing at all. Same outcome, all caps open, rate 3.41 per cent.
Both together took charged bycatch to 660kg - under a third of the correct figure - at a rate of 1.78 per cent and 66kg per haul. The fleet's own bycatch check passed in all three arms, because it asserts that no capped species was taken beyond its cap, and in all three arms none was.
The 1,350kg that went missing in the union is not the sum of the two halves' shortfalls, which come to 1,415kg. The two effects overlap on the unobserved hauls' discards, which both halves remove. That is worth knowing if you ever try to reason about combined patterns arithmetically: they compose, but not by addition.
The number that is identical to a clean week
The negative control here is the week almost everybody builds: the same ten hauls, every one observed, every bycatch landed, nothing discarded. Constructing a discard event is extra work and constructing an unobserved haul means thinking about coverage.
That clean control charges 1,340kg - identical to the kilogram to the arm that loses the discards on the real week's data. A dashboard showing charged bycatch cannot tell a broken accounting rule over a real week from a correct one over a spotless week.
The two runs are not identical everywhere, and where they differ is instructive. The control reports zero unobserved hauls and zero unaccounted kilograms; the defective run reports five unobserved hauls and 1,365kg of bycatch that was killed and never reached the account. Both of those numbers are in the output. Neither of them is the number anybody puts on a dashboard.
Where the caps themselves went, and what stayed loud
Three separate keys produce exactly the same behaviour: removing the cap table, removing the flag that says to honour caps, and removing the closure trigger all leave the same 2,705kg charged, no stock closed, and all ten hauls made. That is a table and its switch being byte-equivalent, and it holds here because nothing downstream operates on the result.
It does not always hold - we measured a case in a previous pass where a table and its switch differed by a clear margin because a second transformation ran on top of the lookup. Do not generalise the equivalence across areas; measure it in yours.
The cap scope is the quiet one in that group. A stock-wide cap means one cap for the whole fleet; the vendor's default hands the entire cap to each vessel separately. Renaming it produced per-vessel balances that are each comfortably inside a cap that was never meant to be divided, with the published caps still displayed correctly.
The loud arms are the value arms, as always. Renaming the landed-bycatch field left nothing countable and the engine refused before charging any cap. Renaming the haul minute did the same. Losing a quantity fails closed; losing the rule about which quantities to count fails open.
The record fields, and two options that protect each other
The names on the haul records matter as much as the names on the configuration, and three of them are worth reporting.
Renaming the discarded-weight field on the record produces exactly the same result as renaming the option that says discards count: 1,340kg charged, no cap closed, all ten hauls made. Two entirely different edits, one to a policy switch and one to a field nobody would classify as a control, converge on the same number. If you are enumerating what could go wrong, the policy switch is the one you will think of.
Renaming the bycatch species field collapses every bucket into one: the balances come back as a single line reading FLEET|undefined=2705kg, which matches no row in the cap table, so nothing is ever charged against anything. The caps are still displayed correctly. A populated cap table is evidence that caps exist, never that any haul reached one.
The third is the one that did nothing, and it is the most encouraging result in the file. Renaming the observed flag makes every haul read as unobserved - the counter goes from five to ten - and charged bycatch stays at exactly 2,010kg, all three caps still close, and the two hauls that should have been stopped are still stopped. Nothing moved but a reported label.
That happened because this programme sets the unobserved uplift to a hundred per cent. An unobserved haul is charged at the observed rate, so it does not matter whether a haul is recorded as watched. The two options protect each other, and they only do so because the operator chose the strict value for one of them. A programme that had left the uplift at the vendor's zero would have lost its entire bycatch account to that one field.
What to do about it
Scope the member pattern away from configuration keys and record field names. That is the single change that removes every arm in this article.
Then look at the two vendor defaults, because they are worth changing whatever you do about obfuscation. A monitoring library whose default is discards do not count and whose default for an unwatched haul is zero is a library whose defaults are chosen for the operator's convenience rather than the stock's. If your programme relies on the non-default answer to either, make the option required rather than defaulted, so a configuration that cannot be read fails instead of quietly reverting.
Finally, monitor the counter that is not on the dashboard. Charged bycatch is the figure everybody watches and it is the figure that moves the least honestly. The count of unobserved hauls and the gap between what was killed and what was charged are both computable, both cheap, and both moved sharply in every arm above.
Industrial and vessel-side monitoring stacks have their own constraints on how far you can push a bundle; IEC 62443 and your JavaScript covers that side.
Frequently asked questions
Does obfuscation break bycatch limits?
Not on its own. Five protection profiles produced identical output on the same fixture. What broke the caps was member renaming reaching the names on the bycatch configuration object, where two keys decide whether the cap is ever reached.
Which two keys mattered most?
Whether discards count against the cap, and what happens to hauls with no observer aboard. Alone they took charged bycatch from 2,010kg to 1,340kg and 1,265kg. Together they took it to 660kg, under a third of the correct figure, with all three caps left open.
Is the combined effect just the sum of the two?
No. The two halves' shortfalls come to 1,415kg and the union's is 1,350kg, because both remove the discards from the unobserved hauls. Combined renaming patterns compose, but not by addition - which is a reason to measure the union rather than reason about it.
Did the bycatch check catch any of this?
No. It asserts that no capped species was taken beyond its cap, and in every defective arm none was, because the kilograms that would have breached the cap never entered the account. The check reported true figures every time.
Why do three different keys produce the same result?
Removing the cap table, the honour-caps flag or the closure trigger all leave 2,705kg charged and nothing closed, because nothing downstream operates on the lookup's result. That equivalence is not general - we have measured areas where a table and its switch differ - so check it in your own code.
Would our test suite catch this?
Only if your fixtures contain discards and unobserved hauls. A week in which everything was landed and everything was watched charges 1,340kg, identical to the kilogram to the defective arm over real data.
How do we protect monitoring software safely?
Scope the member pattern away from configuration and record names, make the discards and coverage options required rather than defaulted, and watch the unobserved-haul count and the killed-versus-charged gap as well as the charged total. Protect Members documents how the regexp is applied and what a safe scope looks like.
Related reading