Platform architecture (summary)
Audience: Platform WebService owners, service authors adopting the cross-cutting contracts, and operators wiring Console configuration. This is the orientation summary; defer to the linked module dossiers for contract-level detail.
This module covers two things: (1) the cross-cutting contracts and guardrails that every Stella Ops service must follow, and (2) the Platform WebService (StellaOps.Platform.WebService) — the runtime that backs the Console UI, serves frontend configuration, owns installation identity/settings and the cross-service tenant directory, exposes federation/NIS2 telemetry surfaces, and hosts the operator-facing database-migration registry.
Installation versus deployment ownership: Platform owns the Stella Ops installation control plane (
platform.*, setup state, installation settings, tenant directory, and read projections). ReleaseOrchestrator owns deployment topology and image placement (release.environments,release.targets, inventory/digests, promotions, and deployment execution). A shared physical PostgreSQL installation does not make Platform a second writer or migration owner for ReleaseOrchestrator tables. Platform compatibility environment routes always proxy the owning ReleaseOrchestrator API.
Source of truth for the runtime described below:
src/Platform/StellaOps.Platform.WebService/Program.cs(composition root + endpoint map),src/Platform/StellaOps.Platform.WebService/Constants/PlatformScopes.cs+PlatformPolicies.cs(authorization), andsrc/Platform/__Libraries/StellaOps.Platform.Database/Migrations/Platform/(the embedded Platform-owned migration stream).Migrations/Release/is immutable mixed pre-1.0 history and is not embedded or selected by Platform startup. Verified 2026-07-11.
Anchors
- High-level system view:
../../ARCHITECTURE_REFERENCE.md - Architecture overview:
../../ARCHITECTURE_OVERVIEW.md - Platform overview:
architecture-overview.md - Platform service definition:
platform-service.md - Cryptography & compliance defaults (first-run setup):
cryptography-and-compliance.md - Aggregation-Only Contract:
../concelier/guides/aggregation-only-contract.md(referenced across ingestion/observability docs)
Scope
- Identity & tenancy: Authority-issued OpToks, tenant scoping, RBAC, short TTLs; see Authority module docs. Tenant identity is resolved exclusively from the envelope-attached
stellaops:tenantclaim viaIStellaOpsTenantAccessor; raw tenant headers are not honoured. - Tenant directory: Platform owns
shared.tenants, the platform-wide tenant directory (slug → UUID resolution,is_default,default_regionresidency fallback). Authority owns tenant lifecycle writes and propagates them in. - Frontend configuration: anonymous
GET /platform/envsettings.jsonserves the AngularAppConfig, merged from three layers (env vars → YAML/JSON → DBplatform.environment_settings). - AOC & provenance: services ingest evidence without mutating/merging; provenance preserved; determinism required.
- Offline posture: Offline Kit parity, sealed-mode defaults, deterministic bundles.
- Platform Service: aggregation endpoints for health, quotas, onboarding, preferences, and global search, plus read-model projections (releases, topology, security, integrations, evidence), federated telemetry, NIS2 effectiveness telemetry, crypto/KEK administration, GDPR subject-access, and the migration admin API.
- Migration catalog and Platform bootstrap:
StellaOps.Platform.Databaseis the operator-facing migration-module registry; Platform exposes it through the/api/v1/admin/migrationsAPI and thestellaCLI. Schema-owning services remain responsible for applying their own startup migrations. Platform applies onlyStellaOps.Platform.Database.Migrations.Platformat startup and never creates authoritative deployment-topology tables such asrelease.environments,release.targets,release.regions,release.agents, orrelease.infrastructure_bindings. - Compatibility truthfulness: Platform-owned aliases may aggregate or proxy real module contracts, but Platform must not ship synthetic notify admin, quota/report, Signals, AOC, Console, registry, or inventory-command payloads on live runtime routes. Synthetic compatibility route groups (
/api/v1/console/*,/api/v1/aoc/*,/api/v1/notify/*,/api/v1/signals/*,/api/v1/jobengine/quotas*) are mapped only inDevelopment/Testing. - Observability baseline: metrics/logging/tracing patterns reused across modules; collectors documented under Telemetry module. Platform emits the
StellaOps.Platform.Aggregationmeter and NIS2 area metrics. - Determinism: stable ordering, UTC timestamps, content-addressed artifacts, reproducible exports.
Coordination
Platform docs are the starting point for new contributors; keep this summary in sync with module-specific dossiers and sprint references.
Platform WebService runtime
StellaOps.Platform.WebService is the Console backend. It is a router-microservice (AddRouterMicroservice(serviceName: "platform")) that reaches the gateway over the Valkey/Redis transport and is authenticated with Authority-issued bearer tokens verified by AddStellaOpsResourceServerAuthentication. All bound options live under the Platform configuration section (PlatformServiceOptions).
Storage and startup posture
- Storage is selected by
Platform:Storage:PostgresConnectionString. When present the service binds Postgres-backed stores; otherwise it binds in-memory stores. Startup fails fast (InvalidOperationException) when the connection string is absent outside theTestingenvironment — there is no silent localhost fallback. Platform:Storage:Schemadefaults toplatform. Startup migration bookkeeping is owned byplatform.schema_migrations. The Platform stream createsplatform.*, the cross-cuttingshared.tenants/shared.actor_identitydirectory, and existing Platform-owned compatibility projections underrelease.*; it does not create ReleaseOrchestrator’s authoritative environment/target/agent topology tables.
Composer pipeline and /platform/envsettings.json
The anonymous GET /platform/envsettings.json endpoint (alias GET /envsettings.json for direct service access) returns the Angular frontend AppConfig (EnvironmentSettingsResponse: Authority/OIDC settings, ApiBaseUrls, optional telemetry/welcome/doctor blocks, and a Setup state). The payload is built by EnvironmentSettingsComposer.ComposeAsync from three layers, lowest-to-highest priority:
- Environment variables —
STELLAOPS_*_URLvalues folded intoApiBaseUrlsbyStellaOpsEnvVarPostConfigure(anIPostConfigureOptions<PlatformServiceOptions>). - YAML/JSON config — standard
IOptionsbinding ofPlatform:EnvironmentSettings(and../etc/platform.yaml/platform.yaml). - Database overrides —
platform.environment_settings(key/value), overlaid last viaIEnvironmentSettingsStore. Keys followApiBaseUrls:{service}for per-service base URLs, or scalar names (ClientId,TokenEndpoint,OtlpEndpoint,WelcomeTitle,DoctorFixEnabled,PlatformVersion, …).
PlatformVersion — the installation’s product version
PlatformVersion is the single source of the product version the console shell displays (the string under the brand mark in the sidebar). It is an ordinary environment setting: composed through the three layers above, served in the platformVersion field of /platform/envsettings.json, and changeable at runtime by an operator via PUT /platform/envsettings/db/PlatformVersion without a rebuild.
Two properties are deliberate:
- No compile-time default.
PlatformEnvironmentSettingsOptions.PlatformVersionis null unless a layer supplies a value, the endpoint omits the field when it is blank, and the Angular shell then renders no version element at all. A stale version is worse than no version on a product whose claim is verifiable evidence, so nothing falls back to a literal. - The row is established by migration. Because there is no default,
Migrations/Platform/092_PlatformVersionSetting.sqlinserts the row (v1.0.0-RC1) so the value is present on every database the service starts against. It is idempotent and skips the write when the value already matches.
This replaced a hardcoded string in app-sidebar.component.ts, which had drifted from the 1.0.0-alpha1 in the service .csproj files and from the 1.0.0 the CLI and GET /platform/metadata report. Note that PlatformVersion governs only what the console displays; assembly/InformationalVersion values remain per-project and are not derived from it.
DB-layer overrides are managed through the authenticated admin API GET/PUT/DELETE /platform/envsettings/db[/{key}] (platform.setup.read to list, platform.setup.admin to mutate; mutations are audited). EnvironmentSettingsRefreshService (hosted) re-reads the DB layer on the Platform:Cache:EnvironmentSettingsRefreshSeconds cadence (default 60 s) and reacts to Valkey pub/sub dirty signals when ConnectionStrings:Redis is configured.
Region-scoped signature-verification material (Verification:*)
Operator-entered, region-scoped signature-verification keys/trust-roots are stored as ordinary platform.environment_settings rows (no schema change) under a reserved Verification: namespace, grouped by the active regional crypto profile (world/fips/gost/sm/kcmvp/eidas, see ComplianceProfiles):
Verification:<profile>:PacksRegistry:PublicKeyPem— RSA public key (PEM) for pack signature verification.Verification:<profile>:VexHub:SignatureTrustRoots:<fingerprint>— one row per DSSE HMAC trust root (keyed by signing-key fingerprint).Verification:<profile>:VexHub:EnableSignatureVerification— explicittrue/falseacknowledgement.
The platform STORES + SERVES these admin-entered values; it never generates keypairs. Rows are written through the same audited admin API (PUT /platform/envsettings/db/{key}). A single-region install may omit the <profile> segment (Verification:PacksRegistry:PublicKeyPem); resolution prefers the region-scoped row and falls back to the unscoped form.
Because the /platform/envsettings.json composer is frontend-only and drops unknown keys, backend services do not receive this material through that payload. Instead, VerificationSettingsResolver maps the stored rows into the flat, service-local config keys each validator reads (PacksRegistry:Verification:PublicKeyPem, VexHub:SignatureTrustRoots:<fp>, …) and serves them at GET /platform/verification-settings/{service}?profile=<active> (VerificationSettingsEndpoints). That endpoint is never anonymous: a service pulling at boot authenticates with the shared internal HMAC secret (Router:IdentityEnvelopeSigningKey) in the X-Stella-Verification-Token header, falling back to the platform.setup.read scope. Validator-wave services consume it via PlatformVerificationSettingsConfigurationSource (in StellaOps.Hosting.RuntimeConfiguration), added to builder.Configuration before their verification options bind — one HTTP GET at startup, fail-soft (if the platform is unreachable the source contributes nothing and the existing fail-loud guard correctly aborts). Key changes require a service restart to take effect (config is read once at boot; the platform’s Valkey invalidation only refreshes the platform’s own cache).
Tenant directory (shared.tenants)
Platform owns the shared.tenants directory table (migration 000_shared_tenants_bootstrap.sql):
| Column | Notes |
|---|---|
id UUID | Canonical tenant UUID (slug claims resolve to this via IPlatformTenantResolver). |
tenant_id TEXT UNIQUE | Tenant slug (e.g. default). |
is_default BOOLEAN | Optional installation-default marker. A partial unique index allows at most one marked row; existing and clean installations may legitimately have none. Request tenant resolution does not use this marker. |
default_region VARCHAR(16) | NOT NULL DEFAULT 'unspecified', constrained to ^[a-z0-9][a-z0-9_-]{0,15}$. Platform-owned data-residency fallback consumed by EvidenceLocker when a request carries no explicit region (migration 078_SharedTenantDefaultRegion.sql). |
status, name, display_name, settings, metadata | Lifecycle/state owned by Authority and propagated via ISharedTenantsPropagator; see ../authority/tenant-model.md. |
IPlatformTenantResolver resolves request claims by an active, case-insensitive tenant_id slug (or accepts an already-canonical UUID); it does not infer the request tenant from is_default. The optional local/demo well-known actor seed follows the same invariant. Historical seed S078_SeedWellKnownActorIdentity.sql looked for is_default=true and can therefore be recorded as a successful no-op on older directories. Forward-only S079_RecoverWellKnownActorIdentity.sql recovers those histories by targeting the active canonical default slug without creating a tenant, changing is_default, overwriting a self-upserted row, or restoring erased PII. See the well-known actor seed recovery runbook.
Federation and NIS2 telemetry endpoints
- Federated telemetry —
/api/v1/telemetry/federation/participation/*is tenant-scoped consent and authenticated fact ingress (telemetry:participation:read|write,telemetry:facts:write);/installation/*is installation status, bundles, intelligence, privacy budget, and trigger (platform:federation:read|write). Grant/revoke/fact actors come from authenticated identity. Platform migrations 084-086 persist installation identity, proofs, eligible facts, atomic privacy spending, consent-set material, bundles, peer delivery receipts, pending outbox rows, and imported aggregate intelligence underplatform.telemetry_federation_*. Enabled startup rejects fallback in-memory stores. Egress is destination-allowlisted and sealed-mode fail-closed. - NIS2 effectiveness telemetry —
GET /api/telemetry/nis2/effectiveness?tenantId=&window=returns the live thirteen-area NIS2 effectiveness dashboard (nis2-effectiveness-dashboard-v1) derived from Telemetry Core KPI samples. Authorized byanalytics.read, tenant-scoped,window∈{rolling-30d, rolling-90d}(defaultrolling-90d). It carries honestknownBlockersfor the target-override audit API and the monthly signed export, which are not yet wired.
Database migration registry and host
StellaOps.Platform.Database is the canonical migration-module registry for the whole platform. MigrationModulePlugins.cs declares one IMigrationModulePlugin per registered schema owner, with Platform itself mapped to migration bookkeeping schema platform and resource prefix StellaOps.Platform.Database.Migrations.Platform. MigrationModuleRegistry discovers these via reflection.
Two consumption paths:
- Operator-facing API/CLI —
/api/v1/admin/migrations(modules,status,verify,run;platform.setup.admin) and thestellaCLIsystem/adminmigrate commands enumerate and run migrations across all registered modules. Release-category migrations require dry-run or explicitforce. - Startup auto-migration — at boot Platform calls
AddStartupMigrations(schemaName: "platform", moduleName: "Platform", ...)with theStellaOps.Platform.Database.Migrations.Platformprefix, so only the Platform-owned stream is applied automatically. The assembly may also embed narrowly-scoped operator migration sources selected by another registry module;SbomLineageorders a Platform-owned constraint-namespace preflight, the retained Lineage-library baseline, and a Platform-owned forward repair. That sequence resolves both the shareduq_lineage_edgebacking-index name and the five shared traversal-index names for Platform-first and host-first histories without editing either applied baseline. The oldMigrations/Release/001_v1_platform_database_release_baseline.sqlremains unchanged on disk as forward-only history but is excluded from embedding. ReleaseOrchestrator alone embeds and applies the deployment-topology migrations that createrelease.environmentsand related source tables. Seed-category migrations run only whenPLATFORM_BOOTSTRAP_ENABLED=true; the clean default seeds no demo tenants. Because the runner records a successful no-op, operators recovering S078 must verify that the active canonicaldefaultslug exists before enabling the one-time S079 seed pass, then restore the bootstrap flag tofalse; see the linked recovery runbook above.
Authorization scopes
Platform maps OAuth scopes to named authorization policies in Program.cs via PlatformPolicies → PlatformScopes (Constants/). ops.admin is a global escape hatch for the crypto/KEK policies. Selected mappings:
| Policy | Required scope(s) | Surface |
|---|---|---|
HealthRead / HealthAdmin | ops.health / ops.admin | /api/v1/platform/health/* |
QuotaRead / QuotaAdmin | quota.read|orch:quota / quota.admin|orch:quota | quotas + legacy quota compatibility |
OnboardingRead / OnboardingWrite | onboarding.read / onboarding.write | /onboarding/* |
PreferencesRead / PreferencesWrite | ui.preferences.read / ui.preferences.write | /preferences/*, dashboard profiles |
ContextRead / ContextWrite | platform.context.read / platform.context.write | /api/v2/context/* |
SearchRead / MetadataRead | search.read / platform.metadata.read | global search, metadata |
AnalyticsRead | analytics.read | /api/analytics/*, NIS2 telemetry |
SetupRead / SetupWrite / SetupAdmin | platform.setup.read / .write / .admin | setup wizard, env-settings DB layer, migration admin, seed |
FederationRead / FederationManage | platform:federation:read / platform:federation:write | federated telemetry |
SubjectAccessRead / SubjectAccessErase | platform:sar:read / platform:sar:erase | GDPR subject-access |
ActorIdentityRead (any-of) | ui.read or platform:sar:read | console actor-identity badge resolver (GET /api/v1/platform/actor-identity/{ref}) — any console user resolves the redaction-aware projection (i5 #17) |
CryptoProviderRead / CryptoProviderAdmin / CryptoProfileAdmin | crypto:read / crypto:admin / crypto:profile:admin (or ops.admin) | crypto provider + compliance profile admin |
OperatorSigningEnrollmentRead | authority:signing-keys.enroll (or crypto:read / ops.admin) | narrow tenant compliance-profile projection for operator public-key enrollment |
CryptoKekRead / CryptoKekRotate | crypto:kek:read / crypto:kek:rotate (or ops.admin) | KEK control plane |
TrustRead/Write/Admin, Script*, ReleaseControl* | see PlatformScopes.cs | trust signing, scripts, release-control bundles |
(The frontend OIDC scope superset requested by the SPA lives in PlatformEnvironmentSettingsOptions.Scope.)
Operator signing provider-change composition
PUT /api/v1/admin/crypto-providers/compliance-profile/ and PUT /api/v1/admin/crypto-providers/preferences compare the resolved decision-signing provider before and after the durable Platform write. An unchanged provider creates no new transition, but the request still claims and resumes any existing transition for that tenant. A changed provider is composed through the owning services: Authority resolves enabled users whose effective permissions include exception approval, IssuerDirectory retires only incompatible active DecisionSigning keys, and Notifier accepts platform.crypto-provider-changed only when keys were actually retired. The event targets only retired-key subjects and deep-links to /administration/profile; its event id, payload ordering, and idempotency key are deterministic for replay. Platform:OperatorProviderChange:IssuerId selects the operator key namespace and defaults to operator-signing.
OSK-P5R makes the composition restart-safe. PostgreSQL migration 088 owns platform.operator_provider_change_outbox; the profile/preference mutation and transition intent commit in one transaction. The row freezes tenant, previous/current provider, ordered algorithms, original actor, stable operation id, stage, attempt/backoff, Authority recipients, the IssuerDirectory receipt, and the exact Notify idempotency key/body. It never stores a bearer token or Router envelope. The first Notify send uses the body returned by the outbox checkpoint write (not the pre-write serialization), so PostgreSQL jsonb normalization and replay use identical bytes. Completion is recorded only after Notify accepts. Development/testing uses the same mutation/outbox contract in memory; an async mutation gate makes the setting write and transition enqueue one atomic critical section without blocking an async call under a monitor lock.
The mutation request tries reconciliation immediately and a same-value retry ignores scheduled backoff to resume the existing operation. A production hosted worker, registered after Platform startup migrations, claims due rows across tenants after restart. Ambient authenticated bearer/verified Router-envelope auth is used on the request path; the worker mints a fresh two-minute, tenant-bound service identity envelope from the configured Router:IdentityEnvelopeSigningKey for each downstream request. The persisted original actor remains audit/event metadata while the reconciler service identity is the executing actor. IssuerDirectory keys requests by the stable operation id and replays the original immutable receipt after a lost response. There is no destructive dead-letter transition: a failure releases the lease and keeps the row pending with attempt_count, bounded exponential next_attempt_at (maximum five minutes), and truncated last_error for operator observability; recovery always resumes the same operation. Platform:OperatorProviderChange:ReconciliationIntervalSeconds controls the idle poll interval (default 5, allowed 1-300 seconds).
The IssuerDirectory grace cutoff preserves lifecycle/verification context; Platform does not interpret it as Policy authorization for new exceptions. That authorization rule remains open in OSK-P5.
Scope-catalog gap closed (verified 2026-07-19). Authority migration
S041_platform_console_scope_catalog.sql, the canonicalStellaOpsScopescatalog, and seed-parity tests now coverplatform.setup.read/write/admin,platform.metadata.read,onboarding.read/write,search.read, andops.admin. These Platform policies no longer depend on bypass-network scope satisfaction.
Endpoint surface (route prefixes)
Mapped in Program.cs. Highlights beyond the core /api/v1/platform group:
| Prefix | Endpoint class | Notes |
|---|---|---|
/platform/envsettings.json, /platform/envsettings/db | EnvironmentSettingsEndpoints, EnvironmentSettingsAdminEndpoints | Frontend config (anonymous) + DB-layer admin |
/platform/verification-settings/{service} | VerificationSettingsEndpoints | Region-scoped signature-verification keys for a backend service’s startup config source (shared-token authenticated) |
/api/v1/platform/* | PlatformEndpoints | health, quotas, onboarding, preferences, search, metadata |
/api/v1/search, /api/v1/platform/search | PlatformEndpoints | global search (legacy search path sends Deprecation/Sunset headers) |
/api/v2/context, /api/v2/releases, /api/v2/topology, /api/v2/integrations, /api/v2/evidence | Context + read-model endpoints | Platform-owned aggregation-only read-model projections |
/api/v1/telemetry/federation, /api/telemetry/nis2 | FederationTelemetryEndpoints, Nis2TelemetryEndpoints | federation + NIS2 telemetry |
/api/v1/admin/migrations | MigrationAdminEndpoints | cross-module migration status/verify/run |
/api/v1/admin/crypto/kek, /api/v1/admin/crypto-providers, /api/v1/admin/crypto/profile | crypto admin endpoints | KEK control plane, provider catalog, profile validate |
/api/v1/platform/connector-credentials, /api/v1/platform/connectors | ConnectorCredentialsEndpoints, ConnectorsCatalogEndpoints | Credential-at-rest store (see Connector credential store below); connector:credentials:read/:write |
MapVerificationKeyLifecycleEndpoints, MapPackAdapterEndpoints, MapActorIdentityEndpoints, MapEvidenceThreadEndpoints | verification-key lifecycle, pack adapters, actor identity, evidence threads | mapped in Program.cs; see source for exact prefixes |
/api/v1/setup, /api/v1/admin (seed) | SetupEndpoints, SeedEndpoints | first-run setup wizard, demo seed |
/api/v1/platform/localization | LocalizationEndpoints | tenant-scoped localization |
/api/v1/release-control/bundles, /api/v1/release-orchestrator/environments | release-control + environments | read-model + RO environment proxy |
/api/v1/administration/trust-signing, /api/v2/scripts, /api/v1/stella-assistant | misc | trust signing, scripts, assistant |
/healthz, /readyz, /health, /buildinfo.json | inline | anonymous liveness/readiness + image-staleness self-check |
Relocated stable paths keep their public URLs but are no longer Platform surfaces: /api/v1/score/* is owned by Signals, /api/v1/function-maps/* by Scanner, /api/v1/policy/interop/* by Policy Engine, and /api/v2/security/* plus /api/risk/aggregated-status by Findings.Security. Router configuration is the external ownership source of truth.
PostgreSQL-backed topology reads retain a process-local last-known snapshot and its synchronization watermarks for brief connection-exhaustion recovery. The cache is isolated by tenant, bounded to 2,048 tenant entries, and expires each value after five minutes. It is populated only by a successful inventory read or upsert, preserves an authoritative null snapshot sentinel, and is consulted only when PostgreSQL reports SQLSTATE 53300 (too_many_connections). Missing or expired last-known values and every other storage failure continue to propagate, so the recovery cannot hide schema, authorization, cancellation, or unknown infrastructure failures.
Identity provider ownership boundary
Identity-provider configuration is Authority-owned and process-global. The canonical operator surface is /console/admin/identity-providers, protected by authority:idp.read / authority:idp.write. Platform no longer maps /api/v1/platform/identity-providers, registers its former read/write policy, proxies Authority status, performs LDAP/OIDC/SAML probes, or carries an identity-provider persistence service. The console and CLI must call Authority directly so there is one mutation and runtime-status contract.
Migration 087_v1_platform_identity_provider_configs.sql is intentionally retained byte-for-byte as forward-only history (normalized SHA-256 2a76024dca7c92436b2b6498673059c3e13360957ea1e51191b87685f8251bf2) and as the input to Authority’s one-time, cross-database global-provider importer. Its retirement comment is applied by the additive 089_v1_platform_identity_provider_configs_retirement_comment.sql migration; an already-applied migration is never edited to describe later lifecycle state. Platform has no EF entity, DbSet, store, or endpoint that can write platform.identity_provider_configs; therefore the table is empty on a fresh installation and vestigial after an upgrade/import. Authority reads it through Authority:IdentityProviderImport:PlatformConnectionString. Physical removal is deferred until import completion and a PostgreSQL snapshot are operator-approved under ADR-004; this sprint does not drop the table.
Connector credential store (ConnectorCredentials/)
The Console backend hosts a credential-at-rest subsystem under StellaOps.Platform.WebService/ConnectorCredentials/, mapped by MapConnectorCredentialsEndpoints() / MapConnectorsCatalogEndpoints() (Program.cs). It stores integration credentials (SCM/CI/registry/secrets connectors) encrypted at rest and is the reason the crypto-provider + KEK control plane exist on Platform. Key components:
PostgresCredentialStore(ICredentialStore) — durable, tenant-scoped credential rows.ConnectorCredentialAead— envelope (AEAD) encryption of secret material, keyed through the KEK control plane; regional crypto substituted viaRegionalCryptoPluginActivation(no cloud-managed KMS default, per the on-prem invariant).ConnectorCredentialReSealStore+ConnectorCredentialExpirySweeper— re-seal on key rotation and expiry-driven cleanup.ConnectorCredentialsChangePublisher— change notifications to consumers (Concelier/Excititor resolve credentials via the/resolveroute underconnector:credentials:read).UnifiedCredentialAuditEmitter(ICredentialAuditEmitter) — audit trail for every mutation.
Authorization: every route checks connector:credentials:read or connector:credentials:write in-handler (ConnectorCredentialsEndpoints.cs); both scopes are in the canonical catalog. This is a security-relevant surface — treat credential read/rotate as privileged and audited.
Shared Storage Driver Contract (Sprint 312)
This contract is the default for all stateful StellaOps webservices unless a module ADR explicitly overrides it.
Storage:Driver- Accepted values:
postgres,inmemory,filesystem. - Production default:
postgres. inmemoryandfilesystemare non-production/testing-only and must be explicitly configured.
- Accepted values:
Storage:ObjectStore:Driver- Accepted values at platform key level:
rustfs,seed-fs. - Module runtime contracts may narrow this set and must fail fast for unsupported values.
- Use only for blob/object payload channels (artifacts, snapshots, package blobs).
- Accepted values at platform key level:
ConnectionStrings:Default- Required when
Storage:Driver=postgresunless a service-specific connection key is provided. - Service-specific key, when present, takes precedence over
ConnectionStrings:Default.
- Required when
Fail-fast policy:
- Non-development runtime must fail startup when required storage configuration is missing (no silent localhost/file fallback).
- Development runtime may use localhost/file defaults only when explicitly intended for local workflows.
Current implementation status (2026-03-05):
PacksRegistry: Postgres metadata/state + seed-fs payload channel for pack/provenance/attestation blobs; startup rejectsrustfsand unknown object-store drivers.TaskRunner: Postgres run state/log/approval + seed-fs artifact payload channel; startup rejectsrustfsand unknown object-store drivers in both WebService and Worker.RiskEngine: Postgres-backed result store (riskengine.risk_score_results) with explicit in-memory test fallback.Replay: Postgres snapshot index + seed-fs snapshot blob store; startup rejectsinmemoryoutsideTesting, rejectsrustfs, and rejects unknown object-store drivers.OpsMemory: connection precedence aligned toConnectionStrings:OpsMemory -> ConnectionStrings:Default, with non-development fail-fast.Platform: Postgres-backed platform-owned state (platform.*,release.*); startup rejects missingPlatform:Storage:PostgresConnectionStringoutsideTesting, and in-memory stores are injected only by explicitTestingharnesses.Platform compatibility harnesses: synthetic/api/console/*,/api/v1/aoc/*,/api/v1/notify/*,/api/v1/signals/*, and/api/v1/jobengine/quotas*route groups are mapped only inDevelopmentandTesting; durable/api/v1/authority/quotas/*aliases remain owned byPlatformEndpoints.Platform registry search: production requires an explicitly configured registry backend and returns503for missing/failing backends instead of empty fixture success.Platform inventory collection: production does not bindNoOpRemoteCommandExecutor; missing executor integration resolves to a fail-closed Platform executor that reports inventory collection unavailable.Platform QA fixture readback:/api/qa/fixtures/advanced-assurance-goldenis disabled by default and reads only configured local seed artifacts; it validatesseed-integrity.jsonagainstseed-manifest.jsonand never accepts request-supplied filesystem paths.Platform advanced-assurance case summary:/api/assurance/cases/ASSURANCE-GOLDEN-PROD-PAYMENTS-001reuses validated seed artifacts and reportsliveRowsImported=falseso operators can distinguish global fixture readback from module-owned write-through/import.- Shared artifact infrastructure:
AddUnifiedArtifactStorebinds the S3 object store plus PostgreSQL artifact index and registers embedded startup migrations forevidence.artifact_index. Process-local in-memory artifact stores are test-project fixtures only and are not exposed through production shared-library DI. - Shared Evidence Pack library:
AddEvidencePackno longer binds process-local pack storage by default. Callers must register a durableIEvidencePackStore; otherwise the shared library resolves a fail-closed store that throws on use. Tests and explicit local harnesses may still opt intoUseInMemoryEvidencePackStore. - Shared HLC library:
AddHybridLogicalClockwithout an explicit state store binds fail-closedIHlcStateStore; production callers must choose a durable store such as PostgreSQL, while local/test harnesses must callAddHybridLogicalClockInMemoryexplicitly.
Platform Runtime Read-Model Boundary Policy (Point 4 / Sprint 20260305-005)
Platform runtime read-model APIs are aggregation-only and must stay behind explicit query contracts. Runtime read handlers must not take direct dependencies on foreign module persistence internals.
Approved runtime query contracts:
IReleaseControlBundleStore(release/topology/security/integration projections over release-control bundles + runs).IPlatformContextQuery(read-only access to region/environment context inventory).
Prohibited in runtime read-model services:
- Direct constructor dependencies on foreign
StellaOps.*.Persistence*namespaces. - Direct
DbContext,NpgsqlDataSource, or module-specific migration runner dependencies from non-admin read endpoints.
Migration/admin allowlist (explicit boundary exceptions):
src/Platform/StellaOps.Platform.WebService/Endpoints/SeedEndpoints.cssrc/Platform/__Libraries/StellaOps.Platform.Database/MigrationModulePlugins.cs
Enforcement:
- Guard tests in
src/Platform/__Tests/StellaOps.Platform.WebService.Tests/PlatformRuntimeBoundaryGuardTests.csfail when constructor contracts drift or foreign persistence references appear outside the allowlist above.
Runtime Dependency Inventory (2026-03-05)
| Component | Dependency category | Classification | Notes |
|---|---|---|---|
ReleaseReadModelService | IReleaseControlBundleStore | Allowed runtime read-model dependency | Release projection reads only via Platform-owned bundle-store contract. |
TopologyReadModelService | IReleaseControlBundleStore, IPlatformContextQuery | Allowed runtime read-model dependency | Topology projection composes release bundles with context inventory through explicit query contracts. |
SecurityReadModelService | IReleaseControlBundleStore, IPlatformContextQuery | Allowed runtime read-model dependency | Security projection remains synthetic/read-only and does not call VEX/exception write stores directly. |
IntegrationsReadModelService | IReleaseControlBundleStore, IPlatformContextQuery | Allowed runtime read-model dependency | Integration freshness projection uses release run metadata and context inventory only. |
PlatformContextService | IPlatformContextStore (InMemory/Postgres) | Allowed runtime dependency (module-local persistence) | Exposes read-only IPlatformContextQuery plus preference write APIs; no foreign module coupling. |
SeedEndpoints | Foreign StellaOps.*.Persistence* migration assemblies | Migration/admin-only dependency | Allowed exception for demo seed execution only (platform.setup.admin). |
MigrationModulePlugins | Foreign module migration assemblies | Migration-only dependency | Allowed exception for schema migration orchestration, not part of runtime read endpoint execution path. |
Advisory Commitments (2026-02-26 Batch)
SPRINT_20260226_223_Platform_score_explain_contract_and_replay_alignmentdefines deterministic score/explain/replay contract behavior for CLI and Web consumers.SPRINT_20260226_230_Platform_locale_label_translation_correctionscompletes locale label correction baseline for cross-language operator UI consistency.- Cross-module advisory translation tracking is maintained in
docs/product/advisory-translation-20260226.md.
