
# How Sovrium Is Built

If you cloned Sovrium from GitHub and went looking for tests, you found none. That is a real finding, and it deserves a real answer rather than a reassurance.

The GitHub repository is not where Sovrium is developed. It is the artifact a release produces. This page explains what that means, what the development repository contains, why it is private today, and what happens to your instance if the company behind Sovrium stops.

## The GitHub repository is a release artifact

Sovrium is developed in a private monorepo on a self-hosted Forgejo instance. Each release runs `scripts/filtered-mirror.sh`, which builds a filtered copy of that tree and publishes it to `github.com/sovrium/sovrium`.

The filter is an **allowlist**. Nothing reaches GitHub unless a line of that script explicitly copies it. Source code, the `@sovrium/types` package, build scripts, migrations, templates, the Dockerfile, and the release metadata are copied. Everything else is absent by default, including:

| Excluded                                                | What it is                                                         |
| ------------------------------------------------------- | ------------------------------------------------------------------ |
| `specs/`                                                | The end-to-end test suite                                          |
| `*.test.ts` / `*.test.tsx` under `src/` and `packages/` | Co-located unit tests, stripped after the copy                     |
| `.forgejo/`                                             | The CI workflows                                                   |
| `playwright.config.ts`                                  | The E2E runner configuration                                       |
| `scripts/check-quality.ts`, `scripts/check-progress.ts` | The two quality pipelines                                          |
| `eslint/`                                               | The modular lint configuration, including the layer-boundary rules |
| `docs/`                                                 | Architecture decision records, patterns, and user stories          |
| `.claude/`, `CLAUDE.md`                                 | Internal development instructions                                  |

Those exclusions are enforced, not merely intended. The script carries fail-closed canaries: if any protected path is present in the built tree, the release aborts before anything is pushed. The root `package.json` is replaced with a curated manifest whose `scripts` block is reduced to the public build subset, which is why no `test:` script is visible on GitHub, and a second canary aborts the release if a development-only script target leaks into it.

Publishing is a fast-forward child commit on top of the existing GitHub `HEAD`. There is no orphan commit and no force-push, so the public history stays continuous and browsable: one commit per release.

## Why the development infrastructure is private

The honest reason is competitive, and it is worth stating plainly rather than dressing up as policy.

The engine is free forever in self-hosted mode. The test suite, the CI pipeline, and the internal tooling are a different thing: together with the source, they are a working blueprint for reproducing the product. With current AI assistance, a complete specification suite is close to a build plan. Sovrium is bootstrapped and solo-founded, and that asymmetry is one of the few it has.

So the reproduction kit is held back. The product is not. Every feature works in the self-hosted binary, with no license keys, no feature gates, and no paid edition.

Read this as **deferred, not withheld**. The continuity commitment below sets the condition under which the private infrastructure is published.

## What the suite covers

These figures come from `SPEC-PROGRESS.md`, which is generated by `bun run progress` and regenerated by CI on every push. They are a static count of what the suite _contains_ — `bun run progress` reads the spec files, it does not execute them. Whether those tests pass on a given commit is what CI reports, not what this table says.

|                            |                                                  |
| -------------------------- | ------------------------------------------------ |
| Spec files                 | 908                                              |
| E2E tests                  | 7,933 total: 6,902 `@spec` + 1,031 `@regression` |
| Implemented                | 7,901                                            |
| Unimplemented placeholders | 32 `test.fixme()`, tracked                       |
| Unit test files            | 826 (787 under `src/`, 39 under `scripts/`)      |
| Unit test cases            | ~10,300, counted statically                      |
| User stories               | 894, tracing 7,426 spec IDs                      |
| Feature domains            | 23 engine domains plus 2 business-app domains    |

The structure matters more than the count, because it is what ties a test to a requirement.

Each `.spec.ts` file holds two tiers. The first is a set of `@spec` tests, one per acceptance criterion, each carrying the ID of the user story it satisfies. The second is a single `@regression` test that replays those same criteria as `test.step()` sections in one continuous workflow. So a feature is covered twice: once criterion by criterion, once as a user would actually move through it. The 894 user stories and the 7,426 traced spec IDs are the join between the two, which is what makes coverage a question with an answer rather than a feeling.

### What is not measured

Sovrium publishes **no code-coverage percentage**, because it does not measure one.

The quality pipeline enforces a test-**file** presence invariant: every source file in the domain layer must have a co-located `*.test.ts` sibling. That is a structural rule, not a line or branch threshold. No coverage threshold is configured anywhere in the project, and a present-but-empty test file satisfies the gate.

A number would be easy to produce and would not mean much. The limit is stated instead.

