Engineering

How it is built, and how to check it.

These are the properties the platform enforces, the mechanism that enforces each one, and where each one runs.

The reason this page exists is that compliance language is cheap. “Isolated per client”, “every AI action logged”, “built to GDPR” - every vendor has those sentences and none of them can be checked. So none of them appear here. Each section below names a thing you can go and look at.

The recurring defect

The gate in the interface is not the gate in the engine.

Every product that lets software act on a company’s behalf has two versions of every rule: the one the interface shows a person, and the one the engine applies when nobody is watching. It is easy to believe these are the same object. On this platform they have repeatedly turned out not to be, and it is always the second path - the one the AI uses - where the difference shows.

Three instances, all found by our own audits, all recorded:

A refusal enforced in the interface and not on the wire. The product deliberately does not show a raw per-person score: it shows an ordinal tier with the evidence behind it, because a number invites a decision the number cannot support. The interface honoured that. The payload underneath did not - the same rule, enforced in one representation of the system and not in the other. The honesty rule we are proudest of is, in one place, a property of the screen rather than of the system.

An audit row that read back as human. The rule is that every mutation writes an audit row and the actor is recorded truthfully. One pipeline wrote its completion row without an explicit initiator, so an AI-dispatched write stored the column’s default - user - and read back as human-initiated. One row, on one skill, with no decision resting on it. So the claim is scoped where it is made: attribution is enforced everywhere the gate’s scan reaches.

Tests that could not see what was broken. A whole vertical was built, merged and reported green while its tests were pointed somewhere else. The tests were not wrong. Green gates over an unexercised surface read exactly like green gates over a working one.

What we do about it, which is the only interesting part. The pattern is always the same shape - a rule that exists in one representation of the system and not in another - so the countermeasures are structural rather than diligent. Isolation is enforced in the database, where there is only one representation. Audit is a CI gate that fails the build, not a code-review convention. The confirmation lock lives in the tool contract with a test whose entire job is to prove a tenant’s opt-out is ignored, and a second one proving a workflow step cannot unlock it either. Each of those exists because asking people to remember the rule is what produced the list above.

And why the countermeasures are structural. This pattern was found three times by audits commissioned to find it - which is the argument for commissioning them, and the reason none of the fixes above rely on anyone remembering a rule. It is a live class, not a closed one, and the schedule assumes that: the audits keep running, and each fix removes a shape rather than an instance.

The mechanisms

Six properties, and what enforces each one.

Tenant isolation, in the database.

Row-level security in Postgres with a fail-closed context, rather than aWHERE tenant_id = convention that one forgotten query undoes. Exercised by a dedicated suite including chaos probes. Since 9 August 2026 a CI job fails the build when a component declaring team-level scoping is named by no isolation test - a census when it landed found eleven such components; its exemption list is empty today, and the gate blocks any new one.

844 test functions in 128 filesunder tests/isolation/, whose only job is to prove one tenant cannot read another’s rows. Counted 13 August 2026.

In CI, on every commit

An audit row on every mutation.

A CI gate fails the build on any mutation path that writes no audit row. Where the AI acts, the row records the AI as the actor: attribution is enforced on every path the gate covers, and verified by audit rather than assumed.

In the engine, on every write

Outward actions are locked in code.

Anything leaving the company is confirmation-locked at the tool contract, and the lock is not something a tenant can switch off. Two tests pin it: one proves a tenant opt-out is ignored, one proves a workflow step cannot unlock it.

core/tool_contract.py, pinned by test

Residency that refuses rather than falls back.

Infrastructure runs in AWS Zürich (eu-central-2). A call pinned to EU residency whose model resolves anywhere outside Bedrock-EU raises a hard error and stops. A silent fallback would work, which is exactly the problem: it would work, and nobody would find out for months.

eu-central-2 · EU-pinned inference

A proactive loop that has run unattended since July.

Thirty-four consecutive nightly sweeps, all four checks reporting, with the feed holding at fifty findings rather than multiplying them - which is the hard part, because a system that surfaces everything has surfaced nothing.

Navigo’s own tenant, nightly

Two things we refuse to build.

No bulk approve, because a person clicking approve on four hundred things has not approved four hundred things. And no automated action that moves money: the accounting connector is draft-only by construction and has no verb that pays or reconciles. Both are written into the decision log as decisions rather than held as preferences, which is what makes them survive the person who made them.

Written into the decision log
What is built, and where it runs

Three things built, and how far each one has got.

A meeting co-pilot that takes Swiss-German as it is actually spoken - dialect in, formal Hochdeutsch out. It drafts the Protokoll, separates the Beschlüsse from the discussion, and turns open points into Pendenzen carrying the person responsible and the deadline where the meeting named one. Built and merged, on Navigo’s own tenant.

An iOS client built for the site: it captures defects offline and reconciles when the network returns. Built and deployed against the live backend. Its own audit is the third instance in the essay above.

Connectors. The platform is built to sit on the tools a company already runs. WhatsApp is live end to end. Odoo runs on Navigo’s own tenant. Mail is the next one.

And this site.

Statically exported to S3 and CloudFront in Zürich, infrastructure in Terraform, deployed only by pipeline over OIDC - there are no long-lived AWS keys anywhere, and no secrets in CI at all. There is no server: what you are reading is a file.

An automated audit fails the build on horizontal overflow or on an input small enough to trigger zoom on iOS. Every animation here is an enhancement over a base layer that must stand on its own - with scroll-driven animation unsupported or switched off, the page is an ordinary column and still reads as one argument. The moment a step stops making sense without the animation, the animation is the bug.

No cookies, no analytics, no tracking of any kind. That is a privacy position and also a security one: there is no third-party tag here that could become someone else’s injection vector.

The internal component reference is at /styleguide if you want to see the primitives on their own.

This page is written in English, the platform’s own vocabulary. The German edition of the home page carries the same six mechanisms in German.

Talk to the people who build it →