Cephalon Operations
เนื้อหานี้ยังไม่ได้แปลเป็นภาษาไทย แสดงเป็นภาษาอังกฤษแทน
This document captures the current operational surface for Cephalon as of April 29, 2026.
For the active phase-2 follow-through inventory, see docs/operational-hardening-gap-inventory.md.
Generated-app deployment smoke
Section titled “Generated-app deployment smoke”For a repo-native adoption replay that scaffolds a fresh app, seeds the repo-local package feed, publishes the generated host, runs the published output, and validates /health/ready, /engine, /engine/snapshot, and /scalar, run:
pwsh ./scripts/validate-generated-app-publish.ps1See docs/generated-app-publishing.md for the corresponding publish-profile and published-output guidance.
Generated-app cold-start adoption smoke
Section titled “Generated-app cold-start adoption smoke”For a repo-native external-adoption replay that publishes a temporary package feed, installs Cephalon.Cli, runs cephalon doctor, scaffolds a fresh app outside the repository, seeds the generated local package feed, reruns cephalon doctor --app-root, restores, builds, runs the generated host, and validates /health/ready, /engine, /engine/snapshot, and /scalar, run:
pwsh ./scripts/validate-generated-app-adoption.ps1See docs/getting-started.md for the corresponding install, doctor, scaffold, seed, restore, and first-run guidance.
Template-pack cold-start adoption smoke
Section titled “Template-pack cold-start adoption smoke”For a repo-native external-adoption replay that publishes a temporary package feed, installs Cephalon.Cli, installs Cephalon.TemplatePack into an isolated custom hive, reruns cephalon doctor with that custom hive visible, scaffolds a fresh dotnet new cephalon-monolith starter outside the repository, seeds the generated local package feed, reruns cephalon doctor --app-root, restores, builds, runs the generated host, and validates /health/ready, /engine, /engine/snapshot, and /scalar, run:
pwsh ./scripts/validate-template-pack-adoption.ps1See docs/getting-started.md for the corresponding template-pack install, doctor, scaffold, and first-run guidance.
Out-of-tree package parity smoke
Section titled “Out-of-tree package parity smoke”For a repo-native external-adoption replay that publishes a temporary package feed, installs Cephalon.Cli, scaffolds a fresh app outside the repository, packs and stages Cephalon.ReferenceModule.Operations through cephalon package stage, patches Engine:Discovery:PackageDirectories plus Engine:PackagePolicy and Engine:Trust, reruns cephalon doctor --app-root, restores, builds, runs the generated host, and validates /api/operations/status, /engine/packages, /engine/package-policy, /engine/trust-policy, and /engine/snapshot, run:
pwsh ./scripts/validate-out-of-tree-package-adoption.ps1See docs/external-package-lifecycle.md for the corresponding stage, trust, and inspect guidance.
Signed package governance smoke
Section titled “Signed package governance smoke”For a repo-native external-adoption replay that publishes a temporary package feed, installs Cephalon.Cli, scaffolds a fresh app outside the repository, repacks Cephalon.ReferenceModule.Operations with a deterministic detached signature, stages the signed package through cephalon package stage, patches Engine:Discovery:PackageDirectories plus stricter Engine:PackagePolicy and Engine:Trust:TrustedSignaturePublicKeys, reruns cephalon doctor --app-root, restores, builds, runs the generated host, validates /api/operations/status, /engine/packages, /engine/package-policy, /engine/trust-policy, and /engine/snapshot, then proves the same host rejects a tampered signed package when signature verification is required, run:
pwsh ./scripts/validate-signed-package-governance.ps1For the matching certificate-chain trust replay, run:
pwsh ./scripts/validate-signed-package-certificate-chain-governance.ps1That lane reuses the same external-adoption path but patches Engine:Trust:TrustedSignatureCertificates plus Engine:Trust:TrustedSignatureCertificateAuthorities, then proves /engine/packages, /engine/trust-policy, and /engine/snapshot expose trusted-certificate-chain verification plus the signing certificateThumbprint.
See docs/external-package-lifecycle.md for the corresponding detached-signature and trust-governance guidance.
Generated-app Windows Service smoke
Section titled “Generated-app Windows Service smoke”For a repo-native adoption replay that scaffolds a fresh app, seeds the repo-local package feed, publishes the generated host, and previews the shipped Windows Service install/remove scripts against the published output without requiring admin rights, run:
pwsh ./scripts/validate-generated-app-windows-service.ps1See docs/windows-service-deployment.md for the corresponding Windows install, verify, and removal guidance.
Generated-app IIS smoke
Section titled “Generated-app IIS smoke”For a repo-native adoption replay that scaffolds a fresh app, seeds the repo-local package feed, publishes the generated host, verifies the SDK-generated web.config, and previews the shipped IIS install/remove scripts against the published output without requiring admin rights or a live IIS install, run:
pwsh ./scripts/validate-generated-app-iis.ps1See docs/iis-deployment.md for the corresponding Windows hosted-IIS install, verify, and removal guidance.
Generated-app Azure App Service smoke
Section titled “Generated-app Azure App Service smoke”For a repo-native adoption replay that scaffolds a fresh app, seeds the repo-local package feed, publishes the generated host, packages it into the shipped Azure ZIP artifact, and previews the Azure CLI deploy contract without contacting Azure, run:
pwsh ./scripts/validate-generated-app-app-service.ps1See docs/azure-app-service-deployment.md for the corresponding Azure ZIP deploy, WEBSITE_RUN_FROM_PACKAGE, and az webapp deploy guidance.
Generated-app container-image smoke
Section titled “Generated-app container-image smoke”For a repo-native adoption replay that scaffolds a fresh app, seeds the repo-local package feed, previews the shipped build/push contract, builds the generated Docker image, and by default proves push through a local Docker registry, run:
pwsh ./scripts/validate-generated-app-container-image.ps1See docs/container-image-publishing.md for the corresponding provider-neutral image build/tag/push guidance.
Generated-app Azure Container Apps smoke
Section titled “Generated-app Azure Container Apps smoke”For a repo-native adoption replay that scaffolds a fresh app, seeds the repo-local package feed, validates the generated Dockerfile locally, and previews the shipped Azure Container Apps source-deploy contract without contacting Azure, run:
pwsh ./scripts/validate-generated-app-container-apps.ps1See docs/azure-container-apps-deployment.md for the corresponding az containerapp up --source guidance.
Generated-app Kubernetes smoke
Section titled “Generated-app Kubernetes smoke”For a repo-native adoption replay that scaffolds a fresh app, seeds the repo-local package feed, validates the generated Dockerfile locally, and previews the shipped Kubernetes manifest/apply contract without contacting a live cluster, run:
pwsh ./scripts/validate-generated-app-kubernetes.ps1See docs/kubernetes-deployment.md for the corresponding kubectl kustomize, namespace, service, and probe guidance.
Generated-app Linux systemd smoke
Section titled “Generated-app Linux systemd smoke”For a repo-native adoption replay that scaffolds a fresh app, seeds the repo-local package feed, publishes the generated host, and verifies the shipped Linux systemd unit under WSL systemd-analyze, run:
pwsh ./scripts/validate-generated-app-systemd.ps1See docs/linux-systemd-deployment.md for the corresponding Linux install, verify, and systemctl guidance.
Health surfaces
Section titled “Health surfaces”ASP.NET Core hosts that call app.MapCephalon() now expose three health routes:
/health/health/live/health/ready
Health responses are JSON and include the check status, duration, and runtime-specific details such as restart count and the most recent failure context.
When modules or installed packages register IDependencyHealthContributor, those responses also include dependency details. Cephalon.Observability.CassandraDependencies, Cephalon.Observability.ClickHouseDependencies, Cephalon.Observability.ConsulDependencies, Cephalon.Observability.ElasticsearchDependencies, Cephalon.Observability.HttpDependencies, Cephalon.Observability.KafkaDependencies, Cephalon.Observability.MemcachedDependencies, Cephalon.Observability.MongoDbDependencies, Cephalon.Observability.MqttDependencies, Cephalon.Observability.MySqlDependencies, Cephalon.Observability.NatsDependencies, Cephalon.Observability.Neo4jDependencies, Cephalon.Observability.OpenSearchDependencies, Cephalon.Observability.OracleDependencies, Cephalon.Observability.PostgresDependencies, Cephalon.Observability.RabbitMqDependencies, Cephalon.Observability.RedisDependencies, and Cephalon.Observability.SqlServerDependencies are the shipped companion packages for turning external upstreams into that dependency-health surface.
Current semantics:
- liveness stays
Healthywhile the process is alive, even during startup and shutdown transitions - liveness becomes
Unhealthywhen the runtime entersFailedorStopped - liveness becomes
Degradedwhen the runtime is live but one or more dependencies report degraded or unhealthy status - readiness is
Healthyonly when the runtime reachesStarted - readiness is
Unhealthyduring startup, shutdown, stopped, and failed states so traffic can stay off the host until the runtime is actually ready - readiness becomes
Unhealthywhen a required dependency reportsUnhealthy - readiness becomes
Degradedwhen only optional dependencies are degraded or unhealthy, or when required dependencies are degraded without fully failing
Optional tuning through Engine:FailurePolicy:
StartupReadinessDelaykeeps readinessUnhealthyfor a bounded warmup window after startup succeedsShutdownLivenessGracePeriodkeeps livenessHealthywhile shutdown drains, then flips toUnhealthyif the drain window expires before stop completesManualRestartBackoffdelays explicitRestartAsync(...)calls after restartable startup failures- health payloads expose those lifecycle windows through
activeWindow,activeWindowEndsAtUtc, andrestartAvailableAtUtcwhen applicable
Dependency surface
Section titled “Dependency surface”GET /engine/dependencies exposes the dependency-health snapshot currently contributed to the runtime.
This keeps dependency visibility separate from the aggregate health routes:
/engine/dependenciesanswers “what dependencies are currently reporting?”/health/liveanswers “is the process live?”/health/readyanswers “is the runtime ready to take traffic with its current dependency state?”
HTTP dependency probes
Section titled “HTTP dependency probes”Cephalon.Observability.HttpDependencies reads Engine:Observability:DependencyHealth:Http and turns configured external HTTP endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Http": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "catalog-api", "DisplayName": "Catalog API", "Endpoint": "https://catalog.example.com/health", "Method": "GET", "Required": true, "TimeoutSeconds": 5, "ExpectedStatusCodes": [200] } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonHttpDependencyHealth(builder.Configuration);Operational notes:
- the HTTP dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state - if
ExpectedStatusCodesis omitted, standard successful HTTP responses are treated as healthy
Consul dependency probes
Section titled “Consul dependency probes”Cephalon.Observability.ConsulDependencies reads Engine:Observability:DependencyHealth:Consul and turns configured Consul endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Consul": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "service-discovery", "DisplayName": "Service Discovery", "Endpoint": "https://consul.internal.example:8501", "AclToken": "${CONSUL_HTTP_TOKEN}", "Datacenter": "ops-dc", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonConsulDependencyHealth(builder.Configuration);Operational notes:
- the Consul dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- if the configured endpoint is just the Consul base URL, the probe automatically resolves
GET /v1/status/leader - probes support
X-Consul-TokenACL headers plus optional datacenter selection through thedcquery parameter - a non-empty leader response maps to
Healthy; an empty leader response maps toUnhealthy - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
Elasticsearch dependency probes
Section titled “Elasticsearch dependency probes”Cephalon.Observability.ElasticsearchDependencies reads Engine:Observability:DependencyHealth:Elasticsearch and turns configured Elasticsearch endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Elasticsearch": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "search-cluster", "DisplayName": "Search Cluster", "Endpoint": "https://search.internal.example:9200", "ApiKey": "${ELASTICSEARCH_API_KEY}", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonElasticsearchDependencyHealth(builder.Configuration);Operational notes:
- the Elasticsearch dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- if the configured endpoint is just the cluster base URL, the probe automatically resolves
GET /_cluster/health - probes support API-key auth, bearer-token auth, or basic auth without hiding those choices in host code
- cluster
greenmaps toHealthy,yellowmaps toDegraded,redmaps toUnhealthy, and Elasticsearch-sidetimed_outresponses are treated asUnhealthy - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
ClickHouse dependency probes
Section titled “ClickHouse dependency probes”Cephalon.Observability.ClickHouseDependencies reads Engine:Observability:DependencyHealth:ClickHouse and turns configured ClickHouse endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "ClickHouse": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "analytics-clickhouse", "DisplayName": "Analytics ClickHouse", "Host": "analytics.internal.example", "Protocol": "https", "Port": 8443, "Database": "analytics", "Username": "cephalon-runtime", "Password": "${CLICKHOUSE_PASSWORD}", "HealthQuery": "SELECT 1", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonClickHouseDependencyHealth(builder.Configuration);Operational notes:
- the ClickHouse dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- probes can use either a full connection string or discrete
Host/Protocol/Port/Databasesettings so HTTP transport choices stay explicit - each probe opens a dedicated ClickHouse connection, runs the configured SQL health query, and reports the result through the shared dependency-health contract
- required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
OpenSearch dependency probes
Section titled “OpenSearch dependency probes”Cephalon.Observability.OpenSearchDependencies reads Engine:Observability:DependencyHealth:OpenSearch and turns configured OpenSearch endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "OpenSearch": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "catalog-search", "DisplayName": "Catalog Search", "Endpoint": "https://search.internal.example:9200", "Index": "catalog-items", "BearerToken": "${OPENSEARCH_BEARER_TOKEN}", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonOpenSearchDependencyHealth(builder.Configuration);Operational notes:
- the OpenSearch dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- if the configured endpoint is just the cluster base URL, the probe automatically resolves
GET /_cluster/health, and it can append an index-specific path whenIndexis configured - probes support bearer-token auth or basic auth without hiding those choices in host code
- cluster
greenmaps toHealthy,yellowmaps toDegraded,redmaps toUnhealthy, and OpenSearch-sidetimed_outor missing-cluster-manager responses are treated asUnhealthy - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
Redis dependency probes
Section titled “Redis dependency probes”Cephalon.Observability.RedisDependencies reads Engine:Observability:DependencyHealth:Redis and turns configured Redis endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Redis": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "shared-cache", "DisplayName": "Shared Redis Cache", "Host": "redis.internal.example", "Port": 6379, "Required": true, "TimeoutSeconds": 5, "Username": "cephalon-runtime", "Password": "${REDIS_PASSWORD}", "Database": 2 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonRedisDependencyHealth(builder.Configuration);Operational notes:
- the Redis dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- each probe opens a TCP connection, optionally authenticates, optionally selects a logical database, and then verifies
PING->PONG - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
Memcached dependency probes
Section titled “Memcached dependency probes”Cephalon.Observability.MemcachedDependencies reads Engine:Observability:DependencyHealth:Memcached and turns configured Memcached endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Memcached": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "session-cache", "DisplayName": "Session Cache", "Host": "memcached.internal.example", "Port": 11211, "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonMemcachedDependencyHealth(builder.Configuration);Operational notes:
- the Memcached dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- each probe opens a TCP connection and verifies that the Memcached
versioncommand returns a validVERSION ...response - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
Postgres dependency probes
Section titled “Postgres dependency probes”Cephalon.Observability.PostgresDependencies reads Engine:Observability:DependencyHealth:Postgres and turns configured Postgres endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Postgres": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "catalog-db", "DisplayName": "Catalog Database", "Host": "postgres.internal.example", "Port": 5432, "Database": "catalog", "Username": "cephalon-runtime", "Password": "${POSTGRES_PASSWORD}", "SslMode": "Require", "HealthQuery": "SELECT 1;", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonPostgresDependencyHealth(builder.Configuration);Operational notes:
- the Postgres dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- probes can use either a full
ConnectionStringor discrete host/port/database settings - each probe opens a dedicated
Npgsqlconnection with pooling disabled, runs the configured health query, and reports the result through the shared dependency-health contract - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
RabbitMQ dependency probes
Section titled “RabbitMQ dependency probes”Cephalon.Observability.RabbitMqDependencies reads Engine:Observability:DependencyHealth:RabbitMq and turns configured RabbitMQ endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "RabbitMq": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "events-broker", "DisplayName": "Events Broker", "Host": "rabbitmq.internal.example", "Port": 5671, "VirtualHost": "/operations", "Username": "cephalon-runtime", "Password": "${RABBITMQ_PASSWORD}", "UseTls": true, "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonRabbitMqDependencyHealth(builder.Configuration);Operational notes:
- the RabbitMQ dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- probes can use either a full AMQP
ConnectionStringor discrete host/port/vhost settings - each probe opens a dedicated AMQP connection with auto-recovery disabled so the result reflects the current broker reachability and authentication state
- required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
Kafka dependency probes
Section titled “Kafka dependency probes”Cephalon.Observability.KafkaDependencies reads Engine:Observability:DependencyHealth:Kafka and turns configured Kafka clusters into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Kafka": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "events-kafka", "DisplayName": "Events Kafka", "BootstrapServers": "kafka-1.internal.example:9093,kafka-2.internal.example:9093", "ClientId": "cephalon-runtime", "Topic": "cephalon.events", "SecurityProtocol": "SaslSsl", "SaslMechanism": "ScramSha512", "Username": "cephalon-runtime", "Password": "${KAFKA_PASSWORD}", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonKafkaDependencyHealth(builder.Configuration);Operational notes:
- the Kafka dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- each probe requests broker metadata from the configured
BootstrapServerslist and can optionally verify that a specificTopicis present in returned metadata SecurityProtocolandSaslMechanismstay explicit in configuration so hosts can declare plaintext, TLS, or SASL broker expectations without hiding them in host code- required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
SQL Server dependency probes
Section titled “SQL Server dependency probes”Cephalon.Observability.SqlServerDependencies reads Engine:Observability:DependencyHealth:SqlServer and turns configured SQL Server endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "SqlServer": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "orders-sql", "DisplayName": "Orders SQL", "Host": "sql.internal.example", "Port": 1433, "Database": "orders", "Username": "cephalon-runtime", "Password": "${SQL_PASSWORD}", "Encrypt": "Mandatory", "TrustServerCertificate": false, "HealthQuery": "SELECT 1;", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonSqlServerDependencyHealth(builder.Configuration);Operational notes:
- the SQL Server dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- probes can use either a full
ConnectionStringor discrete host/port/database settings - each probe opens a dedicated
SqlConnectionwith pooling disabled, runs the configured health query, and reports the result through the shared dependency-health contract - optional
EncryptandTrustServerCertificatesettings let hosts keep SQL Server or Azure SQL transport expectations explicit instead of hidden in host-specific code - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
MySQL dependency probes
Section titled “MySQL dependency probes”Cephalon.Observability.MySqlDependencies reads Engine:Observability:DependencyHealth:MySql and turns configured MySQL endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "MySql": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "catalog-mysql", "DisplayName": "Catalog MySQL", "Host": "mysql.internal.example", "Port": 3306, "Database": "catalog", "Username": "cephalon-runtime", "Password": "${MYSQL_PASSWORD}", "SslMode": "Required", "AllowPublicKeyRetrieval": false, "HealthQuery": "SELECT 1;", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonMySqlDependencyHealth(builder.Configuration);Operational notes:
- the MySQL dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- probes can use either a full
ConnectionStringor discrete host/port/database settings - each probe opens a dedicated
MySqlConnectionwith pooling disabled, runs the configured health query, and reports the result through the shared dependency-health contract - optional
SslModeandAllowPublicKeyRetrievalsettings let hosts keep MySQL transport and authentication expectations explicit instead of hidden in host-specific code - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
Oracle dependency probes
Section titled “Oracle dependency probes”Cephalon.Observability.OracleDependencies reads Engine:Observability:DependencyHealth:Oracle and turns configured Oracle Database endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Oracle": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "orders-oracle", "DisplayName": "Orders Oracle", "Host": "oracle.internal.example", "Port": 1521, "ServiceName": "ORDERSPDB", "Username": "cephalon-runtime", "Password": "${ORACLE_PASSWORD}", "HealthQuery": "SELECT 1 FROM DUAL", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonOracleDependencyHealth(builder.Configuration);Operational notes:
- the Oracle dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- probes can use either a full
ConnectionStringor discrete host/port/service-name settings - each probe opens a dedicated
OracleConnectionwith pooling disabled, runs the configured health query, and reports the result through the shared dependency-health contract - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
Cassandra dependency probes
Section titled “Cassandra dependency probes”Cephalon.Observability.CassandraDependencies reads Engine:Observability:DependencyHealth:Cassandra and turns configured Cassandra clusters into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Cassandra": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "orders-cassandra", "DisplayName": "Orders Cassandra", "ContactPoints": [ "cass-a.internal.example", "cass-b.internal.example" ], "Port": 9042, "Keyspace": "orders", "Username": "cephalon-runtime", "Password": "${CASSANDRA_PASSWORD}", "HealthQuery": "SELECT release_version FROM system.local;", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonCassandraDependencyHealth(builder.Configuration);Operational notes:
- the Cassandra dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- probes accept
ContactPointsas either an array or a comma-separated scalar value so hosts can keep cluster seed-node configuration explicit - each probe opens a dedicated Cassandra session, optionally selects a keyspace, runs the configured CQL health query, and reports the result through the shared dependency-health contract
- required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
NATS dependency probes
Section titled “NATS dependency probes”Cephalon.Observability.NatsDependencies reads Engine:Observability:DependencyHealth:Nats and turns configured NATS endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Nats": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "events-nats", "DisplayName": "Events NATS", "Host": "nats.internal.example", "Port": 4222, "Token": "${NATS_TOKEN}", "ClientName": "cephalon-runtime", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonNatsDependencyHealth(builder.Configuration);Operational notes:
- the NATS dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- each probe opens a TCP connection, reads the initial server
INFOline, sends a NATSCONNECTpayload, and verifies aPING->PONGround-trip - probes support token-based auth or username/password auth, and TLS stays explicit through
UseTlsandTlsServerName - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
Neo4j dependency probes
Section titled “Neo4j dependency probes”Cephalon.Observability.Neo4jDependencies reads Engine:Observability:DependencyHealth:Neo4j and turns configured Neo4j graph endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Neo4j": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "orders-graph", "DisplayName": "Orders Graph", "Uri": "neo4j://graph.internal.example:7687", "Database": "orders", "Username": "cephalon-runtime", "Password": "${NEO4J_PASSWORD}", "HealthQuery": "RETURN 1 AS health", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonNeo4jDependencyHealth(builder.Configuration);Operational notes:
- the Neo4j dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- probes can use either a full
Urior discreteHost/Port/Schemesettings, so routing and TLS semantics stay explicit through standard Neo4j schemes such asneo4j,neo4j+s,bolt, orbolt+s - each probe opens a dedicated Neo4j driver session, optionally selects a database, runs the configured Cypher health query, and reports the result through the shared dependency-health contract
- required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
MQTT dependency probes
Section titled “MQTT dependency probes”Cephalon.Observability.MqttDependencies reads Engine:Observability:DependencyHealth:Mqtt and turns configured MQTT endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "Mqtt": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "edge-mqtt", "DisplayName": "Edge MQTT", "Host": "mqtt.internal.example", "Port": 8883, "UseTls": true, "TlsServerName": "mqtt.internal.example", "ClientId": "cephalon-runtime", "Username": "cephalon-runtime", "Password": "${MQTT_PASSWORD}", "KeepAliveSeconds": 30, "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonMqttDependencyHealth(builder.Configuration);Operational notes:
- the MQTT dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- each probe opens a TCP connection, optionally upgrades to TLS, sends an MQTT 3.1.1
CONNECT, validatesCONNACK, and verifies aPINGREQ->PINGRESPround-trip - probes keep username/password auth, client identifier, keep-alive interval, and TLS server-name expectations explicit in configuration instead of hiding them in host code
- required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
MongoDB dependency probes
Section titled “MongoDB dependency probes”Cephalon.Observability.MongoDbDependencies reads Engine:Observability:DependencyHealth:MongoDb and turns configured MongoDB endpoints into reusable IDependencyHealthContributor data.
Example:
{ "Engine": { "Observability": { "DependencyHealth": { "MongoDb": { "RefreshIntervalSeconds": 30, "Dependencies": [ { "Id": "catalog-mongodb", "DisplayName": "Catalog MongoDB", "Host": "mongo.internal.example", "Port": 27017, "Database": "catalog", "Username": "cephalon-runtime", "Password": "${MONGODB_PASSWORD}", "AuthSource": "admin", "UseTls": true, "AllowInsecureTls": false, "DirectConnection": true, "HealthCommand": "ping", "Required": true, "TimeoutSeconds": 5 } ] } } } }}Registration:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonMongoDbDependencyHealth(builder.Configuration);Operational notes:
- the MongoDB dependency-health package is optional and stays outside
Cephalon.Engine - the package performs one probe refresh during host startup and then refreshes in the background on the configured interval
- probes can use either a full
ConnectionStringor discrete host/port/database settings - each probe creates a dedicated
MongoClient, runs the configured health command against the selected database, and reports the result through the shared dependency-health contract - optional
UseTls,AllowInsecureTls, andDirectConnectionsettings let hosts keep MongoDB topology and transport expectations explicit instead of hidden in host-specific code - required dependency failures pull readiness to
Unhealthy; optional failures degrade readiness/liveness without hiding the runtime state
Diagnostics surface
Section titled “Diagnostics surface”GET /engine/diagnostics exposes the engine’s operational conventions in one place:
meterNameactivitySourceName- counter names used by the runtime
- execution-graph and hosted-execution transition counters alongside runtime, module, failure, and restart counters
- published diagnostics conventions and event-id catalogs for the active engine and companion packages
- the current liveness report
- the current readiness report
- dependency details folded into those runtime reports
- the mapped health routes
Current shipped event-id ranges include:
Cephalon.Engine:2000-2005Cephalon.MultiTenancy:4500-4502Cephalon.MultiTenancy.Governance:4510-4549,4552-4557Cephalon.MultiTenancy.Governance.HttpDelivery:4550-4551Cephalon.MultiTenancy.Governance.MailgunDelivery:4566-4567Cephalon.MultiTenancy.Governance.MailgunDelivery.AspNetCore:4568-4571Cephalon.MultiTenancy.Governance.MicrosoftGraphDelivery:4572-4573Cephalon.MultiTenancy.Governance.AmazonSesDelivery:4576-4577Cephalon.MultiTenancy.Governance.AmazonSesDelivery.AspNetCore:4578-4584Cephalon.MultiTenancy.Governance.SendGridDelivery:4560-4561Cephalon.MultiTenancy.Governance.SendGridDelivery.AspNetCore:4562-4565Cephalon.MultiTenancy.Governance.SmtpDelivery:4558-4559Cephalon.Observability:3000-3006Cephalon.Observability.Gcp:3111-3111Cephalon.Observability.HuaweiCloud:3112-3112Cephalon.Observability.AlibabaCloud:3113-3113Cephalon.Observability.GrafanaCloud:3119-3119Cephalon.Observability.NewRelic:3154-3154Cephalon.Observability.Kubernetes:3117-3117Cephalon.Observability.OpenShift:3114-3114Cephalon.Observability.DigitalOcean:3115-3115Cephalon.Observability.Tanzu:3116-3116Cephalon.Observability.CassandraDependencies:3146-3147Cephalon.Observability.ConsulDependencies:3142-3143Cephalon.Observability.ElasticsearchDependencies:3138-3139Cephalon.Observability.HttpDependencies:3100-3101Cephalon.Observability.RedisDependencies:3120-3121Cephalon.Observability.PostgresDependencies:3122-3123Cephalon.Observability.RabbitMqDependencies:3124-3125Cephalon.Observability.SqlServerDependencies:3126-3127Cephalon.Observability.MySqlDependencies:3128-3129Cephalon.Observability.MongoDbDependencies:3130-3131Cephalon.Observability.KafkaDependencies:3132-3133Cephalon.Observability.NatsDependencies:3134-3135Cephalon.Observability.MqttDependencies:3136-3137Cephalon.Observability.MemcachedDependencies:3140-3141Cephalon.Observability.OracleDependencies:3144-3145Cephalon.Observability.Neo4jDependencies:3148-3149Cephalon.Observability.OpenSearchDependencies:3150-3151Cephalon.Observability.ClickHouseDependencies:3152-3153
This is the quickest way to discover the engine’s observability contract without opening code.
Runtime story surface
Section titled “Runtime story surface”GET /engine/runtime-story exposes the operator-facing lifecycle narrative in one place:
- the current runtime status and last failure context
- loaded package metadata for the active runtime
- per-execution-graph lifecycle state, including loaded, active, and deactivated timestamps
- per-hosted-execution lifecycle state, including loaded, active, and deactivated timestamps
- per-module lifecycle state, including loaded, initialized, started, and stopped timestamps
- an ordered timeline for package load, execution-graph transitions, hosted-execution transitions, module transitions, runtime transitions, restart attempts, and failures
This is the quickest way to answer the adjacent operational question that /engine/status, /engine/packages, /engine/hosted-executions, /engine/diagnostics, and /engine/snapshot already support in pieces: what loaded, what started, what failed, and why.
Execution graph surface
Section titled “Execution graph surface”GET /engine/execution-graphs exposes the operator-facing execution-graph catalog contributed by active modules.
Current payload highlights:
- each graph carries a stable
id,displayName,description,sourceModuleId, andentryNodeId nodescan point back to module ids and capability keys so orchestration descriptors stay grounded in the existing runtime contractedgesexpose the directed graph transitions plus optional labels or routing conditions- the same execution-graph catalog is also available through
/engine/snapshotwhen operators want one merged runtime answer /engine/runtime-storynow shows when each graph became load-visible, active, or inactive with the runtime lifecycle
Current note:
- this is a descriptive orchestration baseline, not a hosted workflow runner yet
- invalid graph ids, node references, module references, or capability references fail at build time instead of leaking broken operator data
Hosted execution surface
Section titled “Hosted execution surface”GET /engine/hosted-executions exposes the operator-facing hosted or background execution catalog contributed by active modules.
Current payload highlights:
- each hosted execution carries a stable
id,displayName,description,sourceModuleId, andkind executionGraphIdcan point back to one execution graph when the hosted/background surface drives a published workflow directlystartsWithHostmakes the intended host lifecycle relationship explicit for operators without inventing a separate engine-owned runner abstraction- the same hosted-execution catalog is also available through
/engine/snapshotwhen operators want one merged runtime answer /engine/runtime-storynow shows when each hosted execution became load-visible, active, or inactive with the runtime lifecycle
Current note:
- hosted executions are descriptive operator-facing conventions on top of the existing Generic Host and module lifecycle model, not a replacement for
IHostedService,BackgroundService, or module-owned runtime hooks - invalid hosted-execution ids, unknown source modules, or unknown cross-module execution-graph references fail at build time instead of leaking broken operator data
REST runtime surfaces
Section titled “REST runtime surfaces”Cephalon now keeps the full REST publication and governance story introspectable through a linked set of runtime endpoints:
GET /engine/rest-endpointsexposes the final published REST endpoint catalog that ASP.NET Core actually mapped after shorthand authoring, authoring-policy filtering, suppression, and override selection completedGET /engine/rest-endpoint-candidatesexposes the richer candidate catalog behind that final answer, including original shorthand or module-DSL source shape, authoring style, grouped publication ownership, original endpoint metadata, matched rule ids, and final selected/applied governance resultsGET /engine/rest-endpoint-publication-groupsexposes the grouped publication story per behavior and per authoring style so operators can see which styles published, which candidates were suppressed, which explicit groups stayed authoritative, and which host rules were skipped because the targeted route group never opted into host governanceGET /engine/rest-endpoint-authoring-policiesexposes behavior-level shorthand authoring-policy intent such as preferred style, allowed/disallowed styles, and multiple-published-candidate answers without making that grouped summary itself another authoring inputGET /engine/rest-endpoint-suppressionsexposes the active suppression-rule catalog together with matched, suppressed, and skipped candidate outcomes plus grouped selection-basis summariesGET /engine/rest-endpoint-overridesexposes the active override-rule catalog together with matched, applied, and skipped candidate outcomes plus grouped selection-basis and declared-versus-effective action summaries
Current payload highlights:
- the final
/engine/rest-endpointsanswer keepsCandidateId,PublicationGroupId,AuthoringStyle, source behavior/module ownership, and original endpoint metadata lineage visible so operators can jump back to the candidate that produced the published route - behavior-backed REST entries also keep stable ownership metadata visible: publication activation
and profile metadata are
application-managed, materialization/runtime catalog truth iscephalon-managed, andrestPublicationActivationModerecords whether the route came from explicit module DSL,MapProfile<TBehavior>(), generated profile shorthand, or an inline helper HostGovernanceScopes,EndpointNames, original explicitTargetBindings, route group prefixes, OpenAPI document names, tag names, HTTP methods, and effective API major versions are all part of the governable selector story across candidate, suppression, override, publication group, and snapshot answers- explicit module DSL routes stay authoritative by default, but when a group uses
WithHostGovernanceScope(...)the scope still becomes visible for future host targeting even beforeAllowHostGovernance()opts that route into suppressions or overrides - if a host rule wins selection but does not materially change the final published answer, the
runtime keeps the winning rule visible through
SelectedOverrideIdplusOverrideSelectionBasiswhile leavingAppliedOverrideId = null; grouped runtime answers keep the same selected-versus-applied truth so no-op governance does not look like a published change - the same REST publication, candidate, governance, and grouped summaries also flow through
/engine/snapshotso operators can choose one merged runtime answer without losing REST-specific troubleshooting detail
Current note:
- these surfaces describe the governable runtime truth for REST publication, not a second authoring system; module code and host configuration still remain the only authoring inputs
- non-REST transports stay out of these REST catalogs and continue to surface through their own transport-specific runtime contracts
Multi-tenancy technology surfaces
Section titled “Multi-tenancy technology surfaces”When MultiTenancy is selected and Cephalon.MultiTenancy is registered, GET /engine/technology-surfaces and GET /engine/snapshot expose the active tenant runtime answer. When Cephalon.MultiTenancy.Governance is also registered, the same surfaces include concrete tenant-governance proofs.
Current payload highlights:
tenant-resolutionreports configured tenant count, configured tenant ids, default tenant id, domain-resolution posture, tenant-key posture, resolver count, ambient-context accessor count, and the enabled resolution strategiestenant-governance-boundariesreports the shippedtenant-resolution-coreascephalon-managed, marks tenant membership, tenant invitations, tenant administration, declared tenant-domain ownership, and approval/remediation governance actions as shipped companion-owned lanes that requireCephalon.MultiTenancy.Governanceregistration, and keeps broader onboarding, delivery, synchronization, and endpoint/UI workflows outside those owned lanes astaxonomy-onlyboundary entriestenant-membershipsreports the governance companion’s Cephalon-managed membership catalog, store, and evaluation posture, including membership count, tenant count, contributor count, configured membership count, runtime membership count, membership-store kind, membership-store durability, membership-store ownership, durable-store ownership, evaluation ownership, per-tenant status counts, role summaries, principal-kind breakdowns, and contributing module ids without exposing individual principal identifierstenant-invitationsreports the governance companion’s Cephalon-managed invitation catalog, store, validation, delivery-dispatch, opt-in delivery retry queue, process-local retry execution coordination, delivery-status reconciliation, and delivery-status observation-store posture, including invitation count, tenant count, contributor count, configured invitation count, runtime invitation count, invitation-store kind, invitation-store durability, invitation-store ownership, durable-store ownership, validation ownership, retry queue enablement/ownership/kind/durability/scope/counts/latest retry outcome, delivery retry max attempts/delay/max items, retry execution coordination enablement/ownership/scope/mode/in-progress state/counts/latest outcome/timestamps, delivery status reconciliation ownership, observation-store kind/durability/scope/history limit/count/latest observation, external delivery status ownership, delivery status reported count/latest status/latest observed timestamp, delivery sender count/ids/ownership, external delivery ownership, delivery run counts/latest outcome, status breakdown, per-tenant retry counts, per-tenant status counts, role summaries, invitee-kind breakdowns, and contributing module ids without exposing individual invitee identifiers. InstallingCephalon.MultiTenancy.Governance.HttpDeliveryregisters a first-partyhttp-webhooksender that appears in the same sender readiness and run-history metadata instead of creating a separate runtime surface; signed sends record only safehttpSignedplus optionalhttpSigningKeyIdmetadata, idempotent sends record safehttpIdempotencyKey/httpIdempotencyKeySourcemetadata, and retrying sends record safe attempt/retry metadata such ashttpAttemptCount,httpMaxAttempts,httpRetried, andhttpRetryReason. InstallingCephalon.MultiTenancy.Governance.SmtpDeliveryregisters a first-partysmtp-emailsender that appears in the same sender readiness and run-history metadata; SMTP sends record only safe relay host/port/TLS/message-id/recipient metadata and never record SMTP credentials or message bodies. InstallingCephalon.MultiTenancy.Governance.SendGridDeliveryregisters a first-partysendgrid-emailsender on the same dispatcher; SendGrid sends record only safe endpoint/status/sandbox/Cephalon-message-id/recipient/category/custom-argument-count metadata and never record the SendGrid API key or message bodies. InstallingCephalon.MultiTenancy.Governance.MailgunDeliveryregisters a first-partymailgun-emailsender on the same dispatcher; Mailgun sends record only safe endpoint/status/test-mode/domain/Cephalon-message-id/recipient/tag/variable/header-count metadata and never record the Mailgun API key or message bodies. InstallingCephalon.MultiTenancy.Governance.AmazonSesDeliveryregisters a first-partyamazon-ses-emailsender on the same dispatcher; Amazon SES sends record only safe region/configuration-set/status/message-id/recipient/tag metadata and never record AWS credentials, raw SDK payloads, or message bodies. InstallingCephalon.MultiTenancy.Governance.MicrosoftGraphDeliveryregisters a first-partymicrosoft-graph-emailsender on the same dispatcher; Graph sends record only safe endpoint/status/request-id/category/header/recipient metadata and never record bearer tokens, authorization headers, raw payloads, or message bodies.tenant-administrationreports the governance companion’s Cephalon-managed host-driven administration workflow posture, including workflow enablement, membership and invitation administration ownership, membership/invitation store kinds, durability, counts, supported commands, and core-package boundaries for public onboarding, host-adapter endpoint ownership, invitation delivery dispatch, invitation delivery status reconciliation, provider-specific sender ownership, external delivery/status ownership, and identity-provider synctenant-administration-http-endpointsreports the ASP.NET Core governance adapter’s optional command endpoint posture, including route pattern,POSTmethod, mapped/configured/disabled state, authorization requirement, optional policy, endpoint-description visibility, and application-managed boundaries for public onboarding, tenant-admin UI, provider-specific invitation senders, external invitation delivery, and identity-provider synctenant-invitation-delivery-status-http-endpointsreports the ASP.NET Core governance adapter’s optional normalized callback and bounded observation-read endpoint posture, including callback route pattern,POSTmethod, mapped/configured/disabled state, authorization requirement, optional policy, provider-message-match enforcement, endpoint-description visibility, provider-neutral callback signature verification configuration, safe signature header names, signing key-id configuration, timestamp tolerance, signed-callback replay protection policy/key/scope/durability/retention/cache-limit posture, observation read route pattern,GETmethod, authorization posture, response contract, default/max limits, summary ownership/scope/dimensions, attention ownership/categories, provider-message filter ownership/scope, remediation-filter ownership/scope, remediation-hint ownership/actions, and application-managed boundaries for provider-specific callback inboxes, provider-specific payload translation, provider-specific signature verification, provider polling, and distributed remediation executiontenant-invitation-delivery-sendgrid-status-callbacksreports the optional SendGrid ASP.NET Core callback translator’s route/auth/body-limit/event-limit/translation/signature/replay/event-id-idempotency posture, including safe signed-webhook verification metadata, bounded process-local signed-callback replay policy/key/scope/durability/retention/cache-limit truth, and observation-store-backedsg_event_idduplicate-skip truth without exposing SendGrid public keys, raw signatures, recipient emails, or raw payload bodiestenant-invitation-delivery-mailgun-status-callbacksreports the optional Mailgun ASP.NET Core callback translator’s route/auth/body-limit/event-limit/translation/signature/replay/event-id-idempotency posture, including explicitnot-configuredsignature/replay/idempotency truth, bounded process-local token replay metadata, observation-store-backedevent-data.idduplicate-skip truth, and application-managed inbox/polling boundaries without exposing recipient emails or raw payload bodiestenant-domain-ownershipreports the governance companion’s Cephalon-managed declared domain-ownership catalog, store, validation, in-process verification-workflow, proof-challenge issuance, proof-publication planning, HTTP file proof-publication state, proof-evaluation, HTTP file proof-collection, configured DNS TXT proof-collection, proof-verification runner, on-demand proof-polling runner, and opt-in background proof-polling posture, including domain ownership count, tenant count, contributor count, configured domain count, runtime domain ownership count, domain-ownership-store kind, domain-ownership-store durability, domain-ownership-store ownership, durable-store ownership, validation ownership, verification-workflow ownership, proof-challenge issuance ownership, proof-publication planning ownership, HTTP proof-publication ownership, published HTTP proof count, proof-evaluation ownership, HTTP proof-collection ownership, DNS TXT proof-collection enablement, DNS TXT resolver configuration, proof-verification runner ownership, external proof-polling ownership, background proof-polling ownership, background polling interval/batch/run counts/latest outcome, DNS/provider proof-publication ownership, status breakdown, verification-method breakdown, and contributing module ids without exposing individual domain namestenant-governance-actionsreports the governance companion’s Cephalon-managed approval/remediation action catalog, decision, in-process workflow, and action-store posture, including action count, tenant count, contributor count, configured action count, runtime action count, decision ownership, workflow execution ownership, action-store kind, action-store durability, action-store ownership, durable-store ownership, notification-delivery ownership, status breakdown, action-kind breakdown, subject-kind breakdown, and contributing module ids without exposing individual action metadata- boundary entries outside the current membership, invitation, tenant-administration, declared domain-ownership, and governance-action proofs still carry
plannedOwnership = companion-planned,basePackageOwnership = not-owned, andsuggestedPackage = Cephalon.MultiTenancy.Governanceso operators can distinguish current runtime ownership from planned companion work
Current note:
- the base package owns tenant resolution and ambient tenant context only
- the governance companion currently owns tenant membership cataloging/evaluation, opt-in local durable membership state, tenant invitation cataloging/validation, opt-in local durable invitation state, host-agnostic invitation delivery dispatch/run-state/outcome persistence over registered sender extensions, opt-in local invitation delivery retry storage plus bounded retry execution, process-local retry execution coordination, and opt-in automatic background retry scheduling over retryable sender failures, host-agnostic invitation delivery status reconciliation over provider or receiver observations, opt-in local durable delivery-status observation storage for normalized reconciliation records, host-driven tenant-administration workflow commands over membership and invitation stores, declared tenant-domain ownership cataloging/validation, opt-in local durable domain-ownership state, in-process tenant-domain ownership verification workflow transitions, domain proof challenge issuance, domain proof publication planning, HTTP file proof publication state for host adapters, domain proof evaluation over reported evidence, on-demand HTTP file proof collection, configured on-demand DNS TXT proof collection through an explicit DNS-over-HTTPS resolver, domain proof verification runner orchestration, bounded on-demand domain proof polling, opt-in automatic background proof polling scheduling/run-state, approval/remediation action cataloging/decision, in-process approval/remediation action workflow transitions, and opt-in local durable action state
- ASP.NET Core hosts can install
Cephalon.MultiTenancy.Governance.AspNetCore, callMapCephalonTenantDomainOwnershipHttpProofs()to serve published HTTP proof files from the governance catalog, callMapCephalonTenantAdministrationCommands()to exposePOST /engine/tenant-administration/commandsoverTenantAdministrationWorkflowRequest, callMapCephalonTenantInvitationDeliveryDispatches()to expose fail-closedPOST /engine/tenant-invitations/delivery-dispatchesdispatch actions overITenantInvitationDeliveryDispatcher, callMapCephalonTenantInvitationDeliveryStatusCallbacks()to exposePOST /engine/tenant-invitations/delivery-statusover normalizedTenantInvitationDeliveryStatusCallbackRequestpayloads with optional provider-neutral HMAC verification plus bounded process-local signed replay rejection, and callMapCephalonTenantInvitationDeliveryStatusObservations()to expose bounded/filterableGET /engine/tenant-invitations/delivery-status/observationsreads plus filtered rollup summaries, attention-category drill-downs, provider-message drill-downs, remediation-action filters, and remediation hints overITenantInvitationDeliveryStatusObservationStore - hosts can install
Cephalon.MultiTenancy.Governance.HttpDeliveryand callAddCephalonHttpInvitationDelivery(...)when invitation dispatch should POST a generic JSON payload to a configured webhook, include a receiver-facing idempotency key, optionally sign that exact body with HMAC-SHA256, retry transient webhook outcomes within a bounded in-process attempt budget, and still record outcome truth through the governance dispatcher - hosts can install
Cephalon.MultiTenancy.Governance.SmtpDeliveryand callAddCephalonSmtpInvitationDelivery(...)when invitation dispatch should hand a templated email to a configured SMTP relay through a replaceable client seam while still recording outcome truth through the governance dispatcher - hosts can install
Cephalon.MultiTenancy.Governance.SendGridDeliveryand callAddCephalonSendGridInvitationDelivery(...)when invitation dispatch should POST a templated Mail Send API payload to SendGrid through a replaceable client seam while still recording outcome truth through the governance dispatcher - hosts can install
Cephalon.MultiTenancy.Governance.MailgunDeliveryand callAddCephalonMailgunInvitationDelivery(...)when invitation dispatch should POST a templated multipart Messages API payload to Mailgun through a replaceable client seam while still recording outcome truth through the governance dispatcher - hosts can install
Cephalon.MultiTenancy.Governance.AmazonSesDeliveryand callAddCephalonAmazonSesInvitationDelivery(...)when invitation dispatch should send a templated Amazon SES v2SendEmailrequest through a replaceable AWS SDK handoff seam while still recording outcome truth through the governance dispatcher - hosts can install
Cephalon.MultiTenancy.Governance.MicrosoftGraphDeliveryand callAddCephalonMicrosoftGraphInvitationDelivery(...)when invitation dispatch should POST a templated Microsoft GraphsendMailpayload through a replaceable client and access-token provider seam while still recording outcome truth through the governance dispatcher - ASP.NET Core hosts can install
Cephalon.MultiTenancy.Governance.SendGridDelivery.AspNetCoreand callMapCephalonSendGridInvitationDeliveryStatusCallbacks()when SendGrid Event Webhook arrays should be translated into the existing delivery-status reconciler without custom host glue; whenRequireSignedEventWebhookis enabled, the same endpoint can reject duplicate verified signed callbacks inside a bounded process-local replay window - ASP.NET Core hosts can install
Cephalon.MultiTenancy.Governance.MailgunDelivery.AspNetCoreand callMapCephalonMailgunInvitationDeliveryStatusCallbacks()when Mailgun webhook objects should be translated, HMAC-verified, protected against duplicate signed tokens inside a bounded process-local replay window, and de-duplicated by observed Mailgun event id without custom host glue; durable inboxing, distributed replay, and distributed event-id ledgers remain separate follow-through - ASP.NET Core hosts can install
Cephalon.MultiTenancy.Governance.AmazonSesDelivery.AspNetCoreand callMapCephalonAmazonSesInvitationDeliveryStatusCallbacks()when Amazon SNSNotificationenvelopes carrying Amazon SES event publishing payloads should be verified, protected against bounded process-local replay, de-duplicated by observed SNS message id, optionally confirmed for verifiedSubscriptionConfirmationenvelopes, and translated into the existing delivery-status reconciler without custom host glue; SNS topic/subscription creation, durable inboxing, distributed replay, and distributed event-id ledgers remain separate follow-through - hosts can enable
EnableInvitationDeliveryRetryQueuewhensender-faileddispatch outcomes should be retained for an explicitITenantInvitationDeliveryRetryRunner.RetryPendingAsync(...)pass; configureInvitationDeliveryRetryQueueFilePathonly when the local retry queue should survive process restarts - the tenant-administration command endpoint is fail-closed by default; keep
RequireTenantAdministrationAuthorization = truefor real hosts, setTenantAdministrationAuthorizationPolicywhen a named ASP.NET Core policy should guard the command surface, and disable authorization only for deliberate internal/test hosts - the delivery status callback and observation read endpoints are fail-closed by default; keep
RequireTenantInvitationDeliveryStatusCallbackAuthorization = trueandRequireTenantInvitationDeliveryStatusObservationAuthorization = truefor real hosts, set the related authorization policy when a named ASP.NET Core policy should guard callback ingress or observation reads, keepRequireTenantInvitationDeliveryStatusCallbackProviderMessageMatch = trueunless the host deliberately owns another correlation boundary, and keep provider-neutral signed callback replay protection enabled whenTenantInvitationDeliveryStatusCallbackSigningSecretis configured - the SendGrid callback endpoint is also fail-closed by default; keep
RequireStatusCallbackAuthorization = truefor real hosts, enableRequireSignedEventWebhookwith a SendGrid public key when callbacks should be verified before parsing, and keepEnableSignedEventWebhookReplayProtection = trueunless the host has a stronger replay boundary outside Cephalon - actual DNS proof publication, provider-backed proof publication or mutation, remediation execution beyond state transitions, distributed or provider-backed membership/invitation/domain/action-store backends, additional provider-specific email API senders beyond the shipped SMTP/SendGrid/Mailgun/Amazon SES/Microsoft Graph set, SMS/chat/CRM/identity-provider invitation senders, distributed retry queues, provider-specific or distributed callback inboxes, cross-node callback replay protection, provider-specific delivery-status callback payload translation beyond shipped SendGrid/Mailgun/Amazon SES translators, provider-specific callback signature verification beyond shipped SendGrid/Mailgun/Amazon SNS hardening, provider polling, identity-provider synchronization, public onboarding, and tenant-admin UI/backoffice flows remain future companion work until a package owns those paths explicitly
Tenant-administration command endpoint configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "AspNetCore": { "EnableTenantAdministrationCommandEndpoint": true, "TenantAdministrationCommandRoutePattern": "/engine/tenant-administration/commands", "RequireTenantAdministrationAuthorization": true, "TenantAdministrationAuthorizationPolicy": "tenant-admin", "ExcludeTenantAdministrationEndpointFromDescription": true } } } }}Tenant-invitation delivery retry queue configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "EnableInvitationDeliveryRetryQueue": true, "InvitationDeliveryRetryMaxAttempts": 3, "InvitationDeliveryRetryDelaySeconds": 300, "InvitationDeliveryRetryMaxItems": 25, "EnableInvitationDeliveryRetryExecutionCoordination": true, "EnableInvitationDeliveryRetryBackgroundScheduling": true, "InvitationDeliveryRetryBackgroundIntervalSeconds": 300, "InvitationDeliveryRetryBackgroundRunOnStartup": true, "InvitationDeliveryRetryBackgroundSource": "background-invitation-delivery-retry", "InvitationDeliveryRetryQueueFilePath": "App_Data/cephalon/invitation-delivery-retries.json" } } }}When the retry queue is enabled, retryable sender-failed dispatch outcomes are queued with a stable tenant/invitation/channel/sender boundary and can be replayed by calling ITenantInvitationDeliveryRetryRunner.RetryPendingAsync(...). Process-local execution coordination is enabled by default for the retry runner; an overlapping manual/background pass returns already-running and leaves the retry queue untouched instead of dispatching the same local entries concurrently. Background scheduling remains disabled by default; set EnableInvitationDeliveryRetryBackgroundScheduling deliberately when the current process should run the same bounded retry runner on startup and on the configured interval. This stays a local process scheduler with a process-local overlap guard, not a distributed queue, cross-node lease, provider-specific sender, or exactly-once delivery system.
Tenant-invitation delivery status callback endpoint configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "AspNetCore": { "EnableTenantInvitationDeliveryStatusCallbackEndpoint": true, "TenantInvitationDeliveryStatusCallbackRoutePattern": "/engine/tenant-invitations/delivery-status", "RequireTenantInvitationDeliveryStatusCallbackAuthorization": true, "TenantInvitationDeliveryStatusCallbackAuthorizationPolicy": "tenant-delivery-status", "ExcludeTenantInvitationDeliveryStatusCallbackEndpointFromDescription": true, "RequireTenantInvitationDeliveryStatusCallbackProviderMessageMatch": true, "TenantInvitationDeliveryStatusCallbackSigningSecret": "${TENANT_INVITATION_STATUS_CALLBACK_SECRET}", "TenantInvitationDeliveryStatusCallbackSigningKeyId": "primary-2026-04", "TenantInvitationDeliveryStatusCallbackSignatureHeaderName": "X-Cephalon-Callback-Signature", "TenantInvitationDeliveryStatusCallbackSignatureTimestampHeaderName": "X-Cephalon-Callback-Signature-Timestamp", "TenantInvitationDeliveryStatusCallbackSignatureKeyIdHeaderName": "X-Cephalon-Callback-Key-Id", "TenantInvitationDeliveryStatusCallbackSignatureToleranceSeconds": 300, "EnableTenantInvitationDeliveryStatusCallbackReplayProtection": true, "TenantInvitationDeliveryStatusCallbackReplayRetentionSeconds": 300, "TenantInvitationDeliveryStatusCallbackReplayCacheLimit": 4096, "EnableTenantInvitationDeliveryStatusObservationEndpoint": true, "TenantInvitationDeliveryStatusObservationRoutePattern": "/engine/tenant-invitations/delivery-status/observations", "RequireTenantInvitationDeliveryStatusObservationAuthorization": true, "TenantInvitationDeliveryStatusObservationAuthorizationPolicy": "tenant-delivery-status-observations", "ExcludeTenantInvitationDeliveryStatusObservationEndpointFromDescription": true, "TenantInvitationDeliveryStatusObservationDefaultLimit": 100, "TenantInvitationDeliveryStatusObservationMaxLimit": 500 } } } }}HTTP invitation delivery configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "HttpInvitationDelivery": { "Enabled": true, "SenderId": "http-webhook", "Endpoint": "https://notifications.internal.example/invitations", "Method": "POST", "TimeoutSeconds": 10, "MaxAttempts": 3, "RetryDelayMilliseconds": 250, "RetryStatusCodes": [408, 429, 500, 502, 503, 504], "RetryTransportFailures": true, "EnableIdempotencyHeader": true, "IdempotencyHeaderName": "X-Cephalon-Idempotency-Key", "IdempotencyMetadataKey": "idempotencyKey", "ExpectedStatusCodes": [202], "SupportedChannels": ["email", "webhook"], "SigningSecret": "${INVITATION_DELIVERY_SIGNING_SECRET}", "SigningKeyId": "primary-2026-04", "SignatureHeaderName": "X-Cephalon-Webhook-Signature", "SignatureTimestampHeaderName": "X-Cephalon-Webhook-Signature-Timestamp", "SignatureKeyIdHeaderName": "X-Cephalon-Webhook-Key-Id", "ProviderMessageIdHeaderName": "X-Cephalon-Provider-Message-Id", "Headers": { "X-Delivery-Key": "${INVITATION_DELIVERY_KEY}" } } } } }}Registration:
builder.Services.AddCephalonHttpInvitationDelivery(builder.Configuration);
builder.AddCephalon(engine =>{ engine.AddMultiTenancyGovernance();});Operational notes:
ExpectedStatusCodesis optional; when omitted, any successful 2xx response is accepted as dispatched- unsupported channels return
suppressedand are still recorded as provider-managed sender decisions - keep
EnableIdempotencyHeaderenabled when receivers should de-duplicate retry attempts; callers can pass the configuredIdempotencyMetadataKeyin dispatch metadata to supply their own stable header-safe key, overlong or header-unsafe metadata values are deterministically hashed, and otherwise the sender derives a hashed key from tenant id, invitation id, channel, and sender id - set
SigningSecretwhen receivers should verify the webhook body; the sender signs{unixTimestamp}.{jsonBody}with HMAC-SHA256, sends the signature asv1=<lowercase hex>, and records onlyhttpSignedplus optionalhttpSigningKeyIdmetadata - set
MaxAttemptsabove 1 when a host wants bounded in-process retry; the sender retries non-acceptedRetryStatusCodesand, whenRetryTransportFailuresis true, transientHttpRequestExceptionfailures using the fixedRetryDelayMillisecondsdelay inside the configured timeout budget - failed HTTP status codes, timeouts, and transport exceptions return
sender-failed; response bodies are not copied into metadata unlessIncludeResponseBodyInMetadatais enabled and then only up toResponseBodyMetadataLimit; retry metadata records attempts and retry reasons without copying secrets or webhook signatures - custom headers and signing secrets are added as configured, so hosts should source secrets from their normal configuration provider and avoid committing raw delivery credentials
SMTP invitation delivery sender
Section titled “SMTP invitation delivery sender”Install Cephalon.MultiTenancy.Governance.SmtpDelivery when invitation dispatch should hand a templated email to an SMTP relay instead of posting a webhook.
Configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "SmtpInvitationDelivery": { "Enabled": true, "SenderId": "smtp-email", "Host": "smtp.internal.example", "Port": 587, "UseSsl": true, "UserName": "${SMTP_USER}", "Password": "${SMTP_PASSWORD}", "FromAddress": "noreply@example.com", "FromDisplayName": "Example SaaS", "RecipientAddressMetadataKey": "email", "SupportedChannels": ["email"], "MessageIdDomain": "mail.example.com", "SubjectTemplate": "Invitation for {tenantId}", "TextBodyTemplate": "You have been invited to tenant {tenantId}. Invitation: {invitationId}. Roles: {roles}.", "Headers": { "X-Product": "Example SaaS" } } } } }}Registration:
builder.Services.AddCephalonSmtpInvitationDelivery(builder.Configuration);
builder.AddCephalon(engine =>{ engine.AddMultiTenancyGovernance();});Operational notes:
- recipient email resolution checks dispatch metadata first, invitation metadata second, and finally
InviteeIdwhenInviteeKindisemail ISmtpInvitationDeliveryClientis replaceable, so test hosts or provider-specific wrappers can reuse the same Cephalon sender contract without changing the governance dispatcher- deterministic SMTP
Message-Idvalues are derived from tenant id, invitation id, channel, and sender id so retry attempts for the same dispatch boundary can be correlated safely - sender metadata records relay host, port, TLS posture, message id, sender id, recipient address, recipient metadata key, and safe client metadata, but it does not record SMTP username, password, message bodies, or unsafe headers
- this package owns SMTP relay handoff only; Mailgun Messages API handoff lives in
Cephalon.MultiTenancy.Governance.MailgunDelivery, SendGrid Mail Send handoff lives inCephalon.MultiTenancy.Governance.SendGridDelivery, Amazon SES v2 handoff lives inCephalon.MultiTenancy.Governance.AmazonSesDelivery, and Microsoft GraphsendMailhandoff lives inCephalon.MultiTenancy.Governance.MicrosoftGraphDelivery, while additional provider-specific email API senders beyond the shipped SMTP/SendGrid/Mailgun/Amazon SES/Microsoft Graph set, SMS, chat, CRM, identity-provider onboarding, bounce handling, provider polling, distributed retry queues, callback inboxes, and tenant-admin UI remain future provider-pack or application-owned work
Amazon SES invitation delivery sender
Section titled “Amazon SES invitation delivery sender”Install Cephalon.MultiTenancy.Governance.AmazonSesDelivery when invitation dispatch should hand a templated email to Amazon SES v2 instead of posting a generic webhook, using SMTP directly, or using another dedicated email API provider.
Configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "AmazonSesInvitationDelivery": { "Enabled": true, "SenderId": "amazon-ses-email", "RegionSystemName": "us-east-1", "ConfigurationSetName": "cephalon-invitations", "FromEmail": "noreply@example.com", "FromName": "Example SaaS", "ReplyToAddresses": ["support@example.com"], "RecipientEmailMetadataKey": "email", "SupportedChannels": ["email"], "SubjectTemplate": "Invitation for {tenantId}", "TextBodyTemplate": "You have been invited to tenant {tenantId}. Invitation: {invitationId}. Roles: {roles}.", "HtmlBodyTemplate": "<p>You have been invited to tenant <strong>{tenantId}</strong>.</p>", "Tags": { "source": "tenant-invitation" }, "AcceptedStatusCodes": [200] } } } }}Registration:
builder.Services.AddCephalonAmazonSesInvitationDelivery(builder.Configuration);
builder.AddCephalon(engine =>{ engine.AddMultiTenancyGovernance();});Operational notes:
- recipient email resolution checks dispatch metadata first, invitation metadata second, and finally
InviteeIdwhenInviteeKindisemail IAmazonSesInvitationDeliveryClientis replaceable, so test hosts, gateway wrappers, or custom AWS SDK policies can reuse the same Cephalon sender contract without changing the governance dispatcher- the default client uses the AWS SDK for .NET SES v2
SendEmailAPI and accepts a successful200 OKresponse with a SESMessageIdas dispatched handoff truth - AWS credentials, IAM policy, verified identities, DKIM/SPF/DMARC, sandbox exit, account-level suppression policy, and SES configuration-set event destinations stay with the host/AWS account rather than
Cephalon.Engine - sender metadata records region, configuration set, SES status code, SES message id, Cephalon message id, sender id, recipient email, recipient metadata key, reply-to count, tag count, and safe client metadata, but it does not record AWS credentials, raw SDK request bodies, or message bodies
- this package owns Amazon SES v2 accepted handoff only; Amazon SES over SNS callback translation, opt-in SNS signature verification, bounded process-local SNS replay protection, observation-store-backed SNS message-id idempotency, opt-in verified SNS subscription confirmation, and opt-in verified SNS unsubscribe-confirmation observation live in
Cephalon.MultiTenancy.Governance.AmazonSesDelivery.AspNetCore, while SNS topic/subscription creation, SES event destination setup, automatic resubscribe/restore, subscription lifecycle governance, provider polling, durable callback inboxes, distributed replay/event-id ledgers, deliverability analytics, SMS, chat, CRM, identity-provider onboarding, distributed retry queues, and tenant-admin UI remain future provider-pack or application-owned work
Amazon SES invitation delivery status callbacks
Section titled “Amazon SES invitation delivery status callbacks”Install Cephalon.MultiTenancy.Governance.AmazonSesDelivery.AspNetCore when Amazon SES event publishing sends SNS HTTP notifications and the host wants those events translated into the existing invitation delivery-status reconciler.
Configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "AmazonSesInvitationDelivery": { "AspNetCore": { "EnableStatusCallbackEndpoint": true, "StatusCallbackRoutePattern": "/engine/tenant-invitations/delivery-status/amazon-ses", "RequireStatusCallbackAuthorization": true, "StatusCallbackAuthorizationPolicy": "amazon-ses-sns", "RequireProviderMessageMatch": true, "RecordStatus": true, "Source": "amazon-ses-sns", "Actor": "amazon-ses", "MaxRequestBodyBytes": 262144, "MaxEventsPerRequest": 1000, "MapEngagementEventsAsDelivered": false, "AcceptRawSesEventPayloads": true, "RequireSnsSignatureVerification": true, "RequireSnsSignatureVersion2": true, "RequireAllowedSnsTopicArn": true, "AllowedSnsTopicArns": [ "arn:aws:sns:us-east-1:123456789012:cephalon-governance" ], "ValidateSnsSigningCertificateChain": true, "EnableSnsReplayProtection": true, "SnsReplayRetentionSeconds": 300, "SnsReplayCacheLimit": 4096, "EnableSnsMessageIdIdempotency": true, "EnableSnsSubscriptionConfirmation": false, "SnsSubscriptionConfirmationTimeoutSeconds": 10, "EnableSnsUnsubscribeConfirmationObservation": false } } } } }}Registration:
builder.Services.AddCephalonAmazonSesInvitationDeliveryAspNetCore(builder.Configuration);
builder.AddCephalon(engine =>{ engine.AddMultiTenancyGovernance();});
var app = builder.Build();app.MapCephalonAmazonSesInvitationDeliveryStatusCallbacks();Operational notes:
- the endpoint parses bounded SNS
NotificationJSON, unwraps the SES event JSON inMessage, and can accept raw SES event objects or arrays for controlled replay/test harness scenarios whenAcceptRawSesEventPayloadsstays enabled - when
RequireSnsSignatureVerificationis enabled, the endpoint rejects raw SES replay payloads, requires an allowedTopicArnby default, requires SNSSignatureVersion2 by default, validates the HTTPS Amazon SNS signing-certificate URL, validates the certificate unless a host deliberately disables chain validation for pinned test certificates, and verifies the RSA signature before mapping or reconciliation - when
EnableSnsReplayProtectionis enabled with SNS signature verification, the endpoint stores a bounded process-local fingerprint derived from the verifiedTopicArnplusMessageIdand rejects duplicate verified callbacks with409 Conflictbefore reconciliation - when
EnableSnsMessageIdIdempotencyis enabled with the governance observation store, the endpoint checks the normalizedamazon-ses-sns:{MessageId}observation id before reconciliation, skips already observed SNS messages withduplicateEvents, and reports diagnostic4581; durability follows the configured observation store and is not a distributed event-id ledger - when
EnableSnsSubscriptionConfirmationis enabled with SNS signature verification, the endpoint confirms only verified SNSSubscriptionConfirmationenvelopes from allowed topics through the replaceableIAmazonSesSnsSubscriptionConfirmationClient; the built-in client performs a bounded no-redirectGETto a trusted HTTPS Amazon SNSSubscribeURL, returns confirmation aggregate fields, and emits diagnostics4582or4583 - when
EnableSnsUnsubscribeConfirmationObservationis enabled with SNS signature verification, the endpoint observes only verified SNSUnsubscribeConfirmationenvelopes from allowed topics, validates the trusted HTTPS Amazon SNSSubscribeURL, returns unsubscribe-confirmation aggregate fields, emits diagnostic4584, and never invokesSubscribeURL - the translator extracts Cephalon context from SES
mail.tags, including tenant id, invitation id, channel, sender id, and correlation id, and usesmail.messageIdas the provider message id captured by the SES sender Sendmaps toaccepted,Deliverymaps todelivered, transientBouncemaps todeferred, otherBouncemaps tobounced,ComplaintandRejectmap tosuppressed,Rendering Failuremaps tofailed, andDeliveryDelaymaps todeferred;Open,Click, andSubscriptionare skipped by defaultPinnedSnsSigningCertificatePemcan be used for controlled tests or deliberate certificate pinning; production hosts usually leave it unset so the endpoint retrieves the AWS SNS signing certificate from the validatedSigningCertURLUnsubscribeConfirmationstays skipped unless unsubscribe-confirmation observation is enabled; automatic topic/subscription provisioning, SES event-destination setup, automatic resubscribe/restore, token storage, and subscription lifecycle governance remain outside this package- the runtime surface reports whether SNS signature verification is required, whether signature version 2 and topic allow-listing are required, how many allowed topic ARNs are configured, whether pinned certificate or chain validation paths are active, whether process-local replay protection is configured, whether observation-store-backed SNS message-id idempotency is configured, whether verified subscription confirmation is configured, and whether verified unsubscribe-confirmation observation is configured
- keep endpoint authorization, gateway policy, SNS topic policy, private networking, or AWS WAF controls in place as defense in depth; SNS topic/subscription setup, topic policies, automatic resubscribe/restore, subscription lifecycle governance, durable inboxes, distributed replay ledgers, distributed event-id ledgers, and provider polling remain separate follow-through
Mailgun invitation delivery sender
Section titled “Mailgun invitation delivery sender”Install Cephalon.MultiTenancy.Governance.MailgunDelivery when invitation dispatch should hand a templated email to the Mailgun Messages API instead of posting a generic webhook, using SMTP directly, or using SendGrid.
Configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "MailgunInvitationDelivery": { "Enabled": true, "SenderId": "mailgun-email", "BaseUrl": "https://api.mailgun.net", "DomainName": "mg.example.com", "ApiKey": "${MAILGUN_API_KEY}", "FromEmail": "noreply@example.com", "FromName": "Example SaaS", "RecipientEmailMetadataKey": "email", "SupportedChannels": ["email"], "SubjectTemplate": "Invitation for {tenantId}", "TextBodyTemplate": "You have been invited to tenant {tenantId}. Invitation: {invitationId}. Roles: {roles}.", "HtmlBodyTemplate": "<p>You have been invited to tenant <strong>{tenantId}</strong>.</p>", "Tags": ["cephalon-invitation"], "Variables": { "product": "example-saas" }, "Headers": { "X-Product": "Example SaaS" }, "EnableTestMode": false, "ProviderMessageIdJsonPropertyName": "id", "AcceptedStatusCodes": [200] } } } }}Registration:
builder.Services.AddCephalonMailgunInvitationDelivery(builder.Configuration);
builder.AddCephalon(engine =>{ engine.AddMultiTenancyGovernance();});Operational notes:
- recipient email resolution checks dispatch metadata first, invitation metadata second, and finally
InviteeIdwhenInviteeKindisemail - set
BaseUrltohttps://api.eu.mailgun.netfor Mailgun EU regional sending; the package always posts to/v3/{DomainName}/messages IMailgunInvitationDeliveryClientis replaceable, so test hosts, gateway wrappers, or custom HTTP policies can reuse the same Cephalon sender contract without changing the governance dispatcher- the sender carries deterministic Cephalon message ids through Mailgun
v:*user variables and safeh:*headers, and captures the JSONidresponse property as the provider message id by default EnableTestModeaddso:testmode=yesso Mailgun processes the request without delivering to recipients- sender metadata records endpoint host, Mailgun status code, configured domain, test-mode posture, Cephalon message id, sender id, recipient email, recipient metadata key, tag count, variable count, header count, and safe client metadata, but it does not record the API key, authorization header, raw request body, or message bodies
- this package owns Mailgun Messages API handoff only; Mailgun webhook callback translation, optional HMAC signed-webhook verification, bounded process-local replay-token rejection, and observation-store-backed event-id idempotency live in
Cephalon.MultiTenancy.Governance.MailgunDelivery.AspNetCore, Amazon SES v2 handoff lives inCephalon.MultiTenancy.Governance.AmazonSesDelivery, Microsoft GraphsendMailhandoff lives inCephalon.MultiTenancy.Governance.MicrosoftGraphDelivery, while additional provider-specific email API senders beyond the shipped SMTP/SendGrid/Mailgun/Amazon SES/Microsoft Graph set, SMS, chat, CRM, identity-provider onboarding, bounce handling, provider polling, distributed retry queues, callback inboxes, and tenant-admin UI remain future provider-pack or application-owned work
Mailgun invitation delivery status callbacks
Section titled “Mailgun invitation delivery status callbacks”Cephalon.MultiTenancy.Governance.MailgunDelivery.AspNetCore translates Mailgun webhook payloads into the existing tenant-invitation delivery-status reconciler. It is optional and separate from the outbound Mailgun sender so hosts can choose whether Mailgun should call back into the application.
Configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "MailgunInvitationDelivery": { "AspNetCore": { "EnableStatusCallbackEndpoint": true, "StatusCallbackRoutePattern": "/engine/tenant-invitations/delivery-status/mailgun", "RequireStatusCallbackAuthorization": true, "StatusCallbackAuthorizationPolicy": "mailgun-webhook", "ExcludeStatusCallbackEndpointFromDescription": true, "RequireProviderMessageMatch": true, "RecordStatus": true, "Source": "mailgun-webhook", "Actor": "mailgun", "MaxRequestBodyBytes": 262144, "MaxEventsPerRequest": 1000, "MapEngagementEventsAsDelivered": false, "NormalizeProviderMessageIdWithAngleBrackets": true, "RequireSignedWebhook": true, "WebhookSigningKey": "${MAILGUN_WEBHOOK_SIGNING_KEY}", "SignedWebhookSignatureToleranceSeconds": 300, "AcceptParentSignature": true, "EnableSignedWebhookReplayProtection": true, "SignedWebhookReplayRetentionSeconds": 300, "SignedWebhookReplayCacheLimit": 4096, "EnableWebhookEventIdIdempotency": true } } } } }}Registration:
builder.Services.AddCephalonMailgunInvitationDelivery(builder.Configuration);builder.Services.AddCephalonMailgunInvitationDeliveryAspNetCore(builder.Configuration);
builder.AddCephalon(engine =>{ engine.AddMultiTenancyGovernance();});
var app = builder.Build();app.MapCephalonMailgunInvitationDeliveryStatusCallbacks();Operational notes:
- Mailgun posts webhook payloads as JSON event objects; the endpoint also accepts JSON arrays for controlled replay and test harness scenarios, with bounded body size and event count
- the outbound sender stores Cephalon context in Mailgun
v:*user variables; callback events withoutcephalonTenantIdandcephalonInvitationIdare skipped instead of being attached to the wrong invitation message.headers.message-idis wrapped in angle brackets by default so it can match the Mailgun Messages API JSONidcaptured during dispatch- delivery events map narrowly:
acceptedtoaccepted,deliveredtodelivered,failedplus temporary severity todeferred,failedplus permanent severity tobounced, otherfailedevents tofailed, andcomplained/unsubscribedtosuppressed;openedandclickedare skipped unless a host deliberately enables engagement-event mapping - set
RequireSignedWebhookplusWebhookSigningKeywhen the endpoint should verify Mailgun’s HMAC-SHA256 signature overtimestamp + tokenbefore translation or reconciliation; missing, malformed, stale, or invalid signatures fail closed with401 - keep
AcceptParentSignatureenabled when Mailgun subaccount events should verify against the parent account signing key throughsignature.parent-signature - keep
EnableSignedWebhookReplayProtection = trueunless the host has a stronger replay boundary outside Cephalon; duplicate verified Mailgun tokens are rejected with409inside the bounded process-local retention window and only SHA-256 token fingerprints are retained - keep
EnableWebhookEventIdIdempotency = trueunless the host owns a stronger callback inbox or idempotency ledger; duplicate translatedevent-data.idvalues are skipped before reconciliation when the normalizedmailgun:{event-data.id}observation id already exists inITenantInvitationDeliveryStatusObservationStore - the endpoint is authorization-required by default and should stay protected by ASP.NET Core policy, a gateway, Mailgun TLS client-certificate checks, or another host-owned control even when signed-webhook verification is enabled
- responses include aggregate and per-event translation outcomes plus
DuplicateEventsbut do not echo recipient email addresses or raw Mailgun payloads - the package projects
tenant-invitation-delivery-mailgun-status-callbackswith route/auth/translation/signature/replay/event-id-idempotency posture, including safe HMAC verification metadata, process-local token replay metadata, and observation-store-backed event-id idempotency metadata when configured; it still does not claim durable callback inboxes, distributed replay protection, distributed event-id ledgers, provider polling, or exactly-once delivery
SendGrid invitation delivery sender
Section titled “SendGrid invitation delivery sender”Install Cephalon.MultiTenancy.Governance.SendGridDelivery when invitation dispatch should hand a templated email to the SendGrid Mail Send API instead of posting a generic webhook or using SMTP directly.
Configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "SendGridInvitationDelivery": { "Enabled": true, "SenderId": "sendgrid-email", "BaseUrl": "https://api.sendgrid.com", "ApiKey": "${SENDGRID_API_KEY}", "FromEmail": "noreply@example.com", "FromName": "Example SaaS", "RecipientEmailMetadataKey": "email", "SupportedChannels": ["email"], "SubjectTemplate": "Invitation for {tenantId}", "TextBodyTemplate": "You have been invited to tenant {tenantId}. Invitation: {invitationId}. Roles: {roles}.", "HtmlBodyTemplate": "<p>You have been invited to tenant <strong>{tenantId}</strong>.</p>", "Categories": ["cephalon-invitation"], "CustomArgs": { "product": "example-saas" }, "Headers": { "X-Product": "Example SaaS" }, "EnableSandboxMode": false, "ProviderMessageIdHeaderName": "X-Message-ID", "AcceptedStatusCodes": [202] } } } }}Registration:
builder.Services.AddCephalonSendGridInvitationDelivery(builder.Configuration);
builder.AddCephalon(engine =>{ engine.AddMultiTenancyGovernance();});Operational notes:
- recipient email resolution checks dispatch metadata first, invitation metadata second, and finally
InviteeIdwhenInviteeKindisemail - set
BaseUrltohttps://api.eu.sendgrid.comfor SendGrid EU regional sending; the package always posts to/v3/mail/send ISendGridInvitationDeliveryClientis replaceable, so test hosts, gateway wrappers, or custom HTTP policies can reuse the same Cephalon sender contract without changing the governance dispatcher- the sender carries deterministic Cephalon message ids through SendGrid
custom_argsand safeX-Cephalon-*headers, and captures SendGrid’sX-Message-IDresponse header as the provider message id by default EnableSandboxModeaddsmail_settings.sandbox_mode.enable = trueand treats SendGrid’s sandbox200 OKvalidation response as accepted alongside the normal202 Acceptedresponse- sender metadata records endpoint host, SendGrid status code, sandbox posture, Cephalon message id, sender id, recipient email, recipient metadata key, category count, custom-argument count, and safe client metadata, but it does not record the API key, authorization header, raw request body, or message bodies
- this package owns SendGrid Mail Send API handoff only; SendGrid Event Webhook callback translation, optional signed-webhook verification, bounded process-local signed-callback replay protection, and observation-store-backed SendGrid event-id idempotency live in
Cephalon.MultiTenancy.Governance.SendGridDelivery.AspNetCore, Mailgun Messages API handoff lives inCephalon.MultiTenancy.Governance.MailgunDelivery, Amazon SES v2 handoff lives inCephalon.MultiTenancy.Governance.AmazonSesDelivery, Microsoft GraphsendMailhandoff lives inCephalon.MultiTenancy.Governance.MicrosoftGraphDelivery, while durable callback inboxes, distributed replay protection, provider polling, dynamic-template lifecycle management, additional provider-specific email API senders beyond the shipped SMTP/SendGrid/Mailgun/Amazon SES/Microsoft Graph set, SMS, chat, CRM, identity-provider onboarding, distributed retry queues, and tenant-admin UI remain future provider-pack or application-owned work
Microsoft Graph invitation delivery sender
Section titled “Microsoft Graph invitation delivery sender”Install Cephalon.MultiTenancy.Governance.MicrosoftGraphDelivery when invitation dispatch should hand a templated email to Microsoft Graph sendMail instead of posting a generic webhook, using SMTP directly, or using a dedicated email API provider.
Configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "MicrosoftGraphInvitationDelivery": { "Enabled": true, "SenderId": "microsoft-graph-email", "BaseUrl": "https://graph.microsoft.com", "ApiVersion": "v1.0", "SenderUserId": "invites@example.com", "AccessToken": "${MICROSOFT_GRAPH_ACCESS_TOKEN}", "RecipientEmailMetadataKey": "email", "SupportedChannels": ["email"], "SubjectTemplate": "Invitation for {tenantId}", "TextBodyTemplate": "You have been invited to tenant {tenantId}. Invitation: {invitationId}. Roles: {roles}.", "HtmlBodyTemplate": "<p>You have been invited to tenant <strong>{tenantId}</strong>.</p>", "SaveToSentItems": false, "Categories": ["cephalon-invitation"], "Headers": { "X-Cephalon-Product": "Example SaaS" }, "AcceptedStatusCodes": [202] } } } }}Registration:
builder.Services.AddCephalonMicrosoftGraphInvitationDelivery(builder.Configuration);builder.Services.AddCephalonMicrosoftGraphInvitationDeliveryAzureIdentity(builder.Configuration);
builder.AddCephalon(engine =>{ engine.AddMultiTenancyGovernance();});Operational notes:
- recipient email resolution checks dispatch metadata first, invitation metadata second, and finally
InviteeIdwhenInviteeKindisemail IMicrosoftGraphInvitationDeliveryAccessTokenProvideris replaceable; real hosts should usually installCephalon.MultiTenancy.Governance.MicrosoftGraphDelivery.AzureIdentityforDefaultAzureCredential, managed identity, or workload identity token acquisition instead of storing a static access token in configurationIMicrosoftGraphInvitationDeliveryClientis replaceable, so test hosts, gateway wrappers, or custom HTTP policies can reuse the same Cephalon sender contract without changing the governance dispatcher- the sender posts to
/v1.0/users/{SenderUserId}/sendMailwhenSenderUserIdis configured and/v1.0/me/sendMailotherwise; Microsoft Graph accepts successfulsendMailrequests with202 Accepted, so Cephalon records accepted handoff truth rather than a delivered-email claim - the sender carries deterministic Cephalon message ids through safe custom
x-*internet message headers and request metadata; Graph does not return a mail message id fromsendMail, so the default provider message id remains empty unless a custom client supplies a truthful id - sender metadata records endpoint host, Graph status code, sender id, sender-user posture, save-to-sent-items posture, recipient email, recipient metadata key, category count, safe header count, Graph request ids, and safe client metadata, but it does not record bearer tokens, authorization headers, raw request bodies, or message bodies
- this package owns Microsoft Graph
sendMailhandoff only; Azure Identity token acquisition lives inCephalon.MultiTenancy.Governance.MicrosoftGraphDelivery.AzureIdentity, while Microsoft Entra app registration, permission consent, mailbox provisioning/access policy, Graph change notifications, delivery completion after accepted handoff, provider polling, durable callback inboxes, additional provider-specific email API senders beyond the shipped SMTP/SendGrid/Mailgun/Amazon SES/Microsoft Graph set, SMS/chat/CRM/identity-provider onboarding, distributed retry queues, and tenant-admin UI remain future provider-pack or application-owned work
Microsoft Graph Azure Identity token provider
Section titled “Microsoft Graph Azure Identity token provider”Install Cephalon.MultiTenancy.Governance.MicrosoftGraphDelivery.AzureIdentity when the Microsoft Graph invitation sender should acquire bearer tokens through Azure.Identity instead of a static configured access token.
Configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "MicrosoftGraphInvitationDelivery": { "AzureIdentity": { "Enabled": true, "Scopes": ["https://graph.microsoft.com/.default"], "TenantId": "00000000-0000-0000-0000-000000000000", "ManagedIdentityClientId": "11111111-1111-1111-1111-111111111111", "AuthorityHost": "AzurePublicCloud", "ExcludeInteractiveBrowserCredential": true, "ExcludeManagedIdentityCredential": false } } } } }}Registration:
builder.Services.AddCephalonMicrosoftGraphInvitationDelivery(builder.Configuration);builder.Services.AddCephalonMicrosoftGraphInvitationDeliveryAzureIdentity(builder.Configuration);Operational notes:
- the default scope is
https://graph.microsoft.com/.default, which is the normal application-permission shape for service-style Graph access - supported authority aliases are
AzurePublicCloud,AzureGovernment, andAzureChina; an absolute HTTPS authority URI is also accepted for deliberate sovereign/private-cloud setups - explicit
TokenCredentialinjection is available for tests, shared host credential factories, or hosts that prefer a concrete credential such asManagedIdentityCredential - token acquisition diagnostics use
4574-4575and record credential type, scope count, expiry, and failure reason without logging bearer tokens - the package owns token acquisition only; Microsoft Entra app registration,
Mail.Sendconsent, Exchange mailbox/application access policy, GraphsendMailacceptance, downstream delivery completion, provider polling, callbacks, and identity-provider synchronization remain outside this package
SendGrid invitation delivery status callbacks
Section titled “SendGrid invitation delivery status callbacks”Cephalon.MultiTenancy.Governance.SendGridDelivery.AspNetCore translates SendGrid Event Webhook payloads into the existing tenant-invitation delivery-status reconciler. It is optional and separate from the outbound SendGrid sender so hosts can choose whether SendGrid should call back into the application.
Configuration:
{ "Engine": { "MultiTenancy": { "Governance": { "SendGridInvitationDelivery": { "AspNetCore": { "EnableStatusCallbackEndpoint": true, "StatusCallbackRoutePattern": "/engine/tenant-invitations/delivery-status/sendgrid", "RequireStatusCallbackAuthorization": true, "StatusCallbackAuthorizationPolicy": "sendgrid-event-webhook", "ExcludeStatusCallbackEndpointFromDescription": true, "RequireProviderMessageMatch": true, "RecordStatus": true, "Source": "sendgrid-event-webhook", "Actor": "sendgrid", "MaxRequestBodyBytes": 262144, "MaxEventsPerRequest": 1000, "MapEngagementEventsAsDelivered": false, "NormalizeProviderMessageIdFromSgMessageId": true, "RequireSignedEventWebhook": true, "SignedEventWebhookPublicKey": "${SENDGRID_EVENT_WEBHOOK_PUBLIC_KEY}", "SignedEventWebhookSignatureHeaderName": "X-Twilio-Email-Event-Webhook-Signature", "SignedEventWebhookTimestampHeaderName": "X-Twilio-Email-Event-Webhook-Timestamp", "SignedEventWebhookSignatureToleranceSeconds": 300, "EnableSignedEventWebhookReplayProtection": true, "SignedEventWebhookReplayRetentionSeconds": 300, "SignedEventWebhookReplayCacheLimit": 4096, "EnableEventWebhookEventIdIdempotency": true } } } } }}Registration:
builder.Services.AddCephalonSendGridInvitationDelivery(builder.Configuration);builder.Services.AddCephalonSendGridInvitationDeliveryAspNetCore(builder.Configuration);
builder.AddCephalon(engine =>{ engine.AddMultiTenancyGovernance();});
var app = builder.Build();app.MapCephalonSendGridInvitationDeliveryStatusCallbacks();Operational notes:
- SendGrid posts Event Webhook payloads as a JSON array; the endpoint rejects oversized bodies and event batches before reconciliation
- the outbound sender stores Cephalon context in SendGrid
custom_args; callback events withoutcephalonTenantIdandcephalonInvitationIdare skipped instead of being attached to the wrong invitation sg_message_idis normalized to the prefix before the first dot by default so it can match theX-Message-IDprovider message id captured during Mail Send dispatch- delivery events map narrowly:
processedtoaccepted,deliveredtodelivered,deferredtodeferred,bouncetobounced, anddropped/spamreport/unsubscribe/group_unsubscribetosuppressed;openandclickare skipped unless a host deliberately enables engagement-event mapping - set
RequireSignedEventWebhookplusSignedEventWebhookPublicKeywhen the endpoint should verify SendGrid’s ECDSA-SHA256 signature before JSON parsing or reconciliation; the signature input is the timestamp header plus the exact raw request body bytes, not re-serialized JSON - keep
EnableSignedEventWebhookReplayProtectionenabled when signed verification is required; duplicate verified signatures insideSignedEventWebhookReplayRetentionSecondsreturn409before reconciliation and are reported through diagnostic4564 - the replay guard stores only safe signature fingerprints in a bounded in-memory cache;
SignedEventWebhookReplayCacheLimitcontrols the per-process cap, and the runtime surface reportsprocess-localscope plusnonedurability so operators do not confuse it with a distributed callback inbox - keep
EnableEventWebhookEventIdIdempotencyenabled when provider retries might produce the samesg_event_idwith a fresh timestamp/signature; translated duplicates are skipped before reconciliation, return200withDuplicateEvents, and are reported through diagnostic4565 - event-id idempotency uses the normalized
sendgrid:{sg_event_id}observation id inITenantInvitationDeliveryStatusObservationStore; it iscephalon-managedonly when the governance observation store is enabled, and its durability follows that store, so in-memory stores are process-local while the built-in file store can retain observed ids locally - the endpoint is authorization-required by default and should stay protected by ASP.NET Core policy, a gateway, or SendGrid OAuth token validation even when signed Event Webhook verification is enabled
- responses include aggregate and per-event translation outcomes but do not echo recipient email addresses or raw SendGrid payloads
- the package projects
tenant-invitation-delivery-sendgrid-status-callbackswith signature verification, process-local replay posture, and observation-store-backed event-id idempotency posture; it still does not claim durable callback inboxes, distributed replay protection, distributed event-id ledgers, provider polling, or exactly-once delivery
Data product surface
Section titled “Data product surface”GET /engine/data-products exposes the operator-facing data product catalog contributed by active modules.
Current payload highlights:
- each data product carries a stable
id,displayName,description,sourceModuleId,domainId,contractId, andmode tagsand free-formmetadatalet a module publish freshness, classification, and other operator-facing data mesh hints without tying the engine to one provider or federation model- the same data product catalog is also available through
/engine/snapshotwhen operators want one merged runtime answer
Current note:
- the baseline is intentionally descriptor-first: query execution still belongs to the owning module or data pack, while the engine owns the runtime catalog
- invalid data-product source-module ownership fails at build time instead of leaking broken operator metadata
Projection surface
Section titled “Projection surface”GET /engine/projections exposes the operator-facing projection catalog contributed by active modules.
Current payload highlights:
- each projection carries a stable
id,displayName,description,sourceModuleId,targetStoreId, andmode sourceContracts,tags, and free-formmetadatakeep the projected read model grounded in the surrounding CQRS or event-driven contract without tying the engine to one storage provider- the same projection catalog is also available through
/engine/snapshotwhen operators want one merged runtime answer
Current note:
- this is a descriptive runtime catalog for the active composition, not an Entity Framework-specific implementation contract yet
- invalid projection source-module ownership fails at build time instead of leaking broken operator metadata
Outbox surface
Section titled “Outbox surface”GET /engine/outboxes exposes the operator-facing outbox catalog contributed by active modules and companion packs.
Current payload highlights:
- each outbox carries a stable
id,displayName,description,sourceModuleId,provider, andmode channelIds,tags, and free-formmetadatalet a pack say whether the outbox is channel-scoped, what provider owns it, and whether dispatch/runtime linking is configured yet- the same outbox catalog is also available through
/engine/snapshotwhen operators want one merged runtime answer
Current note:
- this is a descriptive runtime answer for durable outbound staging surfaces, not a claim that Cephalon already ships a full event dispatch bridge
- invalid outbox source-module ownership fails at build time instead of leaking broken operator metadata
CDC capture surface
Section titled “CDC capture surface”GET /engine/cdc-captures exposes the operator-facing CDC capture catalog contributed by active modules.
Current payload highlights:
- each CDC capture carries a stable
id,displayName,description,sourceModuleId,provider,sourceId,outboxId,mode, andeventFormat resourceIds,tags, and free-formmetadatalet a module publish the table, collection, or resource scope plus operator-facing capture hints without tying the engine to one provider runtimeexecutionBindingnow keeps authored/requested/effective execution-runtime truth on the same descriptor surface, including the resolved ownership mode, execution topology, and selection reason- the same CDC capture catalog is also available through
/engine/snapshotwhen operators want one merged runtime answer - drill-down routes narrow the same catalog by capture id, source module, provider, outbox, source, and resource through
/engine/cdc-captures/{cdcCaptureId},/engine/cdc-captures/modules/{moduleId},/engine/cdc-captures/providers/{provider},/engine/cdc-captures/outboxes/{outboxId},/engine/cdc-captures/sources/{sourceId}, and/engine/cdc-captures/resources/{resourceId} /engine/cdc-captures/execution-runtimes/{executionRuntimeId}now exposes the inverse view for every capture effectively owned by one execution runtime
Current note:
- the surface is still descriptor-first, but it is no longer descriptor-only:
Cephalon.Data.MongoDBnow ships the first provider-native capture implementation through configured MongoDB change streams while the engine still owns the catalog, outbox linkage, capture-side execution binding, and validation - provider packs can contribute a capture on behalf of another module without rewriting authored ownership; when that happens,
sourceModuleIdstays authoritative and metadata can also surfacecontributorModuleId - invalid authored source-module ownership or missing outbox references still fail at build time instead of leaking broken operator metadata
CDC capture runtime-state surface
Section titled “CDC capture runtime-state surface”GET /engine/cdc-captures/runtime exposes the latest operator-facing CDC runtime-state catalog
reported for active captures.
Current payload highlights:
- each runtime-state entry keeps the descriptor-owned identity (
cdcCaptureId,sourceModuleId,provider,sourceId,outboxId,mode,eventFormat, andresourceIds) alongside the latest reportedlastOutcome,lastObservedAtUtc, checkpoint/change-id/error details, and latest/total captured-change plus produced-message counts executionBindingkeeps the same authored/requested/effective execution-runtime answer visible on the live state surface, so runtime reports do not need to infer capture ownership back out of metadata-only hints- each runtime-state entry now also carries typed
freshness,lag, andpublicationanswers so provider packs can surface freshness windows, pending source-change counts, and pending publication counts without forcing hosts or operators to parse ad-hoc metadata - shared in-process execution can now also report
acknowledgementandacknowledgerServiceTypemetadata on successful staged-batch acknowledgement, while acknowledgement failures keepfailureKind = acknowledgementplus pending checkpoint/change-id metadata visible without falsely advancing the durable checkpoint answer - the catalog projects active captures even before the first provider report arrives, so operators can still see declared ownership and linked outbox identity before execution starts
- when the linked publication path already reports runtime truth,
outboxDispatchStatecarries the latest downstream dispatch posture directly on the same CDC runtime answer instead of forcing a second join back through/engine/event-dispatches - when
AddData()enables the shared CDC execution substrate, the same runtime also exposes thedata-cdc-capture-flowexecution graph plus thedata-cdc-capture-pumphosted execution through/engine/execution-graphs,/engine/hosted-executions,/engine/runtime-story, and/engine/snapshot; that execution graph now includes the explicitacknowledge-cdc-progressstep between outbox staging and runtime-state reporting, while the per-capture CDC routes remain the detailed ownership and runtime-state truth for each active capture - the same runtime-state catalog is also available through
/engine/snapshotinCdcCaptureStateswhen operators want one merged runtime answer - drill-down routes narrow the same runtime-state catalog by capture id, source module, provider,
outbox, source, and resource through
/engine/cdc-captures/runtime/{cdcCaptureId},/engine/cdc-captures/runtime/modules/{moduleId},/engine/cdc-captures/runtime/providers/{provider},/engine/cdc-captures/runtime/outboxes/{outboxId},/engine/cdc-captures/runtime/sources/{sourceId}, and/engine/cdc-captures/runtime/resources/{resourceId} - that same runtime-state catalog now also supports reporter-, edge-, and coordination-aware
drill-down through
/engine/cdc-captures/runtime/reporters/{reporterId},/engine/cdc-captures/runtime/edge-nodes/{edgeNodeId},/engine/cdc-captures/runtime/reporter-coordination/{coordinationState}, and/engine/cdc-captures/runtime/reporter-coordination/issues/{degradedReason} /engine/cdc-captures/runtime/execution-runtimes/{executionRuntimeId}now exposes the inverse runtime-state view for every capture effectively owned by one execution runtime- when
DataRuntimeOptions.EnableExternalCdcRuntimeReporting = true,POST /engine/cdc-capture-runtimes/{executionRuntimeId}/reportsacceptsCdcCaptureRuntimeObservation[]payloads for that runtime, validates effective ownership per capture, enforces declared reporter and edge-node policy when present, and refreshes the same runtime-state catalog instead of a separate external-monitor surface reporterCoordinationnow also keeps participant-levelreporterParticipantsplus additivehasStandbyReporters,hasRejectedReporters,participantCount,activeReporterCount,standbyReporterCount, andrejectedReporterCountsummaries so operators can see which reporters are currently active, waiting in standby after takeover, or explicitly rejected for lease conflicts without inferring that story from metadata alone- that same
reporterCoordinationanswer now also publishestakeoverState,degradedReason,requiresTakeover, andhasCompletedTakeover, so operator flows can distinguishawaiting-takeover,rejected-reporter-conflict, andmultiple-active-reportersposture directly on the shared capture/runtime-state surface - later accepted reports now clear stale rejected-conflict evidence and completed takeovers now
stop surfacing previous owners as standby participants after the replacement reporter reaffirms
its lease, while
previousReporterId,leaseExpiredAtUtc, andlastTakeoverObservedAtUtcstill preserve the historical handoff story
Current note:
- the shared runtime-state catalog is reporter-driven and descriptor-backed: the shared
Cephalon.Datapump is one in-process execution substrate, andCephalon.Data.MongoDBnow also reports provider-native change-stream posture through the same surface instead of inventing a MongoDB-only monitor - provider packs can now project typed freshness, lag, publication posture, bounded capture batches, checkpoints, reporter identity, reporter lease, edge provenance, and failure metadata through the shared contract today, while later out-of-process or edge-aware CDC execution topologies should stay additive over the same capture/runtime-state and execution-runtime surfaces instead of a second host-only registry
CDC capture execution-runtime surface
Section titled “CDC capture execution-runtime surface”GET /engine/cdc-capture-runtimes exposes the operator-facing CDC execution-runtime catalog
derived from active data packs plus the shared CDC runtime-state surface.
Current payload highlights:
- each execution runtime carries a stable
id,displayName,description, boundedcdcCaptureIds, first-classexecutionOwnership,executionTopology,acknowledgementMode,hostedExecutionId,executionGraphId,reporterLeaseSeconds,rejectConflictingReporterIds, declarededgeNodeIds, and operator-facingmetadata summarycarries the aggregate latest-plus-total runtime answer for that execution runtime, including reported capture ids, latest outcome/observation time, latest checkpoint/change id, aggregate started/captured/idle/failed counts, total captured changes, total produced messages, latest acknowledgement posture, latest error,lastReporterId,activeReporterId,reporterLeaseExpiresAtUtc,observedEdgeNodeIds,lastEdgeNodeId, and typedreporterCoordination- that same
reporterCoordinationanswer now keeps participant-levelreporterParticipantsplus additivehasStandbyReporters,hasRejectedReporters,participantCount,activeReporterCount,standbyReporterCount, andrejectedReporterCountsummaries so runtime-first operator views can explain active versus standby versus rejected reporters directly - that same runtime-first coordination answer now also keeps
takeoverState,degradedReason,requiresTakeover, andhasCompletedTakeover, so operators can read whether one runtime is awaiting failover, already completed a takeover, still carrying rejected conflicts, or exposing a multiple-active ambiguity without re-deriving it from raw lease timestamps - later accepted reports now clear stale rejected-conflict evidence and completed takeovers now stop surfacing historical previous owners as standby participants after the replacement reporter has reasserted lease ownership, while the same summary still keeps historical takeover fields available for operator readback
- the same execution-runtime catalog is also available through
/engine/snapshotinCdcCaptureExecutionRuntimeswhen operators want one merged runtime answer - the drill-down route
/engine/cdc-capture-runtimes/{executionRuntimeId}narrows the same catalog to one execution runtime by stable id - that same runtime-first catalog now also supports reporter-, edge-, and coordination-aware
drill-down through
/engine/cdc-capture-runtimes/reporters/{reporterId},/engine/cdc-capture-runtimes/edge-nodes/{edgeNodeId},/engine/cdc-capture-runtimes/reporter-coordination/{coordinationState}, and/engine/cdc-capture-runtimes/reporter-coordination/issues/{degradedReason} /engine/cdc-captures*and/engine/cdc-captures/runtime*now also carry first-classexecutionBindingplus typedreporterCoordinationanswers, so runtime-first and capture-first ownership views stay aligned even when an external reporter lease expires, a new reporter takes over, a conflicting reporter is rejected, or two captures make one runtime look multiply active- host-level
AddData(... configure => configure.CdcExecutionRuntimes ...)or otherDataRuntimeOptions.CdcExecutionRuntimesdeclarations can publish external-managed, provider-native, edge, or other runtime answers on the same catalog without falsely implying the engine hosts those runners itself - when
DataRuntimeOptions.EnableExternalCdcRuntimeReporting = true,POST /engine/cdc-capture-runtimes/{executionRuntimeId}/reportsreturns the refreshed descriptor for that runtime after merging the supplied observations into the shared runtime-state catalog, including refreshed reporter-lease and observed-edge-node summaries when they apply
Current note:
- the shipped shared
Cephalon.Dataruntime contributesdata-cdc-capture-pumpwithexecutionOwnership = host-managed,executionTopology = shared-in-process-polling,acknowledgementMode = post-stage-provider, and links back todata-cdc-capture-flowplusdata-cdc-capture-pump;/engine/cdc-captures*and/engine/cdc-captures/runtime*remain the detailed per-capture ownership and live-posture surfaces, while the shared pump now executes only captures whose effective owner resolves to that runtime - the first shipped provider-native runtime is
mongodb-change-stream-capture-pumpfromCephalon.Data.MongoDB; it publishesexecutionOwnership = host-managed,executionTopology = provider-native,acknowledgementMode = provider-native, links tomongodb-change-stream-capture-flow, and keeps resume-token checkpoint truth on the same per-capture runtime-state catalog - the external report-ingest route is additive and opt-in, not a second ownership source: capture ownership still comes from
executionBinding, and the route rejects reports that do not match the effectiveexecutionRuntimeId
Inbox surface
Section titled “Inbox surface”GET /engine/inboxes exposes the operator-facing inbox catalog contributed by active modules and companion packs.
Current payload highlights:
- each inbox carries a stable
id,displayName,description,sourceModuleId,provider, andmode channelIds,tags, and free-formmetadatalet a pack say whether the inbox is channel-scoped, what provider owns it, and whether idempotency or dispatch/runtime linking is configured yet- the same inbox catalog is also available through
/engine/snapshotwhen operators want one merged runtime answer
Current note:
- this is a descriptive runtime answer for processed-message or idempotency-store surfaces, not a claim that Cephalon already ships a full subscription-dispatch runtime
- invalid inbox source-module ownership fails at build time instead of leaking broken operator metadata
Event dispatch runtime surfaces
Section titled “Event dispatch runtime surfaces”GET /engine/event-dispatch-runtimes exposes named dispatch-runtime descriptors when an eventing
pack contributes the abstraction-level descriptor catalog. GET /engine/event-dispatches exposes
the latest per-outbox dispatch-state reports when an eventing pack contributes the abstraction-level
runtime catalog.
Current payload highlights:
- dispatch-runtime descriptors carry the runtime id, display name, description, ownership metadata,
owned outbox ids, and an aggregate
Summaryonce live dispatch reports exist - dispatch-runtime summaries include total report counts, retry-pending outbox count,
terminal-failure observation count, terminal outbox count, and
HasTerminalFailures - dispatch states carry the outbox id, latest channel id, latest outcome, observation timestamp, message id, attempt, started/succeeded/failed/retry-scheduled/skipped counters, retry-pending posture, terminal-failure posture, terminal-failure count, optional error, and safe metadata
GET /engine/event-dispatch-runtimes/{dispatchRuntimeId}narrows the descriptor catalog to one runtime and returns404when no matching descriptor existsGET /engine/event-dispatches/{outboxId}narrows the state catalog to one outbox path and returns404when no state has been reported for that pathGET /engine/event-dispatches/terminal-failuresfilters the same state catalog to outbox paths whose latest report marks the dispatch path as terminally failed- the same descriptor and state catalogs are also available through
/engine/snapshotinEventDispatchRuntimesandEventDispatchStateswhen operators want one merged runtime answer
Current note:
- terminal-failure posture is an operator/drill-down answer over dispatch reports and supported dispatch-store state; it is not a broker-specific dead-letter queue, durable inbox, generic inbound broker-consumption, downstream delivery-completion, or cross-node exactly-once claim
- outbox-backed publication states use
acceptedto mean “staged for later dispatch”; dispatch completion and terminal dispatch failure remain separate event-dispatch runtime answers
Event publication action and runtime-state surfaces
Section titled “Event publication action and runtime-state surfaces”POST /engine/event-publications requests one bounded event publication when an eventing pack
registers the abstraction-level IEventPublicationDispatcher.
GET /engine/event-publications/runtime exposes the latest publication runtime states when the
selected runtime registers the abstraction-level IEventPublicationRuntimeCatalog.
Current payload highlights:
- the request body carries
id,channelId,eventType, JSON or stringpayload,occurredAtUtc,contentType,correlationId,tenantId, optional headers, safe metadata, and optional actor id - the response is
EventPublicationResultwith the publication id, channel id, event type,acceptedoutcome, accepted timestamp, and safe route-trigger metadata such astrigger = aspnetcore-operator-routeandroute = /engine/event-publications - the route returns
404when event publication is not active in the selected runtime or when the requested channel is not registered, and400when the publication body is invalid - when the core in-process lane is selected, the route triggers the active
IEventPublisher, invokes matchingIEventSubscriptionExecutorservices, and flows publication metadata back into the existing subscription runtime catalog aspublicationMetadata.* - each runtime-state entry carries the publication id, latest channel id, event type, latest outcome, observation timestamp, accepted/succeeded/failed/skipped counters, latest subscription counts, optional error summary, and safe metadata
GET /engine/event-publications/runtime/{publicationId}narrows the same catalog to one publication and returns404when no state has been reported for that publicationGET /engine/event-publications/runtime/channels/{channelId}narrows the same catalog to one channel and returns the reported publication states for that channel- the same publication-state catalog is also available through
/engine/snapshotinEventPublicationStateswhen operators want one merged runtime answer
Current note:
- this is a bounded operator action over the active eventing publication path; the in-process lane can optionally suppress duplicate completed executions process-locally, and the runtime-state catalog reports that local publication outcome, but the route is not a durable broker, durable inbox, cross-node idempotency, retry-queue, distributed scheduler, or provider-specific inbound-consumption claim
- outbox-backed publication states use
acceptedto mean “staged for later dispatch”; downstream dispatch completion remains the job of the dispatch-runtime and dispatch-state surfaces - the action and read contracts live in
Cephalon.Abstractions.DatasoCephalon.EngineandCephalon.AspNetCorecan expose them without referencingCephalon.Eventing; the selected eventing pack still owns the implementation and runtime truth
Event subscription readiness surface
Section titled “Event subscription readiness surface”GET /engine/event-subscription-readiness exposes the operator-facing readiness catalog for
declared event subscriptions when an eventing pack registers the abstraction-level
IEventSubscriptionExecutionReadinessCatalog.
Current payload highlights:
- each readiness entry carries a stable
subscriptionId,readinessState,executionOwnership,executionMode, optionalexecutionRuntimeId, ordered machine-readablereasons, and safe metadata readinessStateis one ofruntime-bound,hosted-execution-linked,application-managed-state, ordeclared-only, so declared subscriptions do not look execution ready until a managed binding, hosted execution link, or runtime report existsGET /engine/event-subscription-readiness/{subscriptionId}narrows the same catalog to one declared subscription and returns404when that subscription does not exist- the same readiness catalog is also available through
/engine/snapshotinEventSubscriptionExecutionReadinesswhen operators want one merged runtime answer
Current note:
- the contract lives in
Cephalon.Abstractions.DatasoCephalon.Engineand host adapters can expose it without referencingCephalon.Eventing; the eventing pack or an optional companion still owns the implementation and runtime truth
Agent tool run surface
Section titled “Agent tool run surface”GET /engine/agent-tool-runs exposes the operator-facing run-state catalog for agent-tool runs
when an agentics pack registers the abstraction-level IAgentToolRunCatalog.
POST /engine/agent-tools/{toolId}/runs requests one bounded managed tool run when the active
runtime also registers the abstraction-level IAgentToolDispatcher.
Current payload highlights:
- each run entry carries a stable
toolId,runId, latest outcome, latest observation timestamp, actor/correlation details, attempt number, outcome counters, retry-scheduled count, output/error summaries, and safe metadata requiresApproval,retryPending,duplicateCompleted,terminalFailure, andisTerminalkeep policy waits, process-local retry waits, duplicate-completed suppression, terminal failed executor outcomes, and final success, failure, skipped, or denied outcomes separateGET /engine/agent-tool-runs/retry-pendingfilters the same catalog to runs whose latest report isretry-scheduledGET /engine/agent-tool-runs/idempotency-duplicatesfilters the same catalog to runs whose latest report is a process-local duplicate-completed suppressionGET /engine/agent-tool-runs/approval-requiredfilters the same catalog to runs whose latest report is waiting on an explicit policy approval decisionGET /engine/agent-tool-runs/terminal-failuresfilters the same catalog to runs whose latest report is a terminalfailedoutcomeGET /engine/agent-tool-runs/{runId}narrows the same catalog to one reported run and returns404when that run does not existGET /engine/agent-tool-runs/by-tool/{toolId}narrows the same catalog to all runs reported for one tool idPOST /engine/agent-tools/{toolId}/runsaccepts optional body fields forrunId,actorId,correlationId,attempt, stringarguments, and safemetadata, generates route-owned defaults when they are absent, returns theAgentToolExecutionResult, returns404when execution is not active or the tool id is unknown, and returns409when the tool exists but no executor is registered- the same run-state catalog is also available through
/engine/snapshotinAgentToolRunswhen operators want one merged runtime answer
Current note:
- the read and action contracts live in
Cephalon.Abstractions.AgenticssoCephalon.Engineand host adapters can expose them without referencingCephalon.Agentics; the agentics pack still owns the dispatcher implementation, executor, policy, observer, reporter, and in-memory catalog implementation - retry posture is bounded and process-local through
AgenticRuntimeOptions.ExecutionMaxAttemptsandExecutionRetryDelayMilliseconds; durable retry queues, autonomous planning, memory persistence, distributed scheduling, and provider-specific AI orchestration remain outside this proof until a package truly owns those paths - idempotency posture is opt-in and process-local through
AgenticRuntimeOptions.EnableExecutionIdempotencyandExecutionIdempotencyRetentionMinutes; it suppresses duplicate completed tool runs observed by the in-memory run catalog but does not claim a durable inbox, cross-node exactly-once delivery, broker deduplication, durable retry queues, distributed scheduling, or provider-specific AI orchestration - approval-required and terminal-failure filters are read-only operator seams over the latest run-state catalog; they do not claim a durable approval workflow, dead-letter system, durable retry queue, distributed scheduler, or provider-specific AI orchestration
Knowledge index surface
Section titled “Knowledge index surface”GET /engine/knowledge-indexes exposes the operator-facing index-state catalog for managed
retrieval indexes when a retrieval pack registers the abstraction-level IKnowledgeIndexCatalog.
POST /engine/knowledge-indexes/{collectionId}/reindex requests a manual reindex when the active
runtime also registers the abstraction-level IKnowledgeIndexer.
POST /engine/knowledge-indexes/{collectionId}/queries executes one bounded operator query when the
active runtime also registers the abstraction-level IKnowledgeQueryEngine.
Current payload highlights:
- each entry carries a stable
collectionId, latest indexing run id and outcome, observation and indexed timestamps, source freshness, document count, freshness state, indexing counters, query count, latest query timestamp, query fingerprint, query length, matched-count summary, actor, correlation id, error summary, and safe metadata GET /engine/knowledge-indexes/{collectionId}narrows the same catalog to one collection and returns404when no activity has been recorded for that collectionPOST /engine/knowledge-indexes/{collectionId}/reindexaccepts optionalrunId,actorId, andcorrelationIdquery values, generates safe defaults when they are absent, returns theKnowledgeIndexingResultfor the replacement run, and returns404when indexing is not active or the collection is not registeredPOST /engine/knowledge-indexes/{collectionId}/queriesaccepts a JSON body withqueryText, optionalmaxResults,actorId,correlationId, and safe metadata, returns theKnowledgeQueryResultfor the current index, returns404when querying is not active or the collection is not registered, and returns400when the query request is invalid- opt-in background reindexing uses the same catalog and indexer path, records
trigger = retrieval-background-scheduler,scheduler,schedulerIterationId, collection scope, startup-run, delay, and interval metadata, and never introduces a separate scheduler route - the same index-state catalog is also available through
/engine/snapshotinKnowledgeIndexeswhen operators want one merged runtime answer
Current note:
- the read contract, manual reindex command seam, and bounded query command seam live in
Cephalon.Abstractions.RetrievalsoCephalon.Engineand host adapters can expose, query, and remediate index posture without taking a direct dependency onCephalon.Retrievalimplementation types - the indexer implementation and query execution path remain owned by the selected retrieval pack
through
IKnowledgeIndexer,IKnowledgeQueryEngine, and registeredIKnowledgeDocumentProviderservices RetrievalOptions.EnableBackgroundReindexingregisters an opt-in generic-host scheduler only when ingestion is enabled; emptyBackgroundReindexCollectionIdsmeans all registered collections, while configured ids narrow the scheduler to matching registered collections
Authorization policy surface
Section titled “Authorization policy surface”GET /engine/authorization-policies exposes the operator-facing authorization-policy catalog contributed by active modules.
Current payload highlights:
- each policy carries a stable
id,displayName,description, supported authorizationmodes, and optionaltagsplusmetadata - supported modes stay aligned with the phase-8 core model:
RBAC,ABAC, andPolicy - the same authorization-policy catalog is also available through
/engine/snapshotwhen operators want one merged runtime answer
Current note:
- this is a host-agnostic runtime answer for active policy descriptors, not a replacement for ASP.NET Core schemes, claims mapping, or provider-specific identity wiring
- the engine stamps each policy with its contributing module through
metadata.sourceModuleIdso operators can trace ownership without a second registry
Technology surface
Section titled “Technology surface”GET /engine/technology-surfaces exposes the active runtime surfaces projected by selected technology packs.
Current Cephalon.Eventing highlights:
event-channelsandevent-subscriptionskeep channel and declared subscription descriptors visible under the selectedEventDrivenIntegrationtechnologyevent-subscriptionsnow projects execution readiness through stable metadata keys such asexecutionReadiness,executionPath, andexecutionReadinessReasons- the typed readiness answer is also available through
/engine/event-subscription-readinessandsnapshot.EventSubscriptionExecutionReadiness, so operators do not need to parse metadata when they only need the readiness posture - the typed publication-state answer is also available through
/engine/event-publications/runtime*andsnapshot.EventPublicationStates, so operators can inspect the latest accepted/succeeded, failed, or skipped publication posture without parsingevent-publishersmetadata Cephalon.Eventingcan move a subscription toruntime-bounditself whenEnableInProcessSubscriptionExecutionis selected and a matchingIEventSubscriptionExecutorexists; that path iscephalon-managed, direct, process-local, and reportseventing.publish/eventing.subscribemetadata withretryPolicy = noneandpublicationRuntimeState = availableby default- when
InProcessSubscriptionMaxAttemptsis greater than1, that same core path reportsretryPolicy = bounded-in-process,retryMaxAttempts,retryDelayMilliseconds,retryDurability = none, andretryScope = process-local, emitsretry-scheduledobservations between attempts, and updatesevent-subscriptionscounters such asretryScheduledCount,lastAttempt, andreported.retryPolicy - when
EnableInProcessSubscriptionIdempotencyis enabled, the direct lane suppresses duplicate completedsubscriptionId + publicationIdexecutions inside the configured process-local retention window, reportsskipped, and projectsidempotencyPolicy = completed-publication,idempotencyKey = subscription-publication,idempotencyRetentionMinutes,idempotencyDurability = none, andidempotencyScope = process-localthrough capabilities, bindings,event-publishers,event-subscriptions, andreported.*metadata - outbox-backed event publication reports
acceptedpublication state withhandoff = outboxanddeliveryCompletion = pending-dispatch, keeping publication acceptance separate from later dispatch completion - Wolverine or another companion adapter can still move staged dispatch or one subscription to provider-managed ownership for brokered or staged dispatch scenarios; the shipped Wolverine path now keeps both the dispatch loop and managed subscription retry lanes bounded with max attempts, terminal exhausted-attempt failure reporting, and dispatch-store terminal metadata that stops poison staged publications from re-entering pending reads, while hosted execution links and application-managed reports remain truthful non-provider-owned states
Current Cephalon.Agentics highlights:
- each tool entry still carries the operator-facing tool descriptor
- linked
capabilityKeys,executionGraphId, andhostedExecutionIdnow flow through the same surface when the tool declares them - linked execution-graph and hosted-execution entries also surface the current runtime-story phase and active/inactive state
- invalid linked capability, execution-graph, or hosted-execution references fail when the agentic tool catalog is resolved instead of leaking broken operator metadata
- managed tool execution now flows through
IAgentToolDispatcherwhenAgenticRuntimeOptions.EnableExecutionis enabled - bounded process-local retry is opt-in through
ExecutionMaxAttemptsandExecutionRetryDelayMilliseconds, withretryPolicy,retryMaxAttempts,retryDelayMilliseconds,retryDurability, andretryScopemetadata on the execution capability and tool surface - process-local duplicate-completed suppression is opt-in through
EnableExecutionIdempotencyandExecutionIdempotencyRetentionMinutes, withidempotencyPolicy,idempotencyKey,idempotencyRetentionMinutes,idempotencyDurability, andidempotencyScopemetadata on the execution capability and tool surface - each tool entry reports execution readiness through
executionEnabled,executionOwnership,executorConfigured, andexecutorCount; tools without an executor are reported asawaiting-executorinstead of being described as fully managed - reported runs flow into
IAgentToolRunCatalogand surfaceruntimeState,runCount,lastRunId,lastOutcome, retry-scheduled count, retry-pending posture, approval-required posture, duplicate-completed posture, terminal-failure posture,totalReports, approval/denial counters, actor/correlation details, andreported.*metadata on the same technology surface, while/engine/agent-tool-runs*andsnapshot.AgentToolRunsexpose the direct run-state read seam - operators can now request one bounded managed tool run through
POST /engine/agent-tools/{toolId}/runs; the route records supplied or generated run id, actor, correlation id, attempt, arguments, and safe trigger metadata on the same run-state answer GET /engine/agent-tool-runs/retry-pendingfilters runs whose latest report is waiting for another process-local attempt; approval-required and denied outcomes are policy decisions, not executor failures, so operators can distinguish “waiting for approval” from broken executionGET /engine/agent-tool-runs/idempotency-duplicatesfilters duplicate-completed suppressions so operators can see when a stable run id was intentionally not executed again inside the current processGET /engine/agent-tool-runs/approval-requiredand/engine/agent-tool-runs/terminal-failureskeep approval-blocked runs and terminal failed runs visible without requiring operators to parse genericreported.*metadata- the phase 13
cell-based-architecturebaseline now also projectscell-boundaries,cell-routes,cell-health-isolations, andcell-traffic-automationssurfaces whose entries stay aligned with/engine/cells,/engine/cell-routes,/engine/cell-health-isolations,/engine/cell-traffic-automations,snapshot.CellBoundaries,snapshot.CellRoutes,snapshot.CellHealthIsolations, andsnapshot.CellTrafficAutomations, so operators can read module ownership, blast-radius posture, source-cell to target-cell routing posture, health-isolation posture, effective automation/trigger/action/materialization modes, policy source, dependency linkage, and transport hints from one shared runtime truth - the same traffic-automation surface now also carries first-class
providerIdplusedgeNodeIdstargeting and ASP.NET Core drill-down routes on/engine/cell-traffic-automations/providers/{providerId}plus/engine/cell-traffic-automations/edge-nodes/{edgeNodeId}, so operators can correlate shared cell posture with provider control planes and edge-node topology without inventing a second traffic registry - provider-managed automation entries now also expose
providerMaterializerId,providerMaterializationState,providerMaterializationObservedAtUtc, andproviderMaterializationError, so the same technology surface can answer whether startup reconciliation is stillpending, alreadyapplied, currentlyunavailable, or lastfailedfor the selected provider materializer - edge-managed automation entries now also expose
edgeMaterializerId,edgeMaterializationState,edgeMaterializationObservedAtUtc, andedgeMaterializationError, whileedgeMaterialization.*runtime metadata can carry edge-reported action and targeted-node details, so operators can inspect the same edge-runtime reconciliation posture without a second edge-only traffic-materialization API - the shared route answer now also exposes derived
materializationState,materializationObservedAtUtc, andmaterializationErrorplus selection metadata such asproviderSelection.matchingCandidateCount,edgeSelection.matchingCandidateCount, selected priorities, required versus selected dimensions, andmaterialization.stateBreakdown, soprovider-and-edge-managedroutes can publish one truthful overall posture even when provider and edge reconciliation disagree
Current Cephalon.Retrieval highlights:
- each collection entry carries descriptor metadata plus managed runtime posture when
KnowledgeRetrievalis active indexingOwnershipreportscephalon-managed,awaiting-provider, ornot-configuredso missing document providers do not look like a ready indexqueryOwnershipreportscephalon-managed,awaiting-index,awaiting-provider, ornot-configuredso query readiness stays separate from collection registrationruntimeState,freshnessState,documentCount,queryCount, latest index outcome fields, and latest query match counts are projected through/engine/technology-surfacesand/engine/snapshotbackgroundReindexingEnabled,backgroundReindexingScheduled,backgroundReindexingOwnership,backgroundReindexingCollectionScope, configured collection count, startup-run, delay, and interval metadata are projected beside the index/query posture- the same typed index-state answer is also available through
/engine/knowledge-indexes*andsnapshot.KnowledgeIndexes, so operators do not need to parse technology-surface metadata when they only need collection index posture - operators can now request a bounded manual reindex through
POST /engine/knowledge-indexes/{collectionId}/reindex; the route records the supplied or generated run id, actor, correlation id, and safe trigger metadata on the same index-state answer - operators can now request one bounded lexical query through
POST /engine/knowledge-indexes/{collectionId}/queries; the route returns aKnowledgeQueryResultto the caller and records actor, correlation id, safe metadata, trigger, route, query fingerprint, query length, and match count on the same index-state answer lastQueryFingerprintandlastQueryLengthare reported instead of raw query text so operator introspection can correlate activity without leaking user prompts or private search terms- this is a Cephalon-managed lexical in-process baseline with opt-in in-process freshness scheduling; vector search, embeddings, durable search storage, distributed indexes, rerankers, provider-specific search engines, distributed scheduler coordination, and leader-election semantics stay outside the current compatibility promise until a package owns them explicitly
Trust surface
Section titled “Trust surface”GET /engine/trust-policy exposes the effective package and capability trust snapshot:
- the current
Engine:Trustpolicy - package trust decisions for explicit package assembly loads
- checksum allow-list decisions from
Engine:Trust:AllowedPackageChecksums - capability access decisions, including trusted-only and denied capabilities
For ASP.NET Core REST modules, RequireCapability(...) can enforce those capability decisions at request time.
Package policy surface
Section titled “Package policy surface”GET /engine/package-policy exposes the effective package-governance rules currently applied by the runtime.
Current payload highlights:
- whether raw assembly-path packages are allowed
- whether package manifests must declare
version - whether package manifests must declare minimum or maximum engine versions
- whether package manifests must declare supported target frameworks
- whether package manifests must declare publisher ids, signer fingerprints, signature key ids, signature values, or completed cryptographic signature verification across the declared signature set
- whether package manifests must declare
integrity.sha256
This is the operator-facing contract for package metadata requirements before trust evaluation even starts.
Package surface
Section titled “Package surface”GET /engine/packages exposes the resolved package-loading snapshot for independently shipped modules.
Current payload highlights:
kind,path, andsourcePathexplain how the package was discoveredversioncomes fromcephalon.package.jsonwhen the package was manifest-drivenminimumEngineVersion,maximumEngineVersion, andsupportedTargetFrameworksexpose compatibility intentdependenciesexposes any package-to-package requirements declared by the package manifest, including optional minimum and maximum version boundsdistributionexposes the declared external release channel plus manifest/package fetch hintsprovenanceexposes the declared source repository, source revision, build URI, and provenance statement URIpublisherId,publisherDisplayName,signatureKeyId,signatureFingerprint, andsignatureCertificateThumbprintexpose the primary package provenance summary kept for backward compatibilitysignaturesexposes per-signer provenance plus per-signer verification details such asverificationSourceand certificate thumbprints when a package declares multiple signersisSignatureVerifiedandsignatureVerificationReasonexplain the aggregate detached-signature verification outcome for the packagechecksumSha256exposes the computed hash of the resolved assemblyisTrustedandtrustReasonexplain why the current trust policy accepted or rejected the package
This is the main operator surface for package provenance and compatibility diagnostics. When a package declares multiple signers, per-signer outcomes stay visible while the top-level fields continue to summarize the primary signature for existing consumers.
Telemetry export path
Section titled “Telemetry export path”Cephalon.Engine emits built-in diagnostics through:
- meter:
Cephalon.Engine - activity source:
Cephalon.Engine - counters:
cephalon.engine.buildscephalon.runtime.transitionscephalon.module.transitionscephalon.runtime.failurescephalon.module.failurescephalon.runtime.restarts
Cephalon.Observability reads Engine:Observability:Telemetry and logs the effective export guidance on startup.
Cephalon.Observability.OpenTelemetry can then turn that same section into a supported OTLP export path for logs, metrics, and traces, including the explicit self-hosted collector defaults that sit on top of the same shared contract.
The same shared contract is also the intended downstream extension point. Teams that install Cephalon packages can build their own provider-specific companion integration by reusing ObservabilityOptions.FromConfiguration(builder.Configuration).Telemetry, binding an additional provider-specific sub-section, keeping exporter/auth/resource logic in their own package, and optionally publishing a diagnostics convention plus startup summary through IDiagnosticsConventionContributor and IHostedService.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "Endpoint": "http://localhost:4318", "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true } } }}Self-hosted example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "UseSelfHostedDefaults": true, "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonOpenTelemetry();Operational notes:
- the exporter package is optional and stays outside
Cephalon.Engine - registration is skipped when
Engine:Observability:Telemetry:Endpointis not configured andUseSelfHostedDefaultsis not enabled otlp,otlp/grpc, andotlp/httpare the supported protocol values for the shipped companion package- when
UseSelfHostedDefaultsistrueandEndpointis omitted, the package falls back tohttp://localhost:4317forotlp/otlp/grpcorhttp://localhost:4318forotlp/http - when
otlp/httpis selected, the package appends/v1/logs,/v1/metrics, and/v1/tracesautomatically from the configured base endpoint - the self-hosted path also adds
deployment.environment.namefrom the active host environment alongside the existing service-name and service-version resource defaults - downstream companion packages should reuse this same contract instead of introducing a second Cephalon telemetry abstraction; that is the intended path for Cloudflare or internal-provider integrations
Downstream provider authoring path
Section titled “Downstream provider authoring path”Downstream provider packages should build on top of the same Engine:Observability:Telemetry contract instead of creating a second Cephalon telemetry abstraction.
Recommended authoring pattern:
- bind
ObservabilityOptions.FromConfiguration(builder.Configuration).Telemetryfirst - bind provider-specific settings from
Engine:Observability:Telemetry:{ProviderName} - keep provider-specific exporter, auth, trust, and hosted-default logic inside the downstream package
- publish a startup summary through
IHostedServiceand a diagnostics convention throughIDiagnosticsConventionContributor - reject unsupported protocol or signal combinations explicitly instead of silently dropping signals
Cloudflare note:
- current Cloudflare Workers observability docs focus on Worker-native traces and logs plus exporting OpenTelemetry-compliant traces and logs from Workers to third-party OTLP destinations
- that current path does not yet describe a generic OTLP ingestion target for external Cephalon hosts, and metrics export is still not part of that Worker export story
- until Cloudflare documents a reusable host-side ingestion path that fits Cephalon’s runtime model, treat Cloudflare as downstream authoring guidance rather than a first-party
Cephalon.Observability.Cloudflarepackage
See Observability provider authoring for the recommended package shape and example extension-method pattern.
AWS observability path
Section titled “AWS observability path”Cephalon.Observability.Aws keeps AWS-specific propagation, AWS SDK instrumentation, and hosted AWS resource defaults in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "Endpoint": "http://localhost:4318", "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true, "Aws": { "HostedPlatform": "ecs", "UseXRayTraceIds": true, "UseXRayPropagator": true, "EnableAwsSdkInstrumentation": true } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonAws();Operational notes:
- the AWS package is optional and stays outside
Cephalon.Engine - registration is skipped when
Engine:Observability:Telemetry:Endpointis not configured andUseSelfHostedDefaultsis not enabled HostedPlatformcan beec2,ecs,eks,elasticbeanstalk, orlambda- the package keeps the shared OTLP exporter contract intact while adding AWS X-Ray-compatible trace IDs, optional AWS X-Ray propagation, and AWS SDK client tracing
- EC2, ECS, EKS, and Elastic Beanstalk use AWS resource detectors, while Lambda uses explicit AWS resource attributes plus optional Lambda context configuration
- if a deployment targets AWS-managed OTLP endpoints directly, prefer an ADOT collector or another SigV4-capable gateway in front of that endpoint instead of baking AWS auth rules into the host
GCP observability path
Section titled “GCP observability path”Cephalon.Observability.Gcp keeps hosted GCP defaults and an optional Google-managed traces/metrics path in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true, "Gcp": { "HostedPlatform": "cloudrun", "Location": "asia-southeast1", "UseGoogleManagedIngestion": true, "UseApplicationDefaultCredentials": true } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonGcp();Operational notes:
- the GCP package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds hosted GCP resource defaults - when
Engine:Observability:Telemetry:Gcp:UseGoogleManagedIngestionistrueand no shared endpoint is configured, the package targetshttps://telemetry.googleapis.comfor traces and metrics by using OTLP/HTTP plus Application Default Credentials - Google-managed ingestion requires
Engine:Observability:Telemetry:Protocolto stay onotlp/http - direct Google-managed ingestion does not re-route logs; keep logs on the shared collector path or the platform logging path for the target runtime
HostedPlatformcan begce,gke,cloudrun,appengine, orfunctionsLocationlets the package stamplocation,cloud.region, and when applicablecloud.availability_zone
Huawei Cloud observability path
Section titled “Huawei Cloud observability path”Cephalon.Observability.HuaweiCloud keeps hosted Huawei Cloud defaults and an optional managed APM trace path in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp", "ExportLogs": false, "ExportMetrics": false, "ExportTraces": true, "HuaweiCloud": { "HostedPlatform": "cce", "Region": "ap-southeast-3", "UseApmManagedTraceIngestion": true, "ApmEndpoint": "https://apm.example.huaweicloud.com:4317", "AuthenticationToken": "replace-with-apm-authentication-token" } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonHuaweiCloud();Operational notes:
- the Huawei Cloud package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds hosted Huawei Cloud resource defaults - when
Engine:Observability:Telemetry:HuaweiCloud:UseApmManagedTraceIngestionistrueand no shared endpoint is configured, the package targets the configuredApmEndpointfor traces by using OTLP/gRPC plus the Huawei CloudAuthenticationheader - managed APM trace ingestion requires
Engine:Observability:Telemetry:Protocolto stay onotlporotlp/grpc - direct Huawei Cloud managed APM ingestion does not re-route logs or metrics; keep those signals on the shared collector path or another runtime-specific route
HostedPlatformcan beecs,cce, orfunctiongraphRegionlets the package stampcloud.regionwhen a deployment wants that value to stay explicit
Oracle Cloud observability path
Section titled “Oracle Cloud observability path”Cephalon.Observability.OracleCloud keeps hosted Oracle Cloud defaults and an optional Oracle Cloud APM managed traces/metrics path in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "ExportLogs": false, "ExportMetrics": true, "ExportTraces": true, "OracleCloud": { "HostedPlatform": "oke", "Region": "us-ashburn-1", "UseManagedOpenTelemetryIngestion": true, "DataUploadEndpoint": "https://aaaaaaaaaaaaaaaaaaaaaa.apm-agt.us-ashburn-1.oci.oraclecloud.com", "UsePublicTraceDataKey": true, "TraceDataKey": "replace-with-public-or-private-trace-data-key", "MetricsDataKey": "replace-with-private-metrics-data-key" } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonOracleCloud();Operational notes:
- the Oracle Cloud package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds hosted Oracle Cloud resource defaults - when
Engine:Observability:Telemetry:OracleCloud:UseManagedOpenTelemetryIngestionistrueand no shared endpoint is configured, the package builds Oracle Cloud APM OTLP/HTTP traces and metrics endpoints fromDataUploadEndpoint - managed Oracle Cloud APM ingestion requires
Engine:Observability:Telemetry:Protocolto stay onotlp/http - direct managed trace ingestion requires
TraceDataKey; direct managed metrics ingestion requiresMetricsDataKey UsePublicTraceDataKeyswitches the trace path between Oracle Cloud APM public and private trace-key ingestion; metrics always stay on the private-key path- direct Oracle Cloud APM managed ingestion does not re-route logs; keep logs on the shared collector path, Oracle Log Analytics, or another runtime-specific route
HostedPlatformcan becompute,oke, orfunctionsRegionlets the package stampcloud.regionwhen a deployment wants that value to stay explicit
Grafana Cloud observability path
Section titled “Grafana Cloud observability path”Cephalon.Observability.GrafanaCloud keeps Grafana Cloud OTLP endpoint wiring and access-policy authentication guidance in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true, "GrafanaCloud": { "UseDirectGrafanaCloudEndpoint": true, "Endpoint": "https://otlp-gateway-prod-us-central-0.grafana.net/otlp", "InstanceId": "replace-with-grafana-cloud-instance-id", "AccessPolicyToken": "replace-with-grafana-cloud-access-policy-token", "ServiceNamespace": "checkout" } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonGrafanaCloud();Operational notes:
- the Grafana Cloud package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds Grafana-friendly resource context - when
Engine:Observability:Telemetry:GrafanaCloud:UseDirectGrafanaCloudEndpointistrueand no shared endpoint is configured, the package targets the configured Grafana Cloud OTLP endpoint directly - direct Grafana Cloud mode accepts either
Headersin standard OTLPkey=valueformat or the structuredInstanceIdplusAccessPolicyTokenpair that the package converts into a BasicAuthorizationheader Protocolcan stay onotlp,otlp/grpc, orotlp/http; for HTTP/protobuf the package appends/v1/traces,/v1/metrics, and/v1/logsautomaticallyServiceNamespacelets the package stampservice.namespace, while the active host environment still contributesdeployment.environment.name
New Relic observability path
Section titled “New Relic observability path”Cephalon.Observability.NewRelic keeps New Relic native OTLP endpoint wiring and api-key authentication guidance in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true, "NewRelic": { "UseNativeOtlpEndpoint": true, "Region": "eu", "LicenseKey": "replace-with-newrelic-license-key", "ServiceNamespace": "checkout" } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonNewRelic();Operational notes:
- the New Relic package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds explicit resource context - when
Engine:Observability:Telemetry:NewRelic:UseNativeOtlpEndpointistrueand no shared endpoint is configured, the package targets either the configured New Relic OTLP endpoint or the documented regional endpoint derived fromRegion - direct New Relic mode accepts either
Headersin standard OTLPkey=valueformat or the structuredLicenseKeyvalue that the package converts into the requiredapi-keyheader Protocolcan stay onotlp,otlp/grpc, orotlp/http; New Relic currently recommendsotlp/http, and for HTTP/protobuf the package appends/v1/traces,/v1/metrics, and/v1/logsautomaticallyRegioncan beus,eu, orfedramp; if omitted, the package defaults to the New Relic US OTLP endpointServiceNamespacelets the package stampservice.namespace, while the active host environment still contributesdeployment.environment.name
Alibaba Cloud observability path
Section titled “Alibaba Cloud observability path”Cephalon.Observability.AlibabaCloud keeps hosted Alibaba Cloud defaults and an optional managed OpenTelemetry traces/metrics path in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp", "ExportLogs": false, "ExportMetrics": true, "ExportTraces": true, "AlibabaCloud": { "HostedPlatform": "ecs", "Region": "cn-hangzhou", "UseManagedOpenTelemetryIngestion": true, "ManagedGrpcEndpoint": "https://otel.example.aliyuncs.com:8000", "AuthenticationToken": "replace-with-managed-otel-authentication-token" } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonAlibabaCloud();Operational notes:
- the Alibaba Cloud package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds hosted Alibaba Cloud resource defaults - when
Engine:Observability:Telemetry:AlibabaCloud:UseManagedOpenTelemetryIngestionistrueand no shared endpoint is configured, the package targets the configured Alibaba Cloud Managed Service for OpenTelemetry path for traces and metrics - managed Alibaba Cloud OTLP/gRPC ingestion requires
Engine:Observability:Telemetry:Protocolto stay onotlporotlp/grpcand uses the Alibaba CloudAuthenticationheader - managed Alibaba Cloud OTLP/HTTP ingestion requires
Engine:Observability:Telemetry:Protocolto stay onotlp/httpand uses the configured signal-specific traces and metrics endpoints directly - direct Alibaba Cloud managed ingestion does not re-route logs; keep logs on the shared collector path, SLS, or another runtime-specific route
HostedPlatformcan beecs,fc,functioncompute, oropenshiftRegionlets the package stampcloud.regionwhen a deployment wants that value to stay explicit
OpenShift observability path
Section titled “OpenShift observability path”Cephalon.Observability.OpenShift keeps OpenShift collector discovery, trust material, and hosted cluster defaults in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true, "OpenShift": { "HostedPlatform": "openshift", "ClusterName": "prod-cluster", "Namespace": "payments", "UseInClusterCollectorService": true, "CollectorServiceName": "otel-collector", "CollectorNamespace": "observability" } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonOpenShift();Operational notes:
- the OpenShift package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds OpenShift resource defaults - when
Engine:Observability:Telemetry:OpenShift:UseInClusterCollectorServiceistrueand no shared endpoint is configured, the package targetshttp(s)://{service}.{namespace}.svc.cluster.local:{port} HostedPlatformcan beopenshift,aro, orrosaClusterName,Namespace,POD_NAMESPACE, andHOSTNAMElet the package stampk8s.cluster.name,k8s.namespace.name,service.namespace, andk8s.pod.name;aroandrosaalso stampcloud.providerTrustedCaCertificatePathcan be used for HTTPS OTLP/HTTP traces and metrics when an in-cluster collector, route, or gateway uses a cluster-local CA bundle- the current OpenTelemetry logging exporter does not support custom
HttpClientFactorywiring for HTTP, so configurations that needTrustedCaCertificatePathfor OTLP/HTTP logs are rejected early instead of being treated as supported Headerslets the package pass raw OTLP header values through to the target collector or gateway when a route expects explicit headers
Kubernetes observability path
Section titled “Kubernetes observability path”Cephalon.Observability.Kubernetes keeps platform-neutral Kubernetes collector discovery, cluster-local trust material, and Kubernetes resource defaults in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true, "Kubernetes": { "ClusterName": "prod-cluster", "Namespace": "payments", "PodName": "payments-api-5799c", "NodeName": "node-a", "ContainerName": "api", "UseInClusterCollectorService": true, "CollectorServiceName": "otel-collector", "CollectorNamespace": "observability" } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonKubernetes();Operational notes:
- the Kubernetes package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds Kubernetes resource defaults - when
Engine:Observability:Telemetry:Kubernetes:UseInClusterCollectorServiceistrueand no shared endpoint is configured, the package targetshttp(s)://{service}.{namespace}.{serviceDnsSuffix}:{port} ClusterName,Namespace,PodName,PodUid,NodeName, andContainerNamekeep generic Kubernetes resource attributes explicit without forcing teams into a vendor-specific companion packagePOD_NAMESPACE,POD_NAME,HOSTNAME,POD_UID,NODE_NAME, andCONTAINER_NAMEcan fill those same resource attributes when the deployment already injects them through the Kubernetes downward API or runtime environmentServiceDnsSuffixdefaults tosvc.cluster.localand stays configurable for clusters that use a non-default service DNS suffixTrustedCaCertificatePathcan be used for HTTPS OTLP/HTTP traces and metrics when an in-cluster collector, gateway, or route uses a cluster-local CA bundle- the current OpenTelemetry logging exporter does not support custom
HttpClientFactorywiring for HTTP, so configurations that needTrustedCaCertificatePathfor OTLP/HTTP logs are rejected early instead of being treated as supported - use this package for generic or self-managed Kubernetes clusters; if a deployment also needs provider-specific propagation, managed-ingestion, or hosted defaults, pair the shared telemetry contract with a more specific companion package instead
DigitalOcean observability path
Section titled “DigitalOcean observability path”Cephalon.Observability.DigitalOcean keeps DigitalOcean collector defaults, best-effort Droplet metadata, and hosted runtime guidance in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true, "DigitalOcean": { "HostedPlatform": "doks", "Region": "sgp1", "ClusterName": "prod-cluster", "Namespace": "payments", "UseInClusterCollectorService": true, "CollectorServiceName": "otel-collector", "CollectorNamespace": "observability" } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonDigitalOcean();Operational notes:
- the DigitalOcean package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds DigitalOcean resource defaults - when
Engine:Observability:Telemetry:DigitalOcean:UseInClusterCollectorServiceistrueand no shared endpoint is configured, the package targetshttp(s)://{service}.{namespace}.svc.cluster.local:{port}for DOKS deployments HostedPlatformcan bedroplet,doks, orapp-platformUseDropletMetadataDefaultsturns on a short best-effort call to the Droplet metadata service so the package can fillhost.id,host.name, andcloud.regionwhen they were not configured directly- App Platform context stays explicit: set
AppIdandAppUrldirectly, or bind${APP_ID}and${APP_URL}into runtime environment variables with those names if you want the package to pick them up automatically ClusterName,Namespace,POD_NAMESPACE, andHOSTNAMElet the package stampk8s.cluster.name,k8s.namespace.name,service.namespace, andk8s.pod.namefor DOKS workloadsTrustedCaCertificatePathcan be used for HTTPS OTLP/HTTP traces and metrics when a shared or in-cluster collector uses a non-system CA bundle- the current OpenTelemetry logging exporter does not support custom
HttpClientFactorywiring for HTTP, so configurations that needTrustedCaCertificatePathfor OTLP/HTTP logs are rejected early instead of being treated as supported - there is no first-party DigitalOcean managed OTLP endpoint in this package; use the shared collector path, self-hosted defaults, or a self-managed gateway instead of treating this companion as a vendor-direct exporter
Tanzu observability path
Section titled “Tanzu observability path”Cephalon.Observability.Tanzu keeps Tanzu-specific hosted defaults and trace-focused proxy handoff in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "Protocol": "otlp/http", "ExportLogs": false, "ExportMetrics": false, "ExportTraces": true, "Tanzu": { "HostedPlatform": "tap", "ClusterName": "prod-cluster", "Namespace": "payments", "UseInClusterProxyService": true, "ProxyServiceName": "wavefront-proxy", "ProxyNamespace": "observability", "ProxyPort": 4318 } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonTanzu();Operational notes:
- the Tanzu package is optional and stays outside
Cephalon.Engine - when
Engine:Observability:Telemetry:EndpointorUseSelfHostedDefaultsis configured, the package keeps using the shared collector-oriented OTLP path and only adds Tanzu resource defaults - when
Engine:Observability:Telemetry:Tanzu:UseInClusterProxyServiceistrueand no shared endpoint is configured, the package targetshttp(s)://{service}.{namespace}.svc.cluster.local:{port}for trace-focused proxy handoff HostedPlatformcan betkg,tkgi, ortapClusterName,Namespace,POD_NAMESPACE, andHOSTNAMElet the package stampk8s.cluster.name,k8s.namespace.name,service.namespace, andk8s.pod.name; the hosted-platform selection also stampscloud.provider=vmwareplus a package-specificcloud.platformProxyPortstays required on purpose so the proxy handoff path remains explicit instead of pretending the current Tanzu docs expose one generic vendor-wide OTLP portProxyPathlets teams keep an explicit base path when the proxy or route is mounted away from/TrustedCaCertificatePathcan be used for HTTPS OTLP/HTTP traces and metrics when a shared collector, gateway, or Tanzu proxy route uses a non-system CA bundle- the current OpenTelemetry logging exporter does not support custom
HttpClientFactorywiring for HTTP, so configurations that needTrustedCaCertificatePathfor OTLP/HTTP logs are rejected early instead of being treated as supported - the first-party Tanzu proxy handoff mode intentionally supports traces only; keep logs and metrics on the shared collector path or the explicit self-hosted defaults instead of treating this companion as a generic managed exporter
Azure Monitor exporter path
Section titled “Azure Monitor exporter path”Cephalon.Observability.AzureMonitor keeps Azure Monitor / Application Insights export wiring in a dedicated companion package on top of the same shared Engine:Observability:Telemetry contract.
Example:
{ "Engine": { "Observability": { "Telemetry": { "Provider": "OpenTelemetry", "ExportLogs": true, "ExportMetrics": true, "ExportTraces": true, "AzureMonitor": { "ConnectionString": "InstrumentationKey=00000000-0000-0000-0000-000000000000", "UseDefaultAzureCredential": true, "HostedPlatform": "appservice" } } } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonAzureMonitor();Operational notes:
- the Azure Monitor package is optional and stays outside
Cephalon.Engine - registration is skipped when
Engine:Observability:Telemetry:AzureMonitor:ConnectionStringis not configured UseDefaultAzureCredentialadds Azure Active Directory authentication on top of the configured connection string endpointHostedPlatformcan beappservice,functions,aks,containerapps, orvm- when
HostedPlatformis configured, the package addscloud.provider=azure, the correspondingcloud.platformvalue, anddeployment.environment.namewhen the host environment name is set
Serilog provider path
Section titled “Serilog provider path”Cephalon.Observability.Serilog lets hosts keep logging through injected ILogger<T> services while routing the resulting events through Serilog sinks, enrichers, and formatting.
Example:
{ "Serilog": { "MinimumLevel": { "Default": "Information", "Override": { "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "WriteTo": [ { "Name": "Console" } ], "Enrich": [ "FromLogContext" ], "Properties": { "Application": "Cephalon.Host" } }}Host registration example:
var builder = Host.CreateApplicationBuilder(args);
builder.AddCephalon();builder.Services.AddCephalonObservability(builder.Configuration);builder.AddCephalonSerilog();Operational notes:
- the Serilog package is optional and stays outside
Cephalon.EngineandCephalon.Observability - registration continues to flow through
Microsoft.Extensions.Logging.ILogger; Cephalon does not introduce a separate logging abstraction - the package reads the standard top-level
Serilogconfiguration section and skips registration when that section is absent and no code-based Serilog callback is supplied - hosts can still append sinks, enrichers, or policy with code when configuration alone is not enough
- bootstrap logging before the host builder exists stays an explicit host concern rather than hidden in the Cephalon runtime layer
ASP.NET Core request and response logging
Section titled “ASP.NET Core request and response logging”Cephalon.AspNetCore can opt into HTTP request/response logging through Engine:Observability:HttpLogging.
This keeps the feature in the shared host surface instead of introducing a second logging abstraction, and it can capture bounded textual request/response bodies when teams explicitly enable it.
Example:
{ "Engine": { "Observability": { "HttpLogging": { "Enabled": true, "LogRequestBody": true, "LogResponseBody": true, "RequestBodyLimit": 4096, "ResponseBodyLimit": 4096, "RedactSensitiveValues": true, "RedactedFieldNames": [ "password", "token", "secret", "apiKey" ], "RedactionValue": "[REDACTED]" } } }}Optional code-level override:
var builder = WebApplication.CreateBuilder(args);
builder.AddCephalonHttpLogging(options =>{ options.Enabled = true; options.LogRequestBody = true; options.LogResponseBody = true; options.RequestBodyLimit = 4096; options.ResponseBodyLimit = 4096; options.RedactSensitiveValues = true; options.RedactedFieldNames = ["password", "token", "secret", "apiKey"]; options.RedactionValue = "[REDACTED]";});builder.AddCephalon();Operational notes:
AddCephalon()already registers theEngine:Observability:HttpLoggingcontract, so the extra method is only needed for code-based overrides- request/response body capture is opt-in and limited to textual payloads such as
text/*, JSON, XML, GraphQL, JavaScript, and form payloads - sensitive query-string and payload fields such as
password,token,secret,apiKey,authorization, andcookieare redacted by default before the log event is written, including JSON bodies, form payloads, andtext/plainkey/value or header-style content such asAuthorization: Bearer ... - teams can override the sensitive-field list and placeholder through
RedactedFieldNamesandRedactionValuewhen a host needs stricter or domain-specific masking - request scopes carry
RequestId,TraceId,SpanId, andTraceParent, so logs written inside the request pipeline keep the same correlation context /engine/diagnosticspublishes the ASP.NET Core event-id range for request start, request body, response completion, response body, and request failure events- the same correlation values flow through Serilog when
Cephalon.Observability.Serilogis enabled Cephalon.Observability.OpenTelemetrynow adds ASP.NET Core tracing instrumentation, so OTLP-exported request traces can be matched with the corresponding Cephalon HTTP logs
Release-validation guidance
Section titled “Release-validation guidance”.\scripts\validate-operational-conventions.ps1 is the focused operational validation pass for health and export conventions.
It executes a curated test suite that validates:
- ASP.NET Core
/health/live,/health/ready,/engine/diagnostics, and/engine/dependenciesbehavior - ASP.NET Core request/response logging, bounded body capture, and trace/log correlation behavior
- worker-host parity through
RuntimeHealthEvaluator - startup manifest and telemetry-export guidance emitted by
Cephalon.Observability, including self-hosted OTLP default endpoint guidance - Serilog provider wiring through
Cephalon.Observability.Serilog - Alibaba Cloud-hosted defaults and managed OpenTelemetry traces/metrics through
Cephalon.Observability.AlibabaCloud - AWS-hosted OTLP defaults through
Cephalon.Observability.Aws - Grafana Cloud direct endpoint wiring through
Cephalon.Observability.GrafanaCloud - New Relic native OTLP defaults through
Cephalon.Observability.NewRelic - GCP-hosted defaults through
Cephalon.Observability.Gcp - Huawei Cloud-hosted defaults and managed APM traces through
Cephalon.Observability.HuaweiCloud - Kubernetes in-cluster collector defaults through
Cephalon.Observability.Kubernetes - OpenShift in-cluster collector defaults through
Cephalon.Observability.OpenShift - Tanzu proxy trace handoff defaults through
Cephalon.Observability.Tanzu - OTLP exporter wiring through
Cephalon.Observability.OpenTelemetry, including the explicit self-hosted collector-default path
.\scripts\validate-release.ps1 now runs that focused suite by default in addition to the broader repo test, benchmark, and reference-doc flow.
Use -SkipOperationalConventions only when you intentionally want the wider release flow without the named operational replay.
.\scripts\validate-phase8-conventions.ps1 is the focused validation pass for the current phase-8 architecture/data/security/starter baseline.
It executes a curated suite that validates:
- structured
Engine:Data,Engine:Identity,Engine:Tenancy,Engine:Audit, andEngine:Messagingsettings plus phase-8 app-profile truth - host-agnostic phase-8 contracts, runtime catalogs, and runtime-snapshot answers for data products, projections, inboxes, outboxes, audit stores, and authorization policies
Cephalon.Data,Cephalon.Data.EntityFramework, andCephalon.Ids.Sfidthrough the shipped relational-first CQRS, inbox, outbox, andSfidbaselineCephalon.EventingplusCephalon.Eventing.Wolverinethrough the staged publication, declarative subscription, public execution-binding catalog, public execution-readiness catalog, runtime-reporting, bounded Wolverine managed-dispatch retry, bounded Wolverine managed-subscription retry, terminal exhausted-attempt failure posture, dispatch-store terminal failure behavior, and adapter-surface pathCephalon.Identity,Cephalon.Identity.AspNetCore,Cephalon.MultiTenancy, andCephalon.Auditthrough their runtime surfaces, adapter behavior, and package/reference-doc truth- low-ceremony starter output across
Cephalon.Scaffolding,Cephalon.Cli,Cephalon.TemplatePack, adoption docs, and starter samples so generated apps stay aligned with the runtime story
.\scripts\validate-release.ps1 now also runs that focused phase-8 suite by default.
Use -SkipPhase8Conventions only when you intentionally want the wider release flow without the named phase-8 replay.
For the Docker Desktop / WSL-friendly operator smoke path, .\scripts\validate-container-runtime.ps1 runs samples/Cephalon.Sample.ModularMonolith/compose.yaml, waits for collector health plus /health/ready, /engine, /engine/snapshot, and /api/catalog/overview, and then tears the stack down. That containerized validation stays optional on purpose, so Docker is not a hard dependency of .\scripts\validate-release.ps1.
Worker hosts
Section titled “Worker hosts”Worker hosts do not expose HTTP health routes, but the same runtime health semantics are available through RuntimeHealthEvaluator in DI.
That keeps readiness/liveness logic shared across:
Cephalon.AspNetCoreCephalon.WorkerCephalon.Observability
Related documents
Section titled “Related documents”docs/architecture.mddocs/container-runtime.mddocs/operational-hardening-gap-inventory.mddocs/runtime-failure-policy.mddocs/engine-roadmap.mddocs/engine-backlog.md