Security
What is built, and what is not.
This page says what has been built and exercised, and names what has not. The repository carries no certification, no penetration test report and no external audit report. No availability, latency, maximum data loss or recovery time value is asserted.
01
Three facts, said twice
Each of these three figures was executed, then recorded. We advance no other. And each is written here twice: in the language of a board, then in that of the exercise which produced it. The second line is the exhibit; it is not separated from the first.
21/21
We checked, table by table, that the restored copy was identical to the original: twenty-one tables expected, twenty-one found, no divergence.
Canonical fingerprints computed over the 21 tables in scope and compared with the expectations captured at the witness point: 21/21 identical, 0 divergence. The method was tested by its converse — a clone in which a single value differed, at unchanged cardinality, was refused. Without that negative witness, a comparator that refuses everything would pass for vigilant.
b2-p2-pitr-oldest-antitest-20260817, § 1 and § 3.2
114 s
A lost database came back in under two minutes, from a backup held outside our walls and encrypted — not from a local snapshot. The measurement bears on that precise case: the server was standing, the tooling was in place, only the database had to be rebuilt. Rebuilding the server itself is another operation: it is written into our recovery procedure, it has not been timed, and we therefore ascribe no duration to it.
Point-in-time restoration from the encrypted off-site repository, recovery stop verified in the log, timed end to end: 114 s. Scope of the measurement: surviving server, tooling in place.
b2-p2-pitr-oldest-antitest-20260817, § 1 and § 5
0
The history of decisions is not erased by accident, nor by negligence, nor by an ordinary command — the database engine itself refuses. We tried, including with the highest privileges. The condition on which this guarantee rests is stated below, in the same block, and it is precisely what our operating practice imposes.
On 17 August 2026, two roles on two databases: the application role, not the owner of the tables, on production — “permission denied”, and “must be owner of table” when disarming the trigger; the superuser role on a disposable clone — “audit_events is append-only: DELETE is not permitted”. No attempt succeeded. The guarantee therefore rests on an operating condition which we state rather than pass over: the application connects under a role that does not own the tables. A table owner, for its part, could disarm the trigger.
b2-p5-non-owner-role-2026-08-17; b2-p2-pitr-oldest-antitest-20260817, § 3.3
02
What is built
Every line below can be checked in a file of the product repository. None is served without its limit: those are listed in the following section, and the two sections are read together or not at all.
- Authentication
- A real adapter verifies the bearer token against the identity provider’s public key set. The signature algorithm is allow-listed and asymmetric; shared-secret algorithms and the absence of a signature are refused. Issuer and audience are checked, service and anonymous tokens rejected: a service key is not an identity.
- Environment gate
- The gate is inverted, and closed by default: only the development and test environments open the permissive branch. Everywhere else — production included, down to an environment whose variable is unset — the application requires its real authentication mode, correctly configured, failing which it refuses to start.
- Revocation
- No principal cache, no provisioning on the fly: the group, the roles and the agent or human standing are read from the database on every request. A revocation takes effect at the next request.
- Authorisation
- Deny by default, at group scope. Three checks carry it: the required role, the human standing of the decider, and membership of the same group. Access by one group to another group’s data is refused under a stable code, not silently emptied.
- Separation of duties
- The author of an approval cannot decide it. The refusal is raised before any write, and the transaction is settled without partial mutation.
- Replay
- The replay key is bound to the triple of the operation, its actor and its payload. Another member of the group reusing the same key receives a refusal — and never the memorised response: a replay discloses nothing.
- Audit journal
- The journal is append-only, and that rests on three database triggers: before update and before delete, row by row; before truncate, per statement. The third closes a real breach — in PostgreSQL, row triggers do not fire on a truncation, which therefore erased the whole journal in silence. Two further tables, those of reclassifications and confirmations, are protected in the same way.
- Writing of events
- Every command that changes state writes its event within that command’s transaction: its reference, the actor, its agent or human standing, the source, the correlation identifier and the engine timestamp. A command that fails writes nothing; a command that succeeds never writes elsewhere.
- Encryption at rest
- The VAT number is encrypted at the application boundary, in AES-256-GCM. The key is mandatory everywhere outside development: its absence fails the assembly rather than enabling a deterministic development key, which therefore never serves real data.
- Logs and correlation
- The error envelope exposes a stable code, a message and a correlation identifier — never a document body, never a secret. An identifier supplied by the client outside the expected pattern is replaced by a server identifier, rather than rejected.
- Public surface
- A single route is public: the availability probe. It checks the database with a trivial query and returns no business data.
- Backup
- Two backup repositories: one local, the other off-site and client-side encrypted, with a provider distinct from the one hosting the database, in a European Union jurisdiction. Continuous archiving of the transaction log feeds both, and a real execution was proven before the word “regular” was written: regularity is a property of the scheduler, not an intention.
- Exercised restoration
- On 17 August 2026, a point-in-time restoration was carried out from the off-site repository. Three verifications were carried out: the recovery stop verified in the log, the table fingerprints identical to their expectations, and the absence of the marker written after the witness point. The oldest backup was then replayed in turn.
03
What does not exist
The repository carries no certification, no penetration test report and no external audit report. What exists in their place does not replace them and does not take their name: a single verification gate, reproducible by one command, whose steps and results are committed to the repository; a matrix of authentication scenarios; dated resilience exercises whose exercise logs are committed.
- Service commitment
- No availability, latency, maximum data loss or recovery time value is asserted. The durations published are exercise measurements, not commitments.
- Maximum data loss
- The RPO is not given a figure to date.
- Resilience gate
- The resilience gate instituted by decision ADR-0002 is not passed: two of its three conditions are proven, the third — object storage and integrity checking — is not covered, and a cumulative gate is not passed two thirds of the way.
- Real data
- No real data has entered the system: the gate above forbids it until it is passed.
- Restorable depth
- The off-site restorable depth stood at about five hours on 17 August 2026, and not at the fourteen-day target: that is acquired by accumulation. The only way to know it is to measure it.
- Immutability of the off-site repository
- The off-site repository is neither retention-locked nor immutable: a mass deletion there is detected daily, it is not prevented.
- Full disaster
- Restoration is proven on a surviving server, with tooling in place. Rebuilding the host is described in the recovery kit; it has been neither executed nor timed.
- Operating condition of the journal
- The append-only property of the journal rests on a condition which we state rather than pass over: the application connects under a database role that does not own the tables. A table owner, for its part, could disarm the trigger. No migration can impose it and no test in the repository detects it: it is an operating requirement, and it is written as such in the procedure.
- Partial encryption
- A single field is encrypted at rest, the VAT number. The registration number is stored in clear, because it carries a uniqueness constraint; a blind index is deferred. No key management service is integrated.
- Second factor
- No second authentication factor in version 1; management of the identity provider — banning, service key rotation — remains an operator’s act.
- Corporate directory
- No connection to a corporate directory is built. Invitation and administration go through the identity provider’s gateway.
- Delivery of events
- Every mutation writes its event in the same transaction; no relay consumes that queue within the built scope: the messages remain in the pending state.
- Alerts
- There is no alert of any kind: no model, no field, no route.
- Document storage
- No document storage, no electronic signature, no antivirus scanning.
- Security governance
- No tooled security governance, no incident register. These are specified; they are not built.
04
What is scheduled, and what has never run
A backup check is scheduled every day by timer, and a daily reading of the off-site inventory detects a mass deletion. A restoration exercise is planned every month; two have been executed to date, on 17 and 18 August 2026, and the first is the one whose exercise log is committed to the repository. The weekly repository verification check has not yet run: its presence in the code is not proof, and we do not count it as such. The off-site restorable depth stood at about five hours on 17 August 2026; we measure it, we do not assume it.