Four facts, all verified against the running system, and together they made this phase unavoidable.
- Two bridges sharing one user are structurally deaf to each other. Each bridge skips any message whose sender is itself — and with one shared user, bridge A cannot distinguish bridge B’s message from its own. This is the requirement; everything else is why it took two pieces.
- The user was a single global value, read from config, not a property of a bridge.
- There was no way to mark an account as a bot. A user carried a role and a status and nothing else.
- The correct id was per-deploy and unguessable — and the wrong one was the owner. In production, id 1 is the operator and id 5 is the bot. On dev they are swapped.
Which is why the two pieces had to ship together or not at all. Adding a per-bridge user picker without an agent-account flag would have re-opened exactly the hole the UI phase closed when it removed the bot-user field: a form listing every human on the platform, one of whom is the owner with superadmin. That earlier removal was described in its own doc as “a real reduction, not a fix”, and it named this phase as the fix. Shipping only the relationship would have been a regression wearing the clothes of progress.
What landed: each bridge gets its own user, its own key, its own rate-limit bucket and its own audit trail — and, critically, real evaluated access with no admin bypass anywhere in the fleet. Four gates evaluated, not zero.