Setup Wizard - Doctor Integration Contract
Audience: developers working on Setup Wizard validation or Doctor checks who need to know which check IDs are live, which are design intent, and how the wizard reuses the shared Doctor remediation primitives. Read the status banner first — the wizard’s inline probes and the Doctor diagnostic engine are two separate surfaces.
This document defines how the Setup Wizard validates each step and provides actionable remediation guidance, drawing on the shared Doctor remediation primitives (runtime detection, placeholder resolution, verification execution).
Status (reconciled against
src/, 2026-05-30). This document mixes the implemented contract with forward-looking design. Two distinct surfaces exist in code and must not be conflated:
- Live setup-wizard probes (Platform).
src/Platform/StellaOps.Platform.WebService(Contracts/SetupWizardModels.cs,Services/PlatformSetupService.cs,Endpoints/SetupEndpoints.cs) runs its own inline probes per step and emitsSetupCheckResultrecords carryingcheck.*-shaped string IDs. These probes do not route through the Doctor plugin engine — the check IDs they emit are wizard-local identifiers, not registered DoctorCheckIds. The live backend bootstrap contract supports only six steps:database,valkey,migrations,admin,crypto,sources(seeProbeStepCoreAsync/ApplyStepCoreAsync). All other steps returncheck.setup.unsupported.- Doctor diagnostic engine (separate).
src/Doctor/**andsrc/__Libraries/StellaOps.Doctor*/**implement a plugin-based diagnostic system with its own (larger, differently-named) catalog ofCheckIds (e.g.check.db.connection,check.postgres.connectivity,check.crypto.fips). The wizard reuses Doctor’s remediation primitives (RemediationCommand,WizardRemediation,LikelyCause,IRuntimeDetector,IPlaceholderResolver,IVerificationExecutor— all underStellaOps.Doctor), but does not currently invoke Doctor checks through a wizard client.Types described below that do not exist in source are flagged NOT IMPLEMENTED (design intent) inline. The canonical UX boundary is setup-wizard-ux.md.
1. Overview
The Setup Wizard aims to:
- Validate each configuration step (live: via Platform inline probes)
- Detect existing configuration (for resume/reconfigure)
- Generate runtime-specific fix commands (via shared Doctor remediation primitives)
- Verify that fixes were applied correctly
2. Step-to-Check Mapping
2.1 Implemented backend bootstrap steps
These are the only steps the live Platform setup contract supports (SetupStepDefinitions.All in Contracts/SetupWizardModels.cs; probes in Services/PlatformSetupService.cs). The “Check ID” column lists the wizard-local check IDs actually emitted as SetupCheckResult.CheckId, not Doctor plugin CheckIds. Step IDs are the SetupStepId enum values rendered in lowercase by the UX/API.
| Step ID | Required | Depends on | Emitted check IDs (wizard-local) |
|---|---|---|---|
database | Yes | — | check.database.connectivity, check.database.version |
valkey | Yes | — | check.services.valkey.connectivity |
migrations | Yes | database | check.database.migrations.module, check.database.migrations.applied |
admin | Yes | migrations | check.auth.admin.exists, check.auth.password.policy, check.authority.admin.exists |
crypto | Yes | admin | check.crypto.profile, check.crypto.fips, check.compliance.nis2.prerequisites, check.compliance.dora.prerequisites, check.compliance.cra.prerequisites |
sources | No | admin | check.sources.feeds.configured, check.sources.feeds.connectivity |
Notes (source-grounded):
SetupCheckStatus(the per-check status emitted by the wizard) isPass | Fail | Warn | NotRun— see §3.1. “Severity”/“blocks progression” are derived from stepIsRequiredand whether any check isFail, not stored per check.- The
databasestep definition’sDoctorChecksarray additionally listscheck.database.permissions, butPlatformSetupService.ProbeDatabaseAsyncdoes not emit a permissions result; treatcheck.database.permissionsas declared-but-not-probed. - The probe surface emits both
check.auth.admin.existsandcheck.authority.admin.exists(the step definition uses thecheck.authority.admin.existsform). cryptocompliance prerequisite checks describe evidence support, not legal certification (see setup-wizard-ux.md §1.3).- The UX-live inventory also includes an optional
assurancestep (read-only preflight, no setup-save contract yet); it is documented in setup-wizard-ux.md and is not part of this backend probe contract.
2.2 Steps NOT in the backend bootstrap contract (design intent)
ProbeStepCoreAsync/ApplyStepCoreAsync reject any step outside §2.1 with check.setup.unsupported. The vault, scm, and registry steps exist only as local CLI client steps (src/Cli/StellaOps.Cli/Commands/Setup/Steps/Implementations/); they do not run server-side and emit no Platform SetupCheckResult. The check IDs below (check.integration.vault.*, check.integration.scm.*, check.integration.registry.*, check.notify.*, check.security.identity.*, check.orchestrator.*, check.feeds.*) are NOT IMPLEMENTED (design intent) — none are emitted by the wizard, and most are not registered as Doctor CheckIds either (see §2.3 for what the Doctor engine actually ships). Per setup-wizard-ux.md, post-bootstrap integration/notification/identity work is handled on the relevant Integrations / Notify / Identity & Access pages, not as wizard steps.
2.3 Relationship to the Doctor diagnostic catalog
The Doctor engine ships its own check IDs that are similarly named but distinct from the wizard-local IDs above. When cross-referencing, note (non-exhaustive, from src/Doctor/** and src/__Libraries/StellaOps.Doctor.Plugins.*/**):
| Wizard-local ID | Nearest Doctor plugin CheckId(s) |
|---|---|
check.database.connectivity | check.db.connection, check.postgres.connectivity |
check.database.version | check.db.schema.version |
check.database.migrations.* | check.db.migrations.pending, check.db.migrations.failed, check.postgres.migrations |
check.services.valkey.connectivity | check.servicegraph.valkey |
check.auth.password.policy | check.users.password.policy, check.security.password.policy |
check.authority.admin.exists | check.authority.bootstrap.exists, check.users.superuser.exists |
check.crypto.fips | check.crypto.fips (Doctor Crypto plugin — exact match) |
check.sources.feeds.configured | check.sources.mode.configured |
There is no check.database.migrations.checksums, check.services.valkey.ping, check.crypto.profile.valid, check.crypto.signing.test, or check.feeds.sync.enabled in either catalog.
3. Check Output Model
3.1 Result schemas
There is no single CheckResult type shared by the wizard and Doctor. Two distinct, source-accurate records apply:
Wizard-local result — what the Platform setup probes emit (Contracts/SetupWizardModels.cs):
public sealed record SetupCheckResult(
string CheckId,
SetupCheckStatus Status,
string? Message,
string? SuggestedFix);
public enum SetupCheckStatus { Pass, Fail, Warn, NotRun }
Doctor diagnostic result — what the Doctor engine produces (StellaOps.Doctor/Models/DoctorCheckResult.cs):
public sealed record DoctorCheckResult
{
public required string CheckId { get; init; }
public required string PluginId { get; init; }
public required string Category { get; init; }
public required DoctorSeverity Severity { get; init; }
public required string Diagnosis { get; init; }
public required Evidence Evidence { get; init; }
public IReadOnlyList<string>? LikelyCauses { get; init; } // string list, not LikelyCause records
public Remediation? Remediation { get; init; } // grouped steps, see §9
public string? VerificationCommand { get; init; }
public required TimeSpan Duration { get; init; }
public required DateTimeOffset ExecutedAt { get; init; }
}
public enum DoctorSeverity { Pass = 0, Info = 1, Warn = 2, Fail = 3, Skip = 4 }
DoctorCheckResult.Evidenceis the strongly-typedEvidencerecord (Description+IReadOnlyDictionary<string,string> Data+ optionalSensitiveKeys), not anImmutableDictionary<string, object>.LikelyCauseson the result is a plainIReadOnlyList<string>; the structuredLikelyCauserecord below is used by the wizard-remediation primitive (WizardRemediation), not byDoctorCheckResult.
Shared remediation primitives (StellaOps.Doctor/Models/, StellaOps.Doctor/Detection/) — these match source closely:
public sealed record LikelyCause
{
public required int Priority { get; init; } // 1 = most likely
public required string Description { get; init; }
public string? DocumentationUrl { get; init; }
}
public sealed record RemediationCommand
{
public required RuntimeEnvironment Runtime { get; init; }
public required string Command { get; init; } // may contain {{PLACEHOLDER}}
public required string Description { get; init; }
public bool RequiresSudo { get; init; }
public bool IsDangerous { get; init; }
public IReadOnlyDictionary<string, string>? Placeholders { get; init; }
public string? DangerWarning { get; init; } // extra warning for dangerous commands
}
// WizardRemediation groups LikelyCauses + Commands + VerificationCommand and exposes
// GetCommandsForRuntime(runtime) (exact match then RuntimeEnvironment.Any fallback).
public enum RuntimeEnvironment
{
DockerCompose,
Kubernetes,
Systemd,
WindowsService,
Bare,
Any
}
3.2 Evidence content
DoctorCheckResult.Evidence.Data is IReadOnlyDictionary<string, string> with a human-readable Description; check authors populate it via the result builder (context.CreateResult(...).WithEvidence("…", e => e.Add(key, value))). The keys are check-specific and not contractually fixed. The table below is illustrative of typical keys, not a guaranteed schema:
| Check Category | Typical evidence keys |
|---|---|
| Database | host, port, version |
| Valkey | host, port |
| Migrations | module/convergence status |
| Auth | Username, Email, AutoBootstrap |
Sensitive values are redacted before storage — checks use DoctorPluginContext.Redact(...) and may list redacted keys in Evidence.SensitiveKeys.
4. Remediation Command Generation
4.1 Runtime Detection
Runtime detection is provided by StellaOps.Doctor.Detection.IRuntimeDetector (default impl RuntimeDetector):
public interface IRuntimeDetector
{
RuntimeEnvironment Detect();
bool IsDockerAvailable();
bool IsKubernetesContext();
bool IsSystemdManaged(string serviceName);
string? GetComposeProjectPath(); // nullable
string? GetKubernetesNamespace(); // nullable; defaults to "stellaops"
IReadOnlyDictionary<string, string> GetContextValues(); // placeholder source (§5.1 priority 3)
}
Detection logic (RuntimeDetector.DetectInternal):
- Check for
/.dockerenvfile →DockerCompose - Check
KUBERNETES_SERVICE_HOSTenv var →Kubernetes IsDockerAvailable()AND a compose file is found →DockerCompose- On non-Windows,
systemctl --versionexits 0 →Systemd - On Windows, Windows-Service heuristics →
WindowsService - Default →
Bare
4.2 Command Templates
The YAML below is illustrative design intent, not a shipped configuration format. The live wizard probes (
PlatformSetupService) return a singleSuggestedFixstring perSetupCheckResult; the richerWizardRemediation/RemediationCommandmodel is populated by Doctor checks (see the per-checkWithRemediation(...)builders undersrc/Doctor/**andsrc/__Libraries/StellaOps.Doctor.Plugins.*/**). Treat the check IDs in these examples as logical labels —check.services.valkey.connectivityis wizard-local,check.integration.vault.authis not implemented (see §2.2).
Database Connection Failure
check.database.connectivity:
likelyCauses:
- priority: 1
description: "PostgreSQL is not running"
- priority: 2
description: "Firewall blocking port 5432"
- priority: 3
description: "Incorrect host or port"
- priority: 4
description: "Network connectivity issue"
remediations:
- runtime: DockerCompose
description: "Start PostgreSQL container"
command: "docker compose -f {{COMPOSE_FILE}} up -d postgres"
placeholders:
COMPOSE_FILE: "devops/compose/docker-compose.yml"
- runtime: Kubernetes
description: "Check PostgreSQL pod status"
command: "kubectl get pods -n {{NAMESPACE}} -l app=postgres"
placeholders:
NAMESPACE: "stellaops"
- runtime: Systemd
description: "Start PostgreSQL service"
command: "sudo systemctl start postgresql"
requiresSudo: true
- runtime: Any
description: "Verify PostgreSQL is listening"
command: "pg_isready -h {{HOST}} -p {{PORT}}"
placeholders:
HOST: "localhost"
PORT: "5432"
verificationCommand: "pg_isready -h {{HOST}} -p {{PORT}}"
Valkey Connection Failure
check.services.valkey.connectivity:
likelyCauses:
- priority: 1
description: "Valkey/Redis is not running"
- priority: 2
description: "Firewall blocking port 6379"
- priority: 3
description: "Authentication required but not configured"
remediations:
- runtime: DockerCompose
description: "Start Valkey container"
command: "docker compose -f {{COMPOSE_FILE}} up -d valkey"
placeholders:
COMPOSE_FILE: "devops/compose/docker-compose.yml"
- runtime: Kubernetes
description: "Check Valkey pod status"
command: "kubectl get pods -n {{NAMESPACE}} -l app=valkey"
placeholders:
NAMESPACE: "stellaops"
- runtime: Systemd
description: "Start Valkey service"
command: "sudo systemctl start valkey"
requiresSudo: true
- runtime: Any
description: "Test Valkey connection"
command: "valkey-cli -h {{HOST}} -p {{PORT}} PING"
placeholders:
HOST: "localhost"
PORT: "6379"
verificationCommand: "valkey-cli -h {{HOST}} -p {{PORT}} PING"
Pending Migrations
check.database.migrations.applied:
likelyCauses:
- priority: 1
description: "Pending release migrations require manual execution"
- priority: 2
description: "Startup migrations not yet applied"
remediations:
- runtime: Any
description: "Run pending migrations (dry-run first)"
command: "stella system migrations-run --module all --dry-run"
- runtime: Any
description: "Apply all pending migrations (release migrations require --force)"
command: "stella system migrations-run --module all --force"
isDangerous: true
- runtime: DockerCompose
description: "Run migrations in container"
command: "docker compose exec api stella system migrations-run --module all --force"
- runtime: Kubernetes
description: "Run migrations job"
command: "kubectl apply -f devops/k8s/jobs/migrations.yaml"
verificationCommand: "stella system migrations-run --module all --dry-run"
Vault Authentication Failure
check.integration.vault.auth:
likelyCauses:
- priority: 1
description: "Vault token expired or revoked"
- priority: 2
description: "AppRole credentials invalid"
- priority: 3
description: "Kubernetes service account not configured"
- priority: 4
description: "Vault server unreachable"
remediations:
- runtime: Any
description: "Test Vault connectivity"
command: "curl -s {{VAULT_ADDR}}/v1/sys/health"
placeholders:
VAULT_ADDR: "https://vault.example.com:8200"
- runtime: Any
description: "Verify token validity"
command: "vault token lookup"
- runtime: Kubernetes
description: "Check Kubernetes auth configuration"
command: "kubectl get serviceaccount -n {{NAMESPACE}} stellaops-vault-auth"
placeholders:
NAMESPACE: "stellaops"
verificationCommand: "vault token lookup"
5. Placeholder Resolution
5.1 Placeholder Sources
Placeholders in commands are resolved from:
| Source | Priority | Example |
|---|---|---|
| User input | 1 (highest) | {{HOST}} from form field |
| Environment | 2 | {{VAULT_ADDR}} from env |
| Detection | 3 | {{NAMESPACE}} from context |
| Default | 4 (lowest) | Fallback value |
5.2 Placeholder Syntax
{{PLACEHOLDER_NAME}}
{{PLACEHOLDER_NAME:-default_value}}
Examples:
{{HOST}}- Required placeholder{{PORT:-5432}}- Optional with default{{COMPOSE_FILE:-docker-compose.yml}}- File path default
5.3 Secret Redaction
PlaceholderResolver.Resolve(...) never substitutes sensitive placeholders — they are left in {{NAME}} form regardless of any available value, so the user must copy and manually fill them in. A placeholder is treated as sensitive (IsSensitivePlaceholder) when its name is in the built-in set or contains a sensitive keyword:
- Built-in names (case-insensitive):
PASSWORD,TOKEN,SECRET,SECRET_KEY,SECRET_ID,API_KEY,APIKEY,PRIVATE_KEY,CREDENTIALS,AUTH_TOKEN,ACCESS_TOKEN,REFRESH_TOKEN,CLIENT_SECRET,DB_PASSWORD,REDIS_PASSWORD,VALKEY_PASSWORD,VAULT_TOKEN,ROLE_ID. - Keyword match: name contains
PASSWORD,SECRET,TOKEN, or (KEYplusAPI/PRIVATE).
| Placeholder | Display | Actual |
|---|---|---|
{{PASSWORD}} | {{PASSWORD}} | Never substituted |
{{TOKEN}} | {{TOKEN}} | Never substituted |
{{SECRET_KEY}} | {{SECRET_KEY}} | Never substituted |
{{ROLE_ID}} | {{ROLE_ID}} | Never substituted |
6. Verification Flow
6.1 Post-Fix Verification
After the user applies a fix, the wizard:
- Wait - Pause for user confirmation (“I’ve run this command”)
- Verify - Run the verification command
- Re-check - Run the original Doctor check
- Report - Show success or next steps
6.2 Verification Command Execution
StellaOps.Doctor.Resolver.IVerificationExecutor (default impl VerificationExecutor):
namespace StellaOps.Doctor.Resolver;
public interface IVerificationExecutor
{
Task<VerificationResult> ExecuteAsync(
string command,
TimeSpan timeout,
CancellationToken ct = default);
Task<VerificationResult> ExecuteWithPlaceholdersAsync(
string command,
IReadOnlyDictionary<string, string>? userValues,
TimeSpan timeout,
CancellationToken ct = default);
}
public sealed record VerificationResult
{
public required bool Success { get; init; }
public required int ExitCode { get; init; }
public required string Output { get; init; } // combined stdout + stderr
public required TimeSpan Duration { get; init; }
public bool TimedOut { get; init; }
public string? Error { get; init; } // set when the command failed to start
}
6.3 Re-Check Behavior
[FAIL] check.database.connectivity
Suggested fix applied. Verifying...
[RUN] pg_isready -h localhost -p 5432
localhost:5432 - accepting connections
Re-running check...
[PASS] check.database.connectivity
PostgreSQL connection successful
7. Check Aggregation
7.1 Step Completion Criteria
A step is complete when:
- All Critical checks pass
- No Fail status on any check
- User has acknowledged all Warning checks
7.2 Aggregated Status
There is no StepValidationStatus type in source. The implemented status enums (Contracts/SetupWizardModels.cs) are:
// Per-step status within a session
public enum SetupStepStatus { Pending, Current, Passed, Failed, Skipped, Blocked }
// Overall session status
public enum SetupSessionStatus
{
NotStarted, InProgress, Completed, CompletedPartial, Failed, Abandoned
}
SetupStepStatus.Blocked is set when a step’s dependency failed; there is no distinct “PassedWithWarns” — a step with only Warn checks (no Fail) still resolves to Passed.
7.3 Status Rollup for Thresholds
Illustrative only. The “Production-Ready” threshold and its check IDs (
check.security.identity.configured,check.integration.vault.connected,check.integration.scm.connected,check.orchestrator.agent.healthy,check.feeds.sync.enabled) are NOT IMPLEMENTED — they are not emitted by the wizard and the corresponding optional steps are not in the backend bootstrap contract (§2.2). The “Operational” set maps to the six implemented required-step probes (§2.1).
Operational Threshold:
[x] check.database.connectivity PASS
[x] check.database.permissions PASS
[x] check.database.migrations.applied PASS
[x] check.services.valkey.connectivity PASS
[x] check.auth.admin.exists PASS
[x] check.crypto.profile.valid PASS
Status: OPERATIONAL (6/6 required checks passed)
Production-Ready Threshold:
[x] check.security.identity.configured PASS
[x] check.integration.vault.connected PASS
[x] check.integration.scm.connected PASS
[x] check.notify.channel.configured PASS
[ ] check.orchestrator.agent.healthy SKIP
[ ] check.feeds.sync.enabled SKIP
Status: NOT PRODUCTION-READY (4/6 recommended, 2 skipped)
8. Doctor Engine Integration
NOT IMPLEMENTED (design intent).
WizardCheckContextandIWizardDoctorClientdo not exist in source — there is no wizard→Doctor-engine client. In the live system the wizard runs inline probes inPlatformSetupService(ProbeStepCoreAsync/ApplyStepCoreAsync), driven byEndpoints/SetupEndpoints.cs. The Doctor engine (StellaOps.Doctor.Engine.DoctorEngine,CheckExecutor,CheckRegistry) is invoked separately (e.g.stella doctor run, the Doctor WebService) and is not part of the setup probe path. The records below sketch a possible future integration.
8.1 Wizard-Specific Check Context (design intent)
// NOT IMPLEMENTED — illustrative
public sealed record WizardCheckContext
{
public required string StepId { get; init; }
public required RuntimeEnvironment DetectedRuntime { get; init; }
public required ImmutableDictionary<string, string> UserInputs { get; init; }
public bool GenerateRemediations { get; init; } = true;
public bool IncludePlaceholders { get; init; } = true;
}
The implemented context object passed to Doctor checks is StellaOps.Doctor.Plugins.DoctorPluginContext (services, configuration, time provider, logger, environment name, optional tenant, plugin config) — not a wizard-specific type.
8.2 Check Invocation (design intent)
// NOT IMPLEMENTED — illustrative
public interface IWizardDoctorClient
{
Task<ImmutableArray<CheckResult>> RunStepChecksAsync(string stepId, WizardCheckContext context, CancellationToken ct);
Task<CheckResult> RunSingleCheckAsync(string checkId, WizardCheckContext context, CancellationToken ct);
Task<VerificationResult> RunVerificationAsync(string command, WizardCheckContext context, CancellationToken ct);
}
Implemented entry points instead:
- Setup probe/apply:
POST /api/v1/setup/sessions/{id}/steps/{step}/probeand.../apply(seeSetupEndpoints.cs), executed byPlatformSetupService. - Doctor checks:
IDoctorCheck.RunAsync(DoctorPluginContext, CancellationToken)executed byDoctorEngine/CheckExecutor.
8.3 Check Timeout
| Check Category | Default Timeout | Max Timeout |
|---|---|---|
| Connectivity | 10 seconds | 30 seconds |
| Authentication | 15 seconds | 60 seconds |
| Migrations | 60 seconds | 300 seconds |
| Full validation | 30 seconds | 120 seconds |
9. Remediation Safety
9.1 Dangerous Commands
Commands marked isDangerous: true require user confirmation:
WARNING: This command will modify your database schema.
Command:
stella system migrations-run --module all --force
This action:
- Applies 5 pending migrations
- Cannot be automatically rolled back
- May take several minutes
Type 'apply' to confirm: _
9.2 Sudo Requirements
Commands requiring sudo show a notice:
This command requires administrator privileges.
Command:
sudo systemctl start postgresql
[Copy Command]
Note: You may be prompted for your password.
9.3 Secret Substitution Notice
This command contains placeholders for sensitive values.
Command:
vault write auth/approle/login role_id={{ROLE_ID}} secret_id={{SECRET_ID}}
Before running:
1. Replace {{ROLE_ID}} with your AppRole Role ID
2. Replace {{SECRET_ID}} with your AppRole Secret ID
[Copy Command]
10. Check Plugin Requirements
10.1 Related Doctor checks (status)
The original design called for several new Doctor checks. Current status against src/__Libraries/StellaOps.Doctor.Plugins.*/**:
| Plugin (real) | Check ID (real) | Purpose | Status |
|---|---|---|---|
| Authority | check.users.password.policy | Password complexity | Implemented |
| Authority | check.authority.bootstrap.exists, check.users.superuser.exists | Admin/bootstrap user exists | Implemented |
| Notify | check.notify.delivery.test | Test notification delivery | Implemented |
| Database | check.db.migrations.failed | Failed-migration detection | Implemented |
| — | check.crypto.signing.test | Test signing operation | Not implemented (closest: check.auth.signing-key, check.compliance.attestation-signing) |
| Database | check.database.migrations.checksums | Migration checksum integrity | Not implemented |
| Integration | check.integration.vault.secrets.access | Secret retrieval test | Not implemented (closest: check.integration.secrets.manager) |
10.2 Check Implementation Contract
ISetupWizardAwareCheck does not exist in source. Doctor checks implement StellaOps.Doctor.Plugins.IDoctorCheck:
public interface IDoctorCheck
{
string CheckId { get; }
string Name { get; }
string Description { get; }
DoctorSeverity DefaultSeverity { get; }
IReadOnlyList<string> Tags { get; }
TimeSpan EstimatedDuration { get; }
bool CanRun(DoctorPluginContext context);
Task<DoctorCheckResult> RunAsync(DoctorPluginContext context, CancellationToken ct);
}
Remediations and verification commands are not separate interface methods; checks attach them to the result via the builder (context.CreateResult(...).WithRemediation(r => r .AddStep(...).WithRunbookUrl(...)).WithVerification("stella doctor --check <id>")). The runtime-specific RemediationCommand / WizardRemediation primitives (§3.1, §4) are used where a check chooses to emit runtime-targeted commands.
11. Audit Trail
11.1 Setup Event Logging
Wizard endpoints are audited through the generic audit-emission framework (StellaOps.Audit.Emission), not via a bespoke SetupWizardEvent record or a direct Timeline write. In Endpoints/SetupEndpoints.cs each mutating endpoint chains .Audited(AuditModules.Platform, AuditActions.Platform.<action>, "setup"). There is no SetupWizardEvent type in source (the schema previously shown here is NOT IMPLEMENTED), and there is no per-check (check.passed/check.failed) or remediation.copied audit event in the live backend.
11.2 Audited actions (real)
The actual audited actions emitted by the setup endpoints (AuditActions.Platform.*):
| Audit action | Triggering endpoint |
|---|---|
CreateSetupSession | Create / start a setup session |
ExecuteSetupStep | Probe / apply / reset a step |
SkipSetupStep | Skip an optional step |
FinalizeSetup | Finalize / complete the session |
11.3 Doctor authorization scopes (reference)
The Doctor diagnostic surface (separate from the wizard) is gated by these scopes (StellaOpsScopes.cs, mirrored in DoctorScopes.cs): doctor:run, doctor:run:full, doctor:export, doctor:admin; the Doctor scheduler adds doctor-scheduler:read and doctor-scheduler:write. The first-run setup wizard itself is anonymous until the installation is bootstrapped, after which /setup-wizard/* continues as an authenticated reconfiguration session (see setup-wizard-ux.md §1.3).
Related Documents
- setup-wizard-capabilities.md — functional capability spec and the six-step bootstrap contract.
- setup-wizard-ux.md — the canonical UX boundary for the CLI and Console wizard.
- setup-wizard-inventory.md — orientation map of the setup-related source under
src/.
