Unreleased documentation. These pages follow the main branch and can change before the next release. For supported guidance, use v0.43.0.
You have a registry project that passes
bregctl check --production, and you want it serving. This page takes you from an empty
PostgreSQL server to a breg process that serves the project’s first
package and answers GET /ready. The examples use the
facility template that bregctl init --template facility-registry facility creates.
Two roles take part. The author prepares a package from the project. The operator, holding the migration credential, activates the package and runs the server. One person may hold both on a pilot; the commands stay the same. A package carries no signature: the migration credential is what authorizes an activation, and the database records every activation in its own ledger.
Deployment commands take absolute paths with no .. component and no symbolic link anywhere in
them. That covers --runtime-config, --credentials, --test-receipt, --package, the test
receipt’s --output, and the directories the runtime file names. When an output path such as the
test receipt’s --output is refused for a symbolic link, the diagnostic names the linked component
and the target it resolves to. If the linked component is an ancestor, choose an unused final name
under its real directory. If the final component is itself a symbolic link, that final name is
occupied by the link; choose another unused, non-symbolic-link name under the real parent.
What you need
Section titled “What you need”- PostgreSQL 17 or newer, reached over TLS, with two login roles: a migration role that owns
the schema and applies packages, and a runtime role the serving process uses. A project with a
crs84-pointfield also needs PostGIS 3.5 or newer. Your administrator creates the roles, schemas, and extensions; the product never creates any of them. SQLite is not a target. Ubuntu 24.04 ships PostgreSQL 16 and Debian 12 ships PostgreSQL 15, both too old: install 17 from the PostgreSQL project’s apt repository (PGDG), or run thepostgres:17image (postgis/postgisat PostgreSQL 17 when the project has acrs84-pointfield). - A host for one process. The runtime is a single binary that verifies one package and serves its REST API against one database, on the platforms in platform support.
- HTTPS in front of it. The process trusts no host or forwarded header. Your reverse proxy or
ingress terminates TLS, and generated links use the public origin you configure as
listener.publicOrigin. - A token issuer. The registry verifies bearer access tokens from one OpenID Connect issuer and issues none. Human login, account lifecycle, and multifactor authentication stay with your identity provider.
- A backup of the database before every activation. The product restores nothing itself. A destructive change is refused unless you name the backup its reviewed migration requires, as Change an active registry describes.
Records, their history, Proposals, and the outbox of undelivered events all live in PostgreSQL. Webhook delivery runs inside the process from that outbox, so there is no message broker and no cache. The audit journal goes to a local file per process or to standard output. Attachments use PostgreSQL unless you bind S3-compatible storage. A standalone registry needs no other Registry Stack service; a composition adds only the services it uses, such as a Review provider for reviewed Proposals. Authoring commands open no database, so an author works on a laptop until the project is ready to test.
What stays your job once it runs:
- Secrets. Two database credentials, the audit hash key, the cursor secret, one key per webhook destination, and the issuer’s key set when you pin one. The runtime file names each by reference and refuses a value written inline.
- Every production change. A one-line access change takes the same path as a new registry: check, test against a schema-test database with real tokens, package, plan, and activate under the migration credential in each environment.
- The audit journal. Ship each process’s stream to append-only storage and confirm delivery before local retention expires. The product does not provide tamper evidence.
- Retention and erasure. Erasing a record’s history is an operator command with no undo; see Retain, erase, and audit.
- Rate limits. The runtime applies none of its own, so put the registry behind one.
No throughput or latency figure is committed. The product bounds what it can by construction:
every request, lock, and migration runs under an operator-set timeout, the connection pool has a
maximum size, and spatial responses refuse rather than truncate. A load-test harness ships in
products/breg/loadtest; run it on a representative Linux host before you cite a number.
Base Registry Engine (BReg) is pre-1.0. A minor release may break APIs, package formats, or
deployment contracts, and each break carries a BREAKING: entry in products/breg/CHANGELOG.md at
the release tag you run. Security fixes land only in the latest release; see
API stability and the
support window. A pilot holds three conditions: run breg under
a supervisor that restarts it, treat the holder of the migration credential as the activation gate,
and stay inside the verified deployment profile, which leaves out Kubernetes.
Obtain the runtime
Section titled “Obtain the runtime”Install the binaries on the host that will serve, and on the operator host that holds the migration credential:
curl -fsSL https://github.com/registrystack/registry-stack/releases/latest/download/breg-install.sh | bashbreg --versionbregctl --versionThe installer checks every binary against the release SHA256SUMS before anything reaches the
install directory, and installs breg and bregctl together or not at all. It does not verify who
published the release; for that, follow the
release verification procedure
and rerun the installer with BREG_ASSET_DIR naming the verified directory. BREG_INSTALL_DIR
selects the install directory (default ~/.local/bin). To pin a release, run that release’s
breg-<tag>-install.sh from https://github.com/registrystack/registry-stack/releases/download/<tag>/.
Binaries are published for linux-amd64, linux-arm64, and macos-arm64.
Test, package, activate, and serve with the same release of both binaries.
Each release also publishes the container image ghcr.io/registrystack/breg:<tag> for
linux/amd64. The release manifest beside the binaries,
registry-stack-<tag>-release-manifest.json, records the image digest; pin that digest rather than
the tag. Serve the container image shows how to run it.
Provision PostgreSQL
Section titled “Provision PostgreSQL”As a PostgreSQL administrator, create the two roles:
CREATE ROLE registry_migration LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOBYPASSRLS PASSWORD '<migration-password>';CREATE ROLE registry_runtime LOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOBYPASSRLS PASSWORD '<runtime-password>';Two separate roles are the split role mode, which production uses. The serving process then cannot
write the activation ledger or registry state, and apply and startup both refuse a runtime role
that could, naming the grant, ownership, membership, or trigger to remove. Keep the migration
credential off the serving host when no activation is in progress.
Create two databases with the same shape: the serving database and the schema-test database. In
each, as the administrator (this is the serving database, registry):
CREATE DATABASE registry;REVOKE ALL ON DATABASE registry FROM PUBLIC;GRANT CONNECT ON DATABASE registry TO registry_migration, registry_runtime;\connect registryCREATE EXTENSION IF NOT EXISTS btree_gist;CREATE SCHEMA registry_internal AUTHORIZATION registry_migration;CREATE SCHEMA registry_data AUTHORIZATION registry_migration;CREATE SCHEMA registry_source AUTHORIZATION registry_migration;CREATE SCHEMA registry_derived AUTHORIZATION registry_migration;CREATE SCHEMA registry_context AUTHORIZATION registry_migration;REVOKE ALL ON SCHEMA registry_internal, registry_data, registry_source, registry_derived, registry_context FROM PUBLIC;The package creates every table, function, and policy inside those five schemas. A missing
prerequisite surfaces at test or apply, never at runtime.
For a spatial project, add a bounding-box role named after the runtime role with the suffix
__spatial_bbox, and install PostGIS in a schema neither registry role owns:
CREATE ROLE registry_runtime__spatial_bbox NOLOGIN NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOBYPASSRLS;GRANT registry_runtime__spatial_bbox TO registry_migration WITH INHERIT FALSE, SET TRUE, ADMIN FALSE;-- in each databaseCREATE SCHEMA registry_spatial_ext AUTHORIZATION postgres;CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA registry_spatial_ext;REVOKE CREATE ON DATABASE registry FROM PUBLIC, registry_migration, registry_runtime;REVOKE ALL ON SCHEMA registry_spatial_ext FROM PUBLIC;GRANT USAGE ON SCHEMA registry_spatial_ext TO registry_migration, registry_runtime, registry_runtime__spatial_bbox;Size connections, timeouts, and statement statistics once the registry serves; see Set a PostgreSQL baseline.
Write the runtime configuration
Section titled “Write the runtime configuration”The runtime file binds one package to one database, one token issuer, and one listener. It is a
deployment artifact: keep it with the operator, outside the project, and never put a credential in
it. Every credential is a reference such as secret:file/<name>, which resolves to a file under the
secret root.
apiVersion: id.registrystack.org/formats/breg/runtime/v1alpha1kind: BRegRuntimeConfiglistener: bind: 127.0.0.1:8080identity: environment: production instanceId: facility-registry databaseId: facility-registry-db databaseInitializationEnvironment: productionsecretProviders: file: root: /etc/breg/secretsdatabase: runtimeUrlRef: secret:file/runtime-database-url migrationUrlRef: secret:file/migration-database-url trustedRootCertificateRef: secret:file/database-ca pool: maximumConnections: 4 roles: migration: registry_migration runtime: registry_runtimepackage: root: /var/lib/breg/build-1/packageauthentication: oidc: issuer: https://issuer.example.com audience: urn:breg:facility-registry allowedAlgorithm: EdDSA accessTokenType: JWT scopeClaim: scope scopeSeparator: " " allowedClients: [operator-editor, registrar, reader] maximumTokenLifetimeSeconds: 3600 leewayMilliseconds: 60000 authorityClaims: principal: registry_principal purpose: registry_purposeaudit: hashKeyRef: secret:file/audit-key path: /var/log/breg/audit.jsonlcursor: secretRef: secret:file/cursor-keyThe configuration reference lists every key. What the schema cannot tell you:
identitynames the database this file may serve. The first activation recordsdatabaseIdin the database, and every laterplan,apply, and startup refuses a file that names another.instanceIdstamps every webhook event this runtime captures, so keep it stable while deliveries are pending.databasenames the two connection URLs and the two roles. The runtime requires TLS on both connections and verifies the server’s certificate and host name.trustedRootCertificateRefnames PEM root certificates to trust in place of the platform roots, for a server whose certificate a private authority issued; omit it when a public authority issued it.package.rootis the package directorypackagepublished. Once you have the package, you may addpackage.expectedDigestwith the reported package digest, and startup then refuses any other package at that path.authentication.oidc.allowedClientslists the OAuth clients whose tokens the registry accepts, orunrestricted. A project that names clients itself, for example in a profile’srequesterClients, needs each of them listed, sounrestricteddoes not start with such a project.authentication.oidc.issuermust behttps; plainhttpis accepted only on an IPv4 loopback host. The key set comes from the issuer’s discovery document unlessjwksSourcenames a URI or pins a static document.
Three optional sections matter only for some projects. taskGrantStatus pins, per task-grant
issuer such as Casework or a chat assistant’s task authority, the endpoint and the registry’s own credentials it uses to check that a task grant is still
current. wasmExecution sets the backend and the module and guest-memory ceilings for WASM
handlers. authentication.oidc.assertionIssuers lists, per client, the assertion authorities
that client may exchange a subject token from; once written, a client it does not list may
exchange from none. Webhook destinations are bound in Bind webhook receivers, field
encryption in Field encryption for restricted fields, and
the metrics listener in Scrape metrics.
Create the secret files
Section titled “Create the secret files”Create the files as the user that runs breg and the operator commands, because the resolver
refuses a file owned by anyone else. Each must be a regular file with mode 0400 or 0600, with
no other hard link and no symbolic link to it. A name starts with a lowercase letter and uses
lowercase letters, digits, ., _, and -. The bytes are used exactly as written, so write them
without a trailing newline:
install -d -m 0700 /etc/breg/secrets(umask 077; openssl rand -hex 32 | tr -d '\n' > /etc/breg/secrets/audit-key)(umask 077; openssl rand -hex 32 | tr -d '\n' > /etc/breg/secrets/cursor-key)(umask 077; printf '%s' 'postgresql://registry_runtime:<runtime-password>@db.example.org:5432/registry' \ > /etc/breg/secrets/runtime-database-url)(umask 077; printf '%s' 'postgresql://registry_migration:<migration-password>@db.example.org:5432/registry' \ > /etc/breg/secrets/migration-database-url)(umask 077; cp /path/to/database-root-ca.pem /etc/breg/secrets/database-ca)The audit key and the cursor secret each need at least 32 bytes. Percent-encode a password that
carries reserved characters. The user in each URL must equal the role the file names under
database.roles. The URL needs no sslmode parameter: the runtime requires TLS itself.
In a container platform that injects secrets as environment variables, declare
secretProviders.environment and write secret:env/<NAME> instead.
What a token must carry
Section titled “What a token must carry”The registry verifies a bearer access token before it reads any claim. Configure the issuer so
that every token for this deployment satisfies the table. Fixture claims from journeys.yaml are
never accepted by a running server.
| Token part | Requirement |
|---|---|
alg, typ, kid headers | alg equals allowedAlgorithm; typ matches accessTokenType case-insensitively, and at+jwt and application/at+jwt are accepted for each other; kid is in the key set and absent from deniedKids. |
iss | Equals issuer. |
aud | A string equal to audience, or an array of 1 to 16 distinct strings that contains it. |
exp, iat, nbf | The lifetime is at most maximumTokenLifetimeSeconds (at most 7200); clock skew up to leewayMilliseconds (whole seconds, at most 300000) is tolerated. |
azp or client_id | Listed in allowedClients, unless that is unrestricted. |
scope | The one claim named by scopeClaim covers every required permission: a string split on scopeSeparator, or an array of strings. Permissions from several claims are not merged. |
| principal claim | The claim named by authorityClaims.principal carries the identity recorded in audit and workflow decisions. It must match each profile’s principalClaim. |
| purpose claim | The claim named by authorityClaims.purpose is required when the profile lists requiredPurposes. |
| assignment claims | Each row boundary or claim-backed lookup names its own claim. An equals boundary needs a scalar; an in boundary needs an array. |
Use a resource audience dedicated to this registry API, distinct from your application’s login client. An ID token issued to the login client is not an API credential. A longer token lifetime extends how long an issued token may carry permissions you have since withdrawn.
Identities that survive operations
Section titled “Identities that survive operations”Choose the principal claim deliberately. sub works when both the runtime file and the profiles
select it, and the server never falls back to another claim when the selected one is missing. An
issuer’s sub usually belongs to that issuer alone, so if you may ever change issuer, prefer an
institutional identifier both issuers carry in a custom claim, and name who guarantees it is unique
and never reassigned. The registry treats the value as opaque and links no accounts across issuers;
changing it changes who is recognized as a submitter or a previous reviewer.
Use the same principal claim in an ownership row boundary when a record’s owner field stores that identifier, and separate claims for district, tenant, or team membership. Have the issuer derive these claims from trusted assignments, never from values the caller supplies. A client-credentials token represents a service, not a person signing in.
Rotating keys and changing the issuer are in Rotate keys and change the issuer.
Check, test, package
Section titled “Check, test, package”These three commands turn the project into a package the database can activate. Run check with
the runtime file you will serve, so it also checks that file against the project:
bregctl check facility --runtime-config /etc/breg/runtime.yaml --productionProduction check passed; registry revision sha256:4877be0dd9ded0447278206d829445780bf93a6cee356bc1526773003acad158.Warnings follow the success line; read each one.
test compiles the project, applies it to an empty schema-test database, measures the schema it
produces, runs every journey in tests/journeys.yaml over real HTTP with real tokens, and writes a
receipt that package binds to. It needs three inputs:
- A test runtime file: a copy of the serving file whose database URLs name the schema-test
database and whose
package.rootis an empty directory. - A real access token from your issuer for each journey principal, stored as a secret file.
- A credentials document of
kind: BRegSchemaTestCredentialswhosebindingslist gives, for each journey step, itsjourneyId, itsstepId, and acredentialoftype: bearerwhosetokenRefnames that token’s secret file (keys).
bregctl test facility \ --runtime-config /srv/registry/runtime-test.yaml \ --credentials /srv/registry/schema-test-credentials.yaml \ --output /srv/registry/schema-test-receipt.jsonFixture run passed. 1 journey. profile production registry revision sha256:4877be0dd9ded0447278206d829445780bf93a6cee356bc1526773003acad158 schema fingerprint sha256:99bc1da109508fdab4a69c0d0dc6c00efa0cd1c5cff05d4f81ca1460be91ff74 successful journeys register-facility receipt sha256 33a29c7dfdb50ccee78033963d1beaa1cf4939c0a2d4dc77097bd3c9988fef6b receipt bytes 755test leaves its objects in the schema-test database, and a second run refuses with
schema-test database is not clean. Drop and recreate that database before every run. A token that
has expired fails a step as the fixture request could not be constructed; mint fresh tokens and
rerun.
package seals the candidate and binds it to the receipt:
bregctl package facility \ --test-receipt /srv/registry/schema-test-receipt.json \ --output /var/lib/breg/build-1Sealed and published a deployment package. profile production package digest sha256:ae245974f8da79cd441669fbe0e2461ceb26e216cd1f7f25a7240fd131d20fee registry revision sha256:4877be0dd9ded0447278206d829445780bf93a6cee356bc1526773003acad158 package files 28The package directory is build-1/package. package refuses a receipt taken for other sources,
and refuses an output directory that already holds a package, so give each candidate its own build
directory. Never edit files inside a published package; build another one.
Activate and serve
Section titled “Activate and serve”Rehearse the activation with the migration credential. plan makes every check apply makes,
under the same lock, and changes nothing:
bregctl plan --runtime-config /etc/breg/runtime.yaml --package /var/lib/breg/build-1/packagePlanned the first activation on this registry; nothing was changed. Run `bregctl apply --initial --package DIR` to activate it. activation initial package digest sha256:ae245974f8da79cd441669fbe0e2461ceb26e216cd1f7f25a7240fd131d20fee registry revision sha256:4877be0dd9ded0447278206d829445780bf93a6cee356bc1526773003acad158 role mode split plan kind initial change count 0 reviewed migration count 0 checks passed migration-role, runtime-write-authority, prerequisites, uninitialized-databaseThen activate. --initial is for the first package in a database that has never had one:
bregctl apply --initial --runtime-config /etc/breg/runtime.yaml --package /var/lib/breg/build-1/packageActivated the first package on this registry. activation initial package digest sha256:ae245974f8da79cd441669fbe0e2461ceb26e216cd1f7f25a7240fd131d20fee schema fingerprint sha256:99bc1da109508fdab4a69c0d0dc6c00efa0cd1c5cff05d4f81ca1460be91ff74 activation id 41f33802-b5f2-4bec-94e0-1d8272839c03Read the activation ledger
Section titled “Read the activation ledger”status reads the ledger without taking the lock:
bregctl status --runtime-config /etc/breg/runtime.yamlThe database runs its active package and is ready. package id facility-registry database id facility-registry-db active package digest sha256:ae245974f8da79cd441669fbe0e2461ceb26e216cd1f7f25a7240fd131d20fee activation id 41f33802-b5f2-4bec-94e0-1d8272839c03 registry revision sha256:4877be0dd9ded0447278206d829445780bf93a6cee356bc1526773003acad158 role mode split schema fingerprint sha256:99bc1da109508fdab4a69c0d0dc6c00efa0cd1c5cff05d4f81ca1460be91ff74 maintenance status ready
activation 1 activation id 41f33802-b5f2-4bec-94e0-1d8272839c03 package digest sha256:ae245974f8da79cd441669fbe0e2461ceb26e216cd1f7f25a7240fd131d20fee registry revision sha256:4877be0dd9ded0447278206d829445780bf93a6cee356bc1526773003acad158 plan kind initial migration kind compiled-additive outcome applied role mode split started at 2026-10-17T11:31:02.621523Z applied at 2026-10-17T11:31:24.938465ZEach later activation adds an entry with its own outcome.
Check every dependency
Section titled “Check every dependency”verify checks the package files against their sums and, when set, package.expectedDigest, and re-derives
every generated artifact, without opening the database:
bregctl verify --runtime-config /etc/breg/runtime.yamlVerified the package against the runtime it is bound to. assurance runtime-bound package digest sha256:ae245974f8da79cd441669fbe0e2461ceb26e216cd1f7f25a7240fd131d20fee registry id facility-registry registry version 0.1.0 registry revision sha256:4877be0dd9ded0447278206d829445780bf93a6cee356bc1526773003acad158doctor opens every startup dependency without binding the listener, stops at the first one that
refuses, and otherwise lists them all, then its advisories. These include the PostgreSQL advisories
and the authentication.insecure-http warning when the runtime file sets
authentication.oidc.allowInsecureHttp: true. Advisories never change the exit status:
bregctl doctor --runtime-config /etc/breg/runtime.yaml10 dependency checks passed. runtimeConfig pass package pass database pass audit pass cursor pass authentication.oidc pass eventDestinations pass reviewBindings pass authentication pass fieldEncryption pass roleMode split
Advisories: information postgres.connections.budget one replica's runtime pool takes at most half of the connections PostgreSQL leaves for ordinary roles poolMaxSize 4 maxConnections 100 superuserReservedConnections 3 reservedConnections 0 usableConnections 97 information postgres.pg-stat-statements.unavailable pg_stat_statements is not installed in this database, so per-statement timings are unavailable when diagnosing loadMonitor and recover explains each advisory and every refusal code doctor can
print.
Start serving
Section titled “Start serving”breg --runtime-config /etc/breg/runtime.yamlStartup refuses a package the ledger does not name as active, and logs the role mode it serves in. Check readiness before admitting traffic:
curl -fsS http://127.0.0.1:8080/ready{"status":"ready"}GET /health and GET /healthz report liveness only. Neither probe reflects the background
workers that deliver webhooks and advance reviews: when one stops, breg exits with status 1, so
run it under a supervisor that restarts it.
Watch the background workers covers what to alert
on.
Serve the container image
Section titled “Serve the container image”The image runs breg --runtime-config /etc/breg/runtime.yaml as the non-root user UID 65532,
exposes port 8080, and carries the matching bregctl at /usr/local/bin/bregctl. It has no shell,
no writable directory, and no health check of its own.
The container serves only a package that activation already recorded. Write a second runtime file
for it, changing exactly four things from the host’s: listener.bind (to 0.0.0.0:8080),
secretProviders.file.root (to /etc/breg/secrets), package.root (to /var/lib/breg/package),
and the database host name in the connection URLs, because the container mounts its own paths and
reaches the database over its own network.
UID 65532 must own the secrets directory, every secret file in it, and the audit directory, with
mode 0700 on each directory. The mounted runtime file and package need only be readable by it:
chown -R 65532:65532 /srv/registry/container/secretschmod 0700 /srv/registry/container/secretsinstall -d -m 0700 -o 65532 -g 65532 /var/log/bregchown -R 65532:65532 /var/log/bregStartup refuses an audit directory or audit file owned by anyone else, including a directory Docker
created as root for a missing mount and one a host-run breg or bregctl left behind. Once the
container owns /var/log/breg, a host-run bregctl is refused it in turn, so plan and apply
from the image.
Then mount the inputs read-only and the audit directory writable:
docker run --restart on-failure \ -p 8080:8080 \ -v /srv/registry/container/runtime.yaml:/etc/breg/runtime.yaml:ro \ -v /var/lib/breg/build-1/package:/var/lib/breg/package:ro \ -v /srv/registry/container/secrets:/etc/breg/secrets:ro \ -v /var/log/breg:/var/log/breg:rw \ "$BREG_IMAGE"BREG_IMAGE is the image digest from the release manifest. Run bregctl verify and
bregctl doctor against this exact runtime file before you rely on its GET /ready. A fault that
recurs on every start makes the container restart repeatedly; the restart policy’s backoff bounds
how often.
Activate from the image
Section titled “Activate from the image”You can plan, apply, and read the ledger from the same image you serve, without installing
bregctl on an operator host. Override the entrypoint and pass the arguments
Activate and serve uses, with the container’s paths:
docker run --rm \ --entrypoint /usr/local/bin/bregctl \ -v /srv/registry/container/runtime.yaml:/etc/breg/runtime.yaml:ro \ -v /var/lib/breg/build-1/package:/var/lib/breg/package:ro \ -v /srv/registry/container/migration-secrets:/etc/breg/secrets:ro \ -v /var/log/breg:/var/log/breg:rw \ "$BREG_IMAGE" \ plan --runtime-config /etc/breg/runtime.yaml --package /var/lib/breg/packageRun apply and status the same way. These commands connect with the migration credential, so
mount a secret directory that holds it, and keep that credential out of the serving container’s
secret directory. Give UID 65532 that directory and its files the same way as the serving
container’s. apply writes audit entries beside audit.path, which is why the audit directory is
writable here too.
Kubernetes is outside the verified deployment profile. A ConfigMap or Secret volume mounted the
default way presents each key as a symbolic link, which the runtime refuses for both the runtime
file and secret files; inject secrets through secret:env/<NAME> instead.
- Monitor and recover to size PostgreSQL, rotate keys, scrape metrics, and read refusal codes.
- Bind webhook receivers when the project declares events; activation refuses until every destination is bound.
- Change an active registry for successor packages, blocked Proposals, and turning on field encryption over existing data.
- Retain, erase, and audit for history erasure and the audit journal.
- Publish a statistical series when the project declares datasets.
- Harden a production deployment for the controls around the listener, the secret root, and the migration credential.