Who sees what
Separation you can check,
not separation you hope for.
Most tools give every department a view of the same pile and trust people to stay in their lane. This one starts from nothing visible and widens only where somebody said so.
A department sees its own work
Not by hiding a menu. The department is part of the question the database is asked, so a Marketing agent searching for a serial number, opening a URL directly, or posting to the endpoint behind a button they cannot see gets the same answer: nothing. On lists, exports and search a row another department owns is not fetched and then withheld. It is not fetched, because the predicate sits inside the statement that computes the page and no code path can forget it. Fetching one record by its id works the other way round: the row is read, its department is judged, and the answer is the same refusal. Both hold. Only the first cannot leak later through a count or a page nobody thought to check, which is why the lists are the ones built that way.
It starts at nothing
A person's view begins empty and widens only where a membership says so. That is the opposite of the usual arrangement, where everybody can see everything and a filter narrows it, and the difference shows up on the day somebody forgets the filter: here, forgetting shows nothing rather than everything. A query that declares itself department-scoped and is handed no scope at all refuses to run. The failure mode is an error in front of an engineer, not a disclosure in front of a customer.
A permission is not a boundary
Holding the permission to publish an article says you can publish articles. It does not say whose. Those are two different questions and this platform asks both, because answering only the first is how one department ends up editing another's records. The permission answers what verbs. Membership answers over which rows. Neither one is sufficient on its own. Asking only the first is a whole class of defect rather than a single bug, so we look for that shape deliberately instead of waiting to be shown one, and the refusal is written down when it fires.
Nobody crosses by accident
Some people genuinely need every department: a platform administrator, an owner, and a department whose work is company-wide by nature. Each of those is a property somebody grants deliberately and can see in a list, and it is separate from being senior. A department manager is not a company manager. Seniority inside Finance buys nothing in Marketing, because the two are not points on the same ladder.
Absent, not hidden
A record outside your departments answers the same way as a record that was never created. There is no message telling you the thing exists but is not yours, because that message is itself a disclosure: it confirms the customer, the amount or the incident to somebody who was only guessing. Typing an address you were not given is the cheapest attack there is, so it is the one worth being boring about.
Every write asks again
Rendering a button is a decision about a screen. Accepting a write is a decision about data, and the two are checked separately. Each action re-establishes who is calling and what they may do, then re-reads from the database which department the target record belongs to, so a submitted field cannot nominate whose record is being changed or on whose behalf. A hidden control is not a closed door, and anything that treats it as one is trusting the browser to enforce a boundary.
Navigation follows the rule it enforces
Links are withheld wherever the page behind them would refuse, so nobody is invited somewhere they will be bounced from. The link is a courtesy. The server check is the control. Getting that order the wrong way round produces a product that looks tidy and is not safe, and one that is safe but constantly tells people no.
Everything is written down
Who acted, on what, when, and a line of detail. Sign-ins, permission changes, ticket movements, the report export, credential connections and revocations. Including the refusals: an attempt to WRITE across a boundary is recorded as an attempt, which is the line you want to find when somebody asks whether anything actually happened. Most systems log only what succeeded, which is how a question about an incident becomes an argument about missing evidence. Two limits, because you would find them. There is no previous-value column: a line says what a field was set to, and on a role change or an inline edit it does not say what it was before. And a refused READ writes nothing, because a record outside your departments answers exactly as a record that never existed, silently, by design.
The uncomfortable version of this is that it has to hold when somebody is actively trying. A hidden button is not a closed door, and a role that quietly widens when a department grants it is not a boundary. We treat both as one class of defect rather than two incidents, which is why the checks are written as rules a reviewer can apply to a surface they have never seen before.
None of this is worth anything if you can only take our word for it, so the person who runs the platform can look at any department exactly as its own staff see it: the same queue, the same lists, the same refusals, from their own account. That is how you check a boundary rather than trust one. Do it during evaluation, on your own data, before it matters.