Setup Wizard - Capability Specification

Audience: engineers and product owners implementing or extending the Stella Ops Setup Wizard across the CLI and Console. For the user-facing flow, see setup-wizard-ux.md; for the validation/remediation contract, see setup-wizard-doctor-contract.md.

This document defines the functional requirements for the Stella Ops Setup Wizard, covering both CLI and UI implementations.

Source of truth (verified against src/). The backend-authoritative step contract is SetupStepDefinitions.All in src/Platform/StellaOps.Platform.WebService/Contracts/SetupWizardModels.cs. It defines exactly six steps: Database, Valkey, Migrations, Admin, Crypto (required) and Sources (optional). The Platform setup API (SetupEndpoints.cs) and PlatformSetupService.ProbeStepCoreAsync reject any other step id with “is not part of the installation bootstrap contract”. Sections in this doc that describe additional steps (Vault, Settings Store, SCM, Registry, Notifications, Identity, Environments, Agents, Assurance) are onboarding/handoff capability notes, not setup-wizard steps — they are not accepted by the current setup APIs or the stella setup command group. Where this doc disagrees with the code, the code wins.

1. Overview

The Setup Wizard provides a guided, step-by-step configuration experience that:


2. Completion Thresholds

2.1 Operational (Minimum Required)

The system enters “Operational” state when the required platform dependencies report ready. PlatformHealthService.BuildReadinessAsync (src/Platform/StellaOps.Platform.WebService/Services/PlatformHealthService.cs) builds the readiness summary from five setup-step-derived dependencies plus two live HTTP probes, and PlatformSetupService.FinalizeSessionAsync blocks finalize unless ReadyToProceed is true (or Force=true):

Readiness dependencyDescriptionSource signal
database (Database)PostgreSQL reachable; Database setup step passedsetup step state + check.database.connectivity / check.database.version probe
cache (Cache)Valkey/Redis reachable; Valkey setup step passedsetup step state + check.services.valkey.connectivity probe
migrations (Migrations)Required modules (Platform, ReleaseOrchestrator) convergedsetup step state + check.database.migrations.pending / .applied probe
admin-bootstrap (Admin Bootstrap)Bootstrap admin ensured via Authority; Admin step passedsetup step state + check.authority.admin.exists / check.auth.password.policy probe
crypto-profile (Crypto Profile)Regional crypto/compliance profile saved; Crypto step passedsetup step state + check.crypto.profile probe
front-door (Front Door)Platform front-door HTTP probe succeedslive reachability probe
authority (Authority)Authority service health endpoint respondslive AuthorityInternal health probe