## What runs, and when

The CI workflow fires on **every push and every pull request** to `main`. It runs three jobs on a dedicated 8 vCPU / 32 GB runner, with a 50-minute ceiling on the longest.

1. **Lint.** ESLint across the tree, including the layer-boundary rules that keep the architecture's dependency direction enforceable rather than aspirational.
2. **TypeCheck and unit tests.** Full `tsc` type check, the unit suite, validation of every shipped example config through the real `sovrium validate` command, and a dual-dialect migration drift guard that regenerates both the PostgreSQL and SQLite migration sets and fails if a schema change reached only one of them.
3. **E2E.** Gated on the first two jobs succeeding, so the browser suite never runs against a red type check.

One precision, because it is the kind of thing worth getting right rather than rounding in our favor: CI runs `playwright test --grep "@regression|@packaging"`. That is the 1,031-test regression tier plus the packaging tier, which exercises the compiled binary built earlier in the same job. It is **not** the full 6,902-test `@spec` corpus, which is too slow to gate every push and is run locally and on demand instead.

Locally, two pipelines sit in front of a commit.

`bun run quality` runs thirteen gates in sequence, stopping at the first failure: Prettier, ESLint, workflow lint, a consolidated drift check (design tokens, brand identity, generated assets, schema, changelog, documentation links, and more), guide-config validation, a committed-secrets scan, a dependency audit against the lockfile, TypeScript, Effect diagnostics (opt-in), unit tests, Knip for unused code, the test-file presence invariant, and a smart E2E step that analyzes the changed files and runs only the related regression specs.

`bun run progress` validates the content quality of the specs and user stories themselves, and regenerates `SPEC-PROGRESS.md`.

## Security posture

Vulnerabilities go to **security@sovrium.com**. You will receive an acknowledgment within **48 hours** and an initial assessment within **5 business days**. Please do not open a public issue. Reporters are credited in the release notes, with permission.

The codebase is written against five standing rules, applied at the platform layer so every app inherits them without per-app configuration:

- **Authentication before sensitive logic**, with object-level authorization checked on every request, and `404` rather than `403` on failure so resource existence stays unobservable.
- **One canonical HTML sanitizer** for any content rendered from user or record data. There is deliberately only one, because a second sanitizer is a second set of bugs.
- **Parameter-bound SQL** for every runtime query, with validated identifiers quoted separately.
- **No secrets in client bundles or logs**, and no raw database rows returned from an API route.
- **GDPR export and erasure** wherever a feature touches user data, with erasure a hard delete rather than a soft one.

[Security Hardening](/en/docs/security-hardening) documents what this produces at runtime: the response header set, CSRF and cross-origin enforcement, rate limits, and the anti-enumeration behavior.

**No third-party penetration test has been commissioned to date.** The security work above is internal: design rules, code review, and specs that lock the behavior. That is not the same as an independent audit, and it should not be read as one.

## Continuity

The reasonable question behind "is this safe to build on" is not really about tests. It is: what happens to my instance if you stop?

**The engine is free forever in self-hosted mode.** No license keys, no feature gating, no enterprise edition, no phone-home, no kill switch. Sovrium reads your config and runs. If the company disappeared tomorrow, every running instance would keep running, because there is nothing for it to check in with.

**The license converts on its own.** Sovrium ships under BSL 1.1, which becomes Apache 2.0 on **2030-08-01**. That conversion is written into [`LICENSE.md`](https://github.com/sovrium/sovrium/blob/main/LICENSE.md) and needs no action from anyone, including us. See [License](/en/docs/license) for what the terms permit before then.

**The bus factor is one.** Sovrium is solo-founded and bootstrapped. Saying otherwise would be the kind of claim this page exists to avoid. The hedge is documentation discipline: architecture decision records that capture why each choice was made, user stories that state what each feature is for, and a spec suite that pins the behavior. Those exist so a future maintainer can re-derive the context rather than reverse-engineer it.

**If the company ceases operations, the private development infrastructure is released publicly.** The spec suite, the CI pipeline, and the internal tooling. The reason for holding them back is a going concern that would no longer exist, and the people left running Sovrium would need exactly those artifacts to maintain it. This commitment is recorded in [`SECURITY.md`](https://github.com/sovrium/sovrium/blob/main/SECURITY.md) in the public repository so it does not depend on this page remaining online.

## See also

- [License](/en/docs/license) for the BSL 1.1 terms and the Change Date
- [Security Hardening](/en/docs/security-hardening) for the runtime security guarantees
- [Contributing](/en/docs/contributing) for how to propose changes
- [Trademark](/en/docs/trademark) for how the Sovrium name and logo may be used