Reconciled: the previous “Doctor Check” column listed IDs such as check.services.core.healthy, check.crypto.profile.valid, and check.auth.admin.exists. These are not the IDs emitted by the setup probes, and the readiness gate is not a Doctor-plugin run — it is the step-derived dependency summary above. Setup-step Doctor check IDs are listed per step in §4; the Doctor module’s own catalog (src/Doctor/**) uses unrelated namespaces (check.agent.*, check.scanner.*, check.notify.*, …).

Gating Behavior: Setup status and finalize gate only on this operational threshold. Optional post-boot services may still be degraded and are surfaced through health diagnostics instead of blocking bootstrap completion.

2.2 Production-Ready (Recommended)

Roadmap / out of scope for the wizard. None of the items below are required-readiness signals in the current code, and none of the check.* IDs in this table exist in src/. They describe operator best-practice that is configured through authenticated post-bootstrap surfaces (Integrations, Identity & Access, Notifications, Trust & Signing, Orchestrator), not the setup wizard. Treat this section as a hardening checklist, not a contract.

A production deployment is typically configured with:

RecommendationDescriptionWhere configured
OIDC/LDAP configuredExternal identity provider integratedAuthority / /setup/identity-access
Vault connectedAt least one secrets providerIntegrations / Secrets surfaces
SCM integratedAt least one SCM (GitHub/GitLab)Integrations
Notifications configuredAt least one notification channelNotify / /setup/notifications
Feed sync enabledVulnerability advisory/VEX mirroring activeoptional sources step or Integrations → Advisory & VEX Sources
Environment definedAt least one environment createdReleaseOrchestrator environments
Agent registeredAt least one healthy agentOrchestrator agent registration
TLS hardenedAll endpoints using TLS 1.2+reverse proxy / gateway deployment

3. Step Catalog

3.1 Core Steps

The backend-authoritative inventory is SetupStepDefinitions.All (SetupWizardModels.cs). It is exactly the following six steps; the API projects these (and only these) to the Console and CLI:

Step ID (frontend)SetupStepIdName (backend Title)RequiredSkippableCategoryDepends on
databaseDatabaseDatabase SetupYesNoInfrastructure
cacheValkeyValkey/Redis SetupYesNoInfrastructure
migrationsMigrationsDatabase MigrationsYesNoInfrastructuredatabase
adminAdminAdmin BootstrapYesNoSecuritymigrations
cryptoCryptoCryptographyYesNoSecurityadmin
sourcesSourcesAdvisory & VEX SourcesNoYesRelease Control Planeadmin

Notes verified against src/:

The integration and orchestration catalogs below are historical handoff targets and are not accepted by the current Platform setup API (PlatformSetupService.ProbeStepCoreAsync rejects them) nor surfaced by the stella setup command group’s backend-authoritative flow.

3.2 Integration Handoffs (Not current setup steps)

The Platform backend rejects these step ids. Note that the CLI still ships matching ISetupStep implementations in src/Cli/StellaOps.Cli/Commands/Setup/Steps/Implementations/ (e.g. VaultSetupStep, ScmSetupStep, NotifySetupStep, RegistrySetupStep, SettingsStoreSetupStep, LlmSetupStep, TelemetrySetupStep), and the Web DEFAULT_SETUP_STEPS fallback list still enumerates them — but Identity as a standalone step is not in either inventory (OIDC/LDAP is configured via the authority/admin provider selection and post-bootstrap Identity & Access surfaces).

Step IDNameRequiredSkippableCategoryWhere actually implemented
vaultSecrets ProviderNoYesIntegrationCLI step + Web fallback list (not Platform API)
settingsstoreSettings StoreNoYesIntegrationCLI step + Web fallback list (not Platform API)
scmSource ControlNoYesIntegrationCLI step + Web fallback list (not Platform API)
registryContainer RegistryNoYesIntegrationCLI step + Web fallback list (not Platform API)
notify / notificationsNotification ChannelsNoYesIntegrationCLI step id is notify; Web fallback uses notify (not Platform API)
identityIdentity Provider (OIDC/LDAP)NoYesSecurityNot implemented as a step; configured via Authority provider + Identity & Access

3.3 Orchestration Handoffs (Not current setup steps)

The Platform backend rejects these step ids. The CLI registers EnvironmentsSetupStep / AgentsSetupStep and the Web DEFAULT_SETUP_STEPS fallback enumerates them, but they are not part of the backend bootstrap contract.

Step IDNameRequiredSkippableCategoryWhere actually implemented
environmentsEnvironment DefinitionNoYesOrchestrationCLI step + Web fallback list (not Platform API)
agentsAgent RegistrationNoYesOrchestrationCLI step + Web fallback list (not Platform API)

4. Step Specifications

Sections 4.1–4.5.1 describe the current installation-scoped setup steps that the Platform API accepts (Database, Valkey, Migrations, Admin, Crypto, Sources). §4.5.2 (Assurance) is not a step — see the annotation there.

Sections 4.6 and later are capability notes, not Platform setup steps. The Platform API rejects these step ids (ProbeStepCoreAsync → “is not part of the installation bootstrap contract”). Their inputs belong to: (a) the CLI setup steps under src/Cli/StellaOps.Cli/Commands/Setup/Steps/Implementations/, which the CLI runner can execute independently, and (b) authenticated post-bootstrap surfaces (Integrations, Notify, Trust & Signing, Identity & Access, ReleaseOrchestrator). Field/connector tables below were not re-verified line-by-line against each connector implementation; treat them as design reference, and verify against the owning module before relying on a specific field name or default.

4.1 Database Setup (database)

Purpose: Configure PostgreSQL connection and verify accessibility.

Inputs (config keys consumed by ProbeDatabaseAsync / ResolveDatabaseConnectionString):

Config keyTypeRequiredDefaultDescription
database.connectionStringsecretNo-Full Npgsql connection string; takes precedence if provided
database.hoststringConditional-PostgreSQL host (used with the other discrete fields)
database.portnumberNo5432PostgreSQL port
database.databasestringConditional-Database name
database.userstringConditional-Database user
database.passwordsecretConditional-Database password

When no override is supplied, the probe falls back to the platform’s configured Platform:Storage:PostgresConnectionString.

Reconciled: the previously documented sslMode and poolSize inputs are not read by the setup probe (the discrete-field fallback builds Host=…;Port=…;Database=…;Username=…;Password=…;Timeout=5). SSL/pool tuning is a machine-bootstrap connection-string concern.

Outputs / Validation (reconciled):

Doctor Checks:

Persistence (reconciled):


4.2 Valkey/Redis Setup (valkey)

Purpose: Configure Valkey/Redis for caching, queues, and session storage.

Inputs (config keys consumed by ProbeCacheAsync):

Config keyTypeRequiredDefaultDescription
cache.hoststringNocache.stella-ops.localValkey host
cache.portnumberNo6379Valkey port

Reconciled: the previously documented password, database, useTls, and abortOnConnectFail inputs are not read by the setup probe. The quick-check path additionally derives cache.host/cache.port from the runtime ConnectionStrings:Redis / Router:Messaging:valkey:ConnectionString / STELLAOPS_VALKEY_URL values (BuildCacheConfigFromRuntime).

Outputs / Validation (reconciled):

Doctor Checks:


4.3 Database Migrations (migrations)

Purpose: Converge the required platform schemas (no pending startup or release migrations).

Inputs (reconciled):

Behavior:

Doctor Checks (reconciled):


4.4 Admin Bootstrap (admin)

Purpose: Ensure the bootstrap administrator exists via the Authority service.

Inputs (config keys consumed by ProbeAdminAsync / ApplyAdminAsync):

Config keyTypeRequiredDefaultDescription
users.superuser.usernamestringYes-Admin username
users.superuser.emailstringYes-Admin email
users.superuser.passwordsecretYes-Admin password
users.superuser.displayNamestringNo-Display name
authority.providerstringNo-Authority provider override passed to the bootstrap request (see normalization below)
users.additional.{i}.usernamestringNo-Username for optional additional user i (0-based)
users.additional.{i}.emailstringNo-Email for additional user i
users.additional.{i}.passwordsecretConditional-Initial password for additional user i (required when a username is present)
users.additional.{i}.rolestringNorole/service-release-contributorAuthority role bundle for additional user i

Behavior:

Validation (reconciled):

Doctor Checks:


4.5 Cryptography (crypto)

Purpose: Choose a regional cryptography profile and prepare optional compliance evidence support (NIS2 / DORA / CRA). This is a required step in the backend contract (the Web shell labels it “Compliance” and treats it as the final touch after the other required steps).

Reconciled — this step does not configure signing keys. The previously documented profileType (local/kms/hsm/sigstore), keyAlgorithm, keyId, certificatePath, privateKeyPath inputs, the “key material accessible / certificate chain valid” validation, and the check.crypto.profile.valid / check.crypto.signing.test checks do not exist in ProbeCryptoAsync / ApplyCryptoAsync / ResolveCryptoSettingsAsync. The step writes a regional profile + compliance flags to the environment settings store; signing-key material is a Trust & Signing / Signer concern outside the setup wizard.

Inputs (config keys consumed by ResolveCryptoSettingsAsync):

Config key (aliases)TypeRequiredDefaultDescription
Crypto:Region (crypto.region, crypto.provider)enumNointernationalRegional profile; normalized to one of international, eidas, russian, chinese. Aliases such as fips/world/eu/gost/sm/cryptopro are mapped.
Crypto:FipsMode (crypto.fipsMode, crypto.fips.enabled, fips.enabled)booleanNotrue only when region alias is fips, else falseFIPS-140 mode (only meaningful for the International profile)
Compliance:Nis2:Enabled (compliance.nis2.enabled)booleanNofalseEnable NIS2 evidence support
Compliance:Dora:Enabled (compliance.dora.enabled)booleanNofalseEnable DORA evidence support
Compliance:Cra:Enabled (compliance.cra.enabled)booleanNofalseEnable CRA evidence support

When a compliance flag is enabled, the probe additionally looks for prerequisite settings and emits warnings (not failures) if they are missing — e.g. NIS2 checks for an Authority compliance-profile URL, DORA for a Notify channel, CRA for a manufacturer mailbox + intake key fingerprint.

Note: the Web CRYPTO_PROVIDERS catalog also lists a korean (KCMVP) profile and marks russian as disabled under European Edition. The backend NormalizeCryptoRegion currently maps to international/eidas/russian/chinese only — korean is a frontend-only option pending backend support.

Outputs:

Doctor Checks (reconciled):


4.5.1 Advisory & VEX Sources (sources)

Purpose: Optionally enable advisory and VEX aggregation during bootstrap without forcing operators through the full integrations catalog on first run.

Flow: The Platform step is a thin pass-through. ProbeSourcesAsync / ApplySourcesAsync forward the sources.*-prefixed config to Concelier’s internal setup endpoints (POST internal/setup/advisory-sources/probe and /apply, retried while Concelier reports transient 502/503/504), which own source validation and persistence (ConfiguredAdvisorySourceService).

Inputs (config keys, sources.-prefixed at the wire — verified in Concelier ConfiguredAdvisorySourceService):

Config keyTypeRequiredDefaultDescription
sources.modeenumYesmirrormirror enables StellaOps Mirror only; manual exposes explicit source selection
sources.mirror.urlstringWhen mode=mirrorStellaOps Mirror base endpointStellaOps Mirror base URL
sources.mirror.apiKeysecretNo-Optional StellaOps Mirror API key
sources.enabledstring[]When mode=manual[]Advisory/VEX source IDs to enable

Reconciled: the previous unprefixed names (mode, mirror.url, …) are the conceptual fields; the wire keys are sources.*. Only sources.* keys are forwarded by FilterConfigForStep(Sources, …).

Outputs:

Validation (enforced in Concelier):

Doctor Checks:

Skip behavior:


4.5.2 Assurance Packs (assurance) — NOT IMPLEMENTED as a setup step

NOT IMPLEMENTED. There is no assurance setup step. It is absent from the backend SetupStepDefinitions.All, from the Web SetupStepId union and DEFAULT_SETUP_STEPS, and from the CLI SetupStepCatalog. The check.assurance.packs.optional, check.assurance.nis2.soa.prerequisites, and check.assurance.cra.publication.preflight identifiers do not appear anywhere in src/. The wizard does not probe, apply, skip, or report assurance-pack state.

What does exist: (1) the Crypto step (§4.5) carries the optional NIS2 / DORA / CRA compliance evidence enable flags and their prerequisite warnings; (2) Assurance Packs are a post-bootstrap capability surfaced by the Console Compliance feature (src/Web/StellaOps.Web/src/app/features/compliance/**, assurance-packs.client.ts) and routed through Authority / ExportCenter / Notify / Trust / /assurance. The text below is retained only as a forward- looking description of that post-setup capability — it is not a setup-wizard contract.

Intended post-bootstrap behavior (roadmap / Compliance surfaces, not the wizard):

Pack lines (capability notes):

PackReadiness linePrerequisite groups
NIS2 Evidence PackSoA live-export readinessAuthority compliance profile URL/availability, ExportCenter SoA storage root, signing provider/key, tenant export trust roots
CRA Product Security PackLocal signed export readinessExportCenter storage/signing and evidence bundle references
CRA Product Security PackLive public publication readinessproduct-security mailbox delivery/access, non-expired encryption-capable intake key, rotation roles, support lifecycle/publication metadata

4.6 Vault Integration (vault)

Purpose: Configure secrets management provider.

Multi-Connector Support: Yes - users can add multiple vault integrations.

Connector Options:

ConnectorDefaultDescription
HashiCorp VaultYes (if detected)KV v2 secrets engine
Azure Key VaultYes (if Azure env)Azure-native secrets
AWS Secrets ManagerYes (if AWS env)AWS-native secrets
File ProviderFallbackLocal file-based secrets

Inputs (HashiCorp Vault):

FieldTypeRequiredDefaultDescription
addressstringYes-Vault server URL
authMethodenumYestokentoken, approle, kubernetes
mountPointstringNosecretKV mount point
tokensecretConditional-Vault token
roleIdstringConditional-AppRole role ID
secretIdsecretConditional-AppRole secret ID

Default Selection Logic:

  1. If VAULT_ADDR env var set → HashiCorp Vault
  2. If Azure IMDS available → Azure Key Vault
  3. If AWS metadata available → AWS Secrets Manager
  4. Otherwise → Prompt user

Doctor Checks:


4.7 Settings Store Integration (settingsstore)

Purpose: Configure application settings and feature flag providers.

Multi-Connector Support: Yes - users can add multiple settings stores for different purposes.

Connector Options:

ConnectorPriorityWriteWatchFeature FlagsLabels
Consul KVP0ConfigurableYesNoNo
etcdP0ConfigurableYesNoNo
Azure App ConfigurationP1Read-onlyYesYes (native)Yes
AWS Parameter StoreP1ConfigurableNoNoVia path
AWS AppConfigP2Read-onlyYesYes (native)Yes
ZooKeeperP2ConfigurableYesNoNo
GCP Runtime ConfigP2Read-onlyYesNoNo

Inputs (Consul KV):

FieldTypeRequiredDefaultDescription
addressstringYes-Consul server URL
tokensecretNo-ACL token
tokenSecretRefstringNo-Vault path to ACL token
writeEnabledbooleanNofalseEnable write operations

Inputs (etcd):

FieldTypeRequiredDefaultDescription
addressstringConditional-Single endpoint URL
endpointsstring[]Conditional-Multiple endpoint URLs
usernamestringNo-Authentication username
passwordsecretNo-Authentication password
passwordSecretRefstringNo-Vault path to password
writeEnabledbooleanNofalseEnable write operations

Default Selection Logic:

  1. If CONSUL_HTTP_ADDR env var set -> Consul KV
  2. If ETCD_ENDPOINTS env var set -> etcd
  3. If Azure IMDS + App Config connection available -> Azure App Configuration
  4. If AWS metadata + /stellaops/ path exists -> AWS Parameter Store
  5. Otherwise -> Prompt user

Doctor Checks:


4.8 SCM Integration (scm)

Purpose: Configure source control management integrations.

Multi-Connector Support: Yes - users can add GitHub AND GitLab simultaneously.

Connector Options:

ConnectorDescription
GitHub AppGitHub.com or GHES via App installation
GitLab ServerGitLab.com or self-hosted
BitbucketBitbucket Cloud or Server
GiteaSelf-hosted Gitea
Azure DevOpsAzure Repos

Inputs (GitHub App):

FieldTypeRequiredDefaultDescription
appIdstringYes-GitHub App ID
installationIdstringYes-Installation ID
privateKeysecretYes-App private key (PEM)
apiUrlstringNohttps://api.github.comAPI endpoint

Doctor Checks:


4.9 Notification Channels (notifications)

Purpose: Configure notification delivery channels.

Multi-Connector Support: Yes - multiple channels per type allowed.

Channel Options:

ChannelDescription
SlackIncoming webhook
TeamsIncoming webhook
EmailSMTP server
WebhookGeneric HTTP POST
PagerDutyIncident alerts

Inputs (Slack):

FieldTypeRequiredDefaultDescription
namestringYes-Channel display name
webhookUrlsecretYes-Slack incoming webhook URL
channelstringNo-Default channel override
usernamestringNoStellaOpsBot username
iconEmojistringNo:shield:Bot icon

Doctor Checks:


4.10 Environment Definition (environments)

Purpose: Define deployment environments (dev, staging, prod).

Inputs:

FieldTypeRequiredDefaultDescription
namestringYes-Environment slug (lowercase)
displayNamestringYes-Display name
orderIndexnumberYes-Pipeline position (0=first)
isProductionbooleanNofalseProduction flag
requiredApprovalsnumberNo0Approval count
requireSeparationOfDutiesbooleanNofalseSoD enforcement
autoPromoteFromstringNo-Auto-promote source

Validation:

Doctor Checks:


4.11 Agent Registration (agents)

Purpose: Register deployment agents with the orchestrator.

Inputs:

FieldTypeRequiredDefaultDescription
namestringYes-Agent name
capabilitiesstring[]Yes-docker, compose, ssh, winrm
labelsmapNo{}Agent labels for selection

Outputs:

Generated Command:

stella-agent register --token <token> --name <name> --orchestrator-url <url>

Doctor Checks:


5. Multi-Connector Model

Scope note: the multi-connector model below applies to the CLI/integration connector catalogs and post-bootstrap Integrations surfaces, not to the six-step Platform setup contract. The Platform setup session stores draft values and secret-draft metadata per step (SetupSession.DraftValues / SecretDrafts); it does not implement per-category connector instances or lastConnectors preference persistence. Treat instance limits and selection heuristics as design intent unless verified in the owning module.

5.1 Connector Categories

Each integration category supports multiple instances:

CategoryMax InstancesUse Case
Vault5Separate vaults per environment
Settings Store5Config from Azure App Config + feature flags from Consul
SCM10GitHub + GitLab + internal Gitea
Registry10ECR + Harbor + internal registry
Notifications20Slack per team + email + PagerDuty

5.2 Default Connector Selection

The wizard suggests a default connector based on:

  1. Environment Detection:

    • VAULT_ADDR -> HashiCorp Vault
    • CONSUL_HTTP_ADDR -> Consul KV
    • ETCD_ENDPOINTS -> etcd
    • Azure IMDS -> Azure Key Vault / Azure App Configuration
    • AWS metadata -> AWS Secrets Manager / AWS Parameter Store
    • GITHUB_TOKEN -> GitHub
    • GITLAB_TOKEN -> GitLab
  2. Configuration Files:

    • Existing etc/*.yaml samples
    • Docker Compose environment files
  3. Repository Defaults:

    • Harbor (most commonly used registry)
    • Slack (most common notification)

5.3 Last Selected Connector Persistence

The wizard stores user preferences in the settings store:

{
  "setupWizard": {
    "lastConnectors": {
      "vault": "hashicorp-vault",
      "settingsstore": "consul-kv",
      "scm": "github-app",
      "registry": "harbor",
      "notifications": "slack"
    },
    "completedAt": "2026-01-13T10:30:00Z",
    "skippedSteps": ["sources"]
  }
}

Reconciled: identity is not a setup step, so it cannot appear in skippedSteps (only the optional sources step is skippable in the Platform contract). This lastConnectors shape is illustrative for the connector catalogs; the Platform setup session does not persist it.


6. Resume/Re-run Behavior

6.1 Idempotency Requirements

All steps must be safe to re-run:

StepRe-run Behavior
databaseVerify connection; no changes if already configured
migrationsSkip already-applied; apply only pending
adminSkip if admin exists; offer password reset
vaultAdd new integration; don’t duplicate
settingsstoreAdd new integration; don’t duplicate
scmAdd new integration; don’t duplicate

6.2 Re-run and Reconfigure Access (reconciled)

The CLI setup command group (SetupCommandGroup.cs) exposes these subcommands — there is no --reconfigure flag:

On the server side, re-running is supported because steps are idempotent and a session can be re-created with ForceRestart (preserving prior draft values). The Console exposes the wizard at the setup-wizard route; “Settings > Configuration Wizard” is descriptive, not a verified menu label.


7. Security Posture

7.1 Secret Storage

Secret TypeStorage Location
Database passwordVault (if configured) or local keyring
Valkey passwordVault (if configured) or local keyring
API tokensVault integration
Private keysFile system with 0600 permissions

7.2 Redaction Rules

The wizard must never display:

Display format for sensitive fields:

7.3 Audit Trail (reconciled)

Mutating setup endpoints are decorated with .Audited(AuditModules.Platform, AuditActions.Platform.<action>, "setup") — e.g. CreateSetupSession, ExecuteSetupStep, SkipSetupStep, FinalizeSetup (see SetupEndpoints.cs). Admin bootstrap is performed through the Authority internal/users endpoint, so the admin-creation audit lives in Authority.

Reconciled: the previously documented “Timeline service with HLC timestamps” and “Doctor run history for check results” are not the mechanism for setup-action auditing in the current code. Setup uses the Platform audit emission decorator above.


8. Error Handling

8.1 Validation Errors

Error TypeBehavior
Invalid inputInline error message; prevent progression
Connection failureShow error; offer retry with different params
Permission deniedShow required permissions; offer skip (if skippable)
TimeoutShow timeout; offer retry with increased timeout

8.2 Partial Completion

If wizard exits mid-flow:


9. Exit Criteria

9.1 Successful Completion

FinalizeSessionAsync completes the session (Completed) only when:

A skipped optional Sources step does not block completion.

9.2 Completion Actions (reconciled)

On finalize success, the code performs:

  1. Mark the session Completed (sets CompletedAtUtc).
  2. Delete the session’s secret drafts (secretStore.DeleteSessionAsync).
  3. Write SetupComplete=true to the environment settings store and invalidate the cache, so /platform/envsettings.json reports setup: "complete" and the frontend stops redirecting to the wizard.
  4. Return nextSteps pointing to /setup/integrations and the Secrets/Integrations surfaces (restartRequired: false).

Reconciled / NOT IMPLEMENTED: the finalize path does not run a full Doctor diagnostic, does not generate a Markdown setup report (FinalizeSetupSessionResponse.ReportPath is null), and does not emit a setup.completed timeline event. Completion is signalled by the SetupComplete env-settings flag (SetupStateDetector.SetupCompleteKey). A separate POST /api/v1/setup/quick-check shortcut probes database/cache/migrations/authority and sets the same flag without walking the wizard.