# Sibyla deployment tooling — Slice 1 V3 closed specification

Revision 9 (2026-09-02; the re-review ACCEPTED revision 8 with Critical 0, High 0, Medium 0, Low 1
residual; the owner asked for that residual to be applied too, tagged `[L-8]`, and re-reviewed).
Revision 8 followed the final independent review, which ACCEPTED revision 7 with Critical 0, High 0,
Medium 0, Low 7 (the owner asked for the seven Low findings to be applied, tagged `[L-n]`, and re-reviewed).
Revision 7 followed sub-slices F, G and H (the checkpoint-2 re-review accepted revision 6 with
Critical 0, High 0, Medium 0, Low 0). Revision 6 followed checkpoint 2 (rejected on process with Critical 0,
High 0, Medium 2, Low 7, every finding resolved and referenced as `[C2-n]`). Revision 1 was rejected by independent review (Critical 0, High 4,
Medium 10, Low 5); every finding is resolved and referenced as `[R1-n]`. Revision 2 was accepted
with changes (Critical 0, High 1, Medium 3, Low 4); those are resolved and referenced as `[R2-Nn]`.
Revision 5 (after checkpoint 1, which rejected on process with Critical 0, High 1, Medium 2, Low 6)
carries the implementer amendments `[R3-A1]`, `[R3-A2]` and the checkpoint-1 resolutions `[C1-n]`.
Section 7.1 was written after the sub-slice B handlers and is therefore NOT the oracle source: the
registry oracle is re-typed by an independent author from V2 §5 and the section 7 table only
(`[C1-1]`), and the code adapts to that oracle in sub-slice C.

Status: proposed for independent review before any Slice 1 V3 code is written.
Supersedes, for Slice 1 only, the ambiguities listed in section 1 of the V2 closed contract
(`subagent-summary-0-20260901_184628_084351.txt`) and of the V3 handoff
(`sibyla-slice1-review-finish-handoff.md`). Everything not restated here keeps the V2 wording.

## 0. Decisions already taken by the owner (2026-09-01)

| Decision | Value |
|---|---|
| Git base | `06d27f40e283f7df5dff6897c02de3e848dd8147` (current `main`), not `dee1efe`. Reason: `main` is 10 commits ahead and changed `src/Sibyla.Web/Program.cs`; basing on `dee1efe` guarantees a merge conflict. |
| Branch / worktree | `ops/apollo-deployment-slice1-v3` / `D:\fileStorage\repos\GOTT.Apollo-worktrees\apollo-deployment-slice1-v3` |
| Code author | Claude Code writes the code directly (no Codex; not available in this environment). |
| Independent review cadence | Three checkpoints: after sub-slices A+B, after C+D+E, final after F+G+H. |
| Spec first | The owner accepted that this specification is reviewed before sub-slice A, and that the spike gate items not provable without the real design are carried into sub-slices A–E (see Spike row). |
| Language / packaging | C# binary PowerShell module, `net48`, built with the .NET SDK 10 on the host, fully offline. |
| Spike `[R1-12]` | Disposable spike at `C:\Users\ADMINI~1\AppData\Local\Temp\2\claude\D--fileStorage-repos-GOTT-Sibyla\506611ae-dc1f-4aff-b19a-fa4684ea163c\scratchpad\spike-net48` (outside every governed candidate). Results below. |

Spike gate results in `powershell.exe` 5.1.26100 (2026-09-01):

| # | Gate item | Result |
|---|---|---|
| 1 | binary module imports | PASS (`Import-Module Spike.dll`) |
| 2 | exports exactly the declared cmdlets | PASS for one cmdlet; six-cmdlet exactness carried into A |
| 3 | returns a sealed, immutable, version-1 CLR contract | PASS (`IsSealed = True`, get-only, `ContractVersion = 1`) |
| 4 | compares types by exact CLR identity | carried into A (needs the identity gate code) |
| 5 | default provider traverses provider → executor → PlanOnly invoker | carried into B |
| 6 | orchestrator uses the real phase commands | carried into B |
| 7 | same instances carried by `ReferenceEquals` | carried into B |
| 8 | operation-specific handler produces a typed intent | carried into C |
| 9 | `ValueRef<T>` represents future outputs without `null`/`Guid.Empty` | PASS (constructor rejects `Guid.Empty`); lineage carried into D |
| 10 | PlanOnly never declares Held, Committed or Released | carried into E (names do not exist, section 1.1) |
| 11 | no file/IIS/SCM/TLS/process/HTTP/database/network mutation | PASS for the spike; byte-level reference scan carried into E |

Toolchain found: .NET SDK 10.0.301; no .NET Framework Developer Pack, no `net48` reference
assemblies, no PowerShell NuGet packages, no `pwsh`; `System.Management.Automation` 3.0.0.0 in
the GAC; `csc.exe` 4.0.30319 (C# 5) as the only in-box compiler. Nothing was installed; no network
call was made. Failure mode for option B (`Add-Type`) would have been C# 5 only; not needed.

Consequence of the base decision: four of the five preserved C# paths are byte-equal to the approved
V2 source (hashes in section 9). `src/Sibyla.Web/Program.cs` cannot be byte-equal because `main`
changed it; the approved 8-line hunk was applied verbatim at the same anchor. The reviewer verifies
the hunk, not the file hash.

## 1. Contradictions in the inherited contracts, and how V3 resolves them

1. **Lease state machine.** V2 §7 defines `Held → … → Committed → Released` and "mark committed after
   completion". V2 was rejected (HIGH 3) for implementing exactly that in PlanOnly. **V3 rule:** the
   Slice 1 assemblies contain no type, enum member, field, property or method named `Held`,
   `LeaseEstablished`, `Committed`, `Released`, `RollingBack`, `RolledBack`, `ReleaseFailed`,
   `RollbackAvailable`, `Verified`, `Succeeded`, `Active`, `Completed`, `Complete`. The only state
   machine is `Created → Validated → Compiled → Planned`. Enforced by reflection over the built
   assemblies plus the byte-level reference scan (sub-slice E, section 9). Forbidden names are
   matched exactly (ordinal, whole member name) `[R2-N6]`; the V2 nullable evidence fields
   `HeadMatched`, `CleanBefore`, `CleanAfter`, `OriginalWorkloadStateId`, `ScmStartNamePreserved`,
   `AllDeclaredChecksPassed`, `StatusCode`, `WebReleaseVerified`, `WorkerReleaseVerified` remain and
   are always `null` in Slice 1.
2. **Sanitization at execution boundaries.** The handoff asks for injection at rollback, rollback
   readback, release and aggregate boundaries. Those execution boundaries do not exist without
   execution. **V3 rule:** one sanitizer type, `DeploymentFailure`, is the only way an error leaves
   Slice 1 code, at every boundary that exists in Slice 1 (section 8). Execution-time boundaries are
   Slice 2 scope and are listed as such in section 8. The aggregate boundary that does exist in
   Slice 1 is public-input validation (section 8) `[R1-8]`.
3. **"Rollback readback verifies the rollback receipt".** In a plan this is a lineage property.
   **V3 rule:** every compensation readback request carries a `ValueRef<RollbackReceipt>` pointing at
   the intent id of its own compensation intent, never at the forward `MutationReceipt`. Tested by
   deep lineage comparison (sub-slice D). One exception, adjudication D4 `[C2-4]`: the compensation
   of `Process.Start` is a `Process.Stop`, whose result is a `MutationReceipt`, so that one
   compensation readback references the stop's `MutationReceipt` through its receipt set.
4. **`WorkerServiceName`.** V2: "optional, default `GottSibylaWorker`, bounded safe SCM name".
   Handoff: "service name different from `GottSibylaWorker`" must be rejected. **V3 rule:** the
   parameter stays for API parity; `SafeScmName` accepts only the exact ordinal value
   `GottSibylaWorker` (case variants rejected) in Slice 1. Forwarding is proven negatively
   (section 9, A) `[R1-9]`.
5. **Contract-typed parameters** `[R1-5]`. Cmdlet parameters that carry a contract are declared
   `object`. The cmdlet unwraps `PSObject.BaseObject`, rejects any wrapper carrying an adapted member
   (`NoteProperty`, `ScriptProperty`, `AliasProperty`, `CodeProperty`) with
   `SIBYLA-S1-CONTRACT-IDENTITY`, then applies the section 4 identity and version checks. The
   PowerShell binder therefore never produces an unsanitized `ParameterBindingException` for a
   lookalike. The `.ps1` entrypoints also declare those parameters as `[object]`.
6. **Non-WhatIf calls and WhatIf mechanics** `[R1-15]`. Kept from V2: every public cmdlet called
   without `-WhatIf` throws `SIBYLA-S1-EXECUTION-DEFERRED` before touching provider, executor or
   invoker. WhatIf is detected from `MyInvocation.BoundParameters["WhatIf"]`; when present, the cmdlet
   runs planning and `WriteObject(result, enumerateCollection: false)` without gating on
   `ShouldProcess`. Each `.ps1` carries `[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]`
   so `-WhatIf` is a valid script parameter and is forwarded as `-WhatIf:$WhatIfPreference`.
7. **First accepted v1 field shape** `[R1-1]`. Slice 1 defines wire version 1 for the first time;
   V2 §3's "removing a field requires a version increment" does not apply to fields that never
   shipped. The V2 §3 fields dropped or narrowed for v1 are, per contract:
   - every result: `Outcome` is an enum with the single member `Planned`; `Verified` is removed;
   - `PublishedArtifact`: unchanged (`Replayed` and the manifest fields stay nullable evidence);
   - `InstallRollbackHandle`, `ConfigureRollbackHandle`: `HandleState` is an enum with the single
     member `Planned`; `RollbackAvailable` is removed;
   - `HealthResult`: `HealthCheckEvidence.Status` is an enum with the single member `Planned`;
   - `DeploymentResult`: `LeaseState` and `Completed` are removed;
   - `NativeInvocationResult`: `Disposition` is an enum with the single member `Planned`;
     `ActualResult` and `ExitCode` do not exist.
   Later slices may add members by incrementing the contract version.
8. **Test seam** `[R1-6]`. Deviation from V2 "tests may replace only the lower command invoker",
   required by the handoff's sentinel probes: tests may substitute the phases, the provider and the
   handler table only with throwing sentinels or corrupted tables that must make the call fail (no
   test passes a positive assertion through a substituted phase, provider or table); only the
   invoker may be substituted with a working double (a recording invoker). The default
   `DeploymentRuntime.Current` is built from the concrete production types with no environment
   variable, file, registry or configuration lookup. The hook is `internal`, resettable, and every
   test using it runs in one serialized xUnit collection that resets it in `Dispose`.
9. **UNC and special prefixes** `[R1-18]`. Slice 1 rejects every `\\server\share`, `\\?\` and
   `\\.\` prefix by decision. `WebSecretsPath` and `WorkerSecretsPath` use `AbsoluteWindowsPath`
   plus the rule "leaf is a file name, not a drive or directory root"; planning never opens the file.
10. **Phase allocation of the 29 operations** `[R1-2]`. V2 gives one canonical lifecycle for the
    whole deployment and does not say which phase plans which operation. Section 7 fixes the
    allocation. V2's single-transaction interleaving is superseded: order is phase-wise (within a
    phase: snapshots, mutations, readbacks) and the section 7 table is the sole order oracle
    `[R2-N1]`. `FileSystem.GetSnapshot` is issued per root (Gate, Publish, Install) instead of V2's
    one all-roots snapshot.

## 2. Layout (all new files; nothing copied from rejected candidates)

```text
.gitignore                                   + local/deploy/Sibyla.Deployment/*.dll|*.pdb|*.deps.json|*.xml  [R1-13]
local/deploy/
  Invoke-SibylaReleaseGate.ps1          six thin entrypoints (unchanged names)
  Publish-SibylaProduction.ps1
  Install-SibylaProduction.ps1
  Configure-SibylaProduction.ps1
  Test-SibylaProduction.ps1
  Invoke-SibylaDeployment.ps1
  Sibyla.Deployment/Sibyla.Deployment.psd1   RootModule = Sibyla.Deployment.Cmdlets.dll, RequiredAssemblies = Core
  Sibyla.Deployment/*.dll                    build output, git-ignored (see above)
  build.ps1                                   dotnet build + copy into the module folder
  Sibyla.Deployment.slnx                      separate solution; Sibyla.slnx is untouched
  Directory.Build.props                       imports the root props, overrides TFM/usings/LangVersion
  src/Sibyla.Deployment.Core/                 net48;net10.0 — no PowerShell dependency
  src/Sibyla.Deployment.Cmdlets/              net48 — six PSCmdlet classes, references GAC SMA
  tests/Sibyla.Deployment.Tests/              net10.0 xUnit; spawns powershell.exe 5.1 for the net48 bytes
  tests/Sibyla.Deployment.Tests/oracles/      hand-written JSON oracles (registry, lineage, validators, sanitizer)
  tests/Sibyla.Deployment.Tests/probes/*.ps1  scripts run inside powershell.exe 5.1, emit JSON
  tests/Sibyla.Deployment.Tests/evidence/     <sub-slice>-red.txt / -green.txt, listed in the inventory
```

Language pinning `[R1-17]`: `LangVersion` is `13.0` for every project and both TFMs. Core and
Cmdlets do not use `init`, records, `required`, default interface members, static abstract
members, or `#if`; properties are get-only and constructor-initialized. Enforced by a source-grep test.

Offline build settings for the `net48` targets (proven on this host on 2026-09-01):
`FrameworkPathOverride = C:\Windows\Microsoft.NET\Framework64\v4.0.30319`,
`AutomaticallyUseReferenceAssemblyPackages = false`, `System.Management.Automation` referenced by
HintPath from the GAC (`v4.0_3.0.0.0__31bf3856ad364e35`). No package is installed; no network call.

### 2.1 Two runners and what each must prove `[R1-4]`

The host has no `System.Reflection.Metadata` package cached, so xUnit cannot restore for `net48`
offline. Logic tests run on the `net10.0` build of Core; the `net48` bytes are proven as follows.

**(a) Inside `powershell.exe` 5.1, on the exact bytes in `local/deploy/Sibyla.Deployment/`
(never `bin/`)**, by probe scripts driven from xUnit:
- import; `CmdletsToExport` exactly the six names; `FunctionsToExport`/`AliasesToExport`/`VariablesToExport` empty;
- parameter-name parity between each `.ps1` and its cmdlet, from `Get-Command` metadata;
- the six entrypoints in fresh processes with unique sentinels, asserted from the returned `Request`;
- `[object]::ReferenceEquals` on every handoff and on the five nested `DeploymentResult` members;
- sealed, no parameterless constructor, no settable property, `ContractVersion = 1`, by reflection
  on the loaded types;
- zero `NoteProperty`/`ScriptProperty`/`AliasProperty`/`CodeProperty` on every returned object
  (`Get-Member -View Extended`) `[R2-N5]`;
- `PSCustomObject` lookalike, same-simple-name foreign type (compiled with `Add-Type` in the probe),
  foreign versions 0 and 2, and non-WhatIf rejection through the entrypoints;
- the validator matrix (`oracles/validators.json`) through the entrypoints;
- the sanitizer matrix for the input, contract and deferred boundaries over the serialized
  `ErrorRecord` (`$_ | Format-List * -Force | Out-String` and `$_.Exception | Format-List * -Force | Out-String`)
  minus the caller-owned `InvocationInfo` and `ScriptStackTrace` fields, plus a second assertion
  that markers appear nowhere except inside those two fields `[R2-N3]`;
- the assembly-reference and forbidden-type scan of section 9 E on the loaded DLL bytes;
- the net48 member set of Core (types, members, accessibility), compared by xUnit with the
  net10.0 reflection set (must be identical);
- every probe emits `$PSVersionTable.PSVersion`, `[Environment]::Is64BitProcess` and the SHA-256 of
  each loaded module DLL; xUnit asserts version 5.1 and hash equality with the module folder.

**(b) In xUnit on `net10.0`**: sentinel and recording call-graph tests, handler and intent tests,
lineage tests, capability matrix, validator matrix, sanitizer matrix.

**(c) Transferability rule**: Core and Cmdlets contain no `#if`, no TFM-conditional `Compile`,
`Reference` or `PackageReference` items, and identical `LangVersion` on both TFMs (source-grep test).

## 3. Public surface (exact)

Six cmdlets, names and parameter sets exactly as V2 §2, all `SupportsShouldProcess = true`,
`ConfirmImpact = High`. `CmdletsToExport` lists exactly these six; `FunctionsToExport`,
`AliasesToExport`, `VariablesToExport` are empty arrays. No public parameter named `Provider`,
`CommandExecutor`, `CommandInvoker`, `Release`, `ExpectedManifestSha256`, `ManifestSha256`.

Each `.ps1`: `[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]`, own nonempty
`param()` block mirroring the cmdlet's business parameters (`[object]` for contracts, `[string]`
otherwise, `HttpsPort` included `[F-1]`), one `Import-Module` of
`$PSScriptRoot\Sibyla.Deployment\Sibyla.Deployment.psd1` with `-DisableNameChecking` (the
`Configure` verb is unapproved and the warning must not reach the operator `[C2-9]`), one call
`Sibyla.Deployment\<Verb-Noun> @forwarded -WhatIf:$WhatIfPreference`, no dot-source, no logic.
No `[Validate*]` attribute on any parameter at either boundary; `Mandatory` is the only binder-side
attribute. Every business parameter is `[string]` at both boundaries, `CertificateStore` and
`HttpsPort` included `[F-1]`: a `[uint16]` port would let the PowerShell type converter reject
`abc`, `-1` or `65536` with a message that echoes the value, so the value objects, not the binder,
reject everything `[R1-10]` `[R2-N4]`.

## 4. Contracts (`Sibyla.Deployment.Core.Contracts.V1`)

Sealed classes with constructor-only initialization, get-only properties, no parameterless
constructor, no settable property. Fields as V2 §3 with the section 1.7 shape. Every contract has
`ContractName` (must equal the CLR type name), `ContractVersion` (constructor parameter, must equal
`1` or the constructor throws `SIBYLA-S1-CONTRACT-VERSION`), `OperationId` (Guid), `Outcome`
(`Planned`), `Request` (immutable bound-input receipt), `OperationResults`, and `Plan` `[R1-2]`
(the `DeploymentPlan` of that phase, so downstream `ValueRef<T>` can be checked against the intents
actually received).

Identity rule: a consumer accepts a contract instance only if `instance.GetType() == typeof(T)` for
the exact Core assembly type (checked first), `ContractName` equals the type name and
`ContractVersion == 1`. Foreign types with the same simple name, `PSCustomObject` lookalikes, and any
other version fail with `SIBYLA-S1-CONTRACT-IDENTITY` / `SIBYLA-S1-CONTRACT-VERSION`. Version
rejection is tested with one foreign assembly (compiled in the test project, and with `Add-Type` in
probes) that declares lookalike types with versions 0 and 2 `[R1-16]`. No code adds `NoteProperty`
members to any contract.

Cross-instance lineage on direct calls `[R1-11]`: `Configure-SibylaProduction` requires
`ReferenceEquals(InstallRollbackHandle.PublishedArtifact, PublishedArtifact)`;
`Test-SibylaProduction` requires the same and `ReferenceEquals(ConfigureRollbackHandle.InstallRollbackHandle, InstallRollbackHandle)`.
Violations throw `SIBYLA-S1-CONTRACT-LINEAGE` `[R2-N7]`.

## 5. Planning pipeline (the only call graph)

```text
.ps1 → Sibyla.Deployment\<cmdlet>
     → DeploymentRuntime.Current.Phases.<Phase>(typedRequest)      (IDeploymentPhases)
     → SibylaProductionHostProvider.Plan<Phase>(...)                (provider)
     → CapabilityPreflight.Check(table, invoker)                    (pure, before compilation)
     → SibylaProductionCommandExecutor                              (executor, owns the handler table)
     → DeploymentPlanCompiler (pure)                                (compiles the phase plan)
     → ISibylaCommandInvoker = SibylaPlanOnlyCommandInvoker         (ValidateIntent, InvokeIntent)
     → typed Planned result built by the provider, returned by reference
```

- `Invoke-SibylaDeployment` calls `DeploymentOrchestrator.Run`, which calls the five
  `IDeploymentPhases` methods in order and passes the returned instances forward.
  `DeploymentResult` holds those exact instances (`ReferenceEquals`). The orchestrator rejects a
  phase that returns null or an instance not built from the instances it passed in with
  `SIBYLA-S1-ORCHESTRATION-HANDOFF` `[G-2]`.
- No cmdlet, orchestrator or phase constructs a `ReleaseGateResult`, `PublishedArtifact`,
  `InstallRollbackHandle`, `ConfigureRollbackHandle`, `HealthResult` or `NativeInvocationResult`.
  Only the provider builds phase results; only the invoker builds `NativeInvocationResult`.
- `OperationResults` of a phase result contains exactly, in plan order, the
  `NativeInvocationResult` instances returned by `InvokeIntent` for every `PlannedOperation` of that
  phase (forward and compensation entries alike); the count equals the plan count and each element
  is `ReferenceEquals` to the recording invoker's return (asserted in B) `[R1-2]`.
- The executor rejects an invoker result whose `IntentId` or `OperationName` does not echo the
  intent with `SIBYLA-S1-INVOKER-RESULT` `[R1-11]`.
- Capability preflight `[R1-7]` is the pure function
  `CapabilityPreflight.Check(IReadOnlyDictionary<string, IOperationHandlerDescriptor>, ISibylaCommandInvoker)`
  that the real provider calls before compiling. It compares the wired table with the canonical
  production table `[H-1]`: the exact 29 ordinal keys (no missing, extra, duplicate, case alias or
  null), and for each key the declaration (exact CLR request and result types, adapter, action,
  mutation kind, elevation, compensation and readback links, the declared ordered argument schema
  `ArgumentSchema` with its declared types `ArgumentTypes` `[L-3]`, and closed
  `IOperationHandler<TRequest,TResult>` identity), then the invoker. `HandlerTable` owns its entries
  under an ordinal comparer whatever dictionary it is handed, so a case variant of a key is never a
  hit `[L-4]`.
  `BuildIntent` callability is proven at compilation, where the plan builder also rejects with
  `SIBYLA-S1-INTENT-SCHEMA` any intent whose argument names or declared argument types (`ArgumentTypes`,
  compared exactly `[L-3]`), adapter, action, result type, kind or elevation flag (`[L-8]`, the
  re-review's residual finding) depart from its descriptor, and with `SIBYLA-S1-INTENT-BUILD` any handler whose build throws `[G-1]`; both
  happen before any invoker call. The mutex descriptor is `Global\GOTT.Apollo.Deployment.v1`. Table-level
  failures (missing, extra, duplicate, case alias, null handler, mutex descriptor) are
  `SIBYLA-S1-CAPABILITY-REGISTRY`; per-descriptor failures (types, links, schema, `BuildIntent`) are
  `SIBYLA-S1-CAPABILITY-HANDLER` `[R2-N7]`. Invoker rule: `SupportsIntentValidation == true`, `CanExecuteReads == false`,
  `CanExecuteMutations == false` (`SIBYLA-S1-CAPABILITY-INVOKER`, fail-closed against an executing
  invoker being wired in). It leaves invoker call count at zero on failure.
- `DeploymentRuntime.Current` is the composition root with the `internal` hook of section 1.8,
  which allows substituting phases, provider, handler table and invoker. Production sources contain
  none of the tokens `Fake`, `Mock`, `Recording`, `Sentinel`, `TestOnly`.

## 6. Handlers, intents, `ValueRef<T>`

- `IOperationHandler<TRequest, TResult>`: `OperationName`, `Adapter`, `Action`, `MutationKind`,
  `RequiresElevation`, `BuildIntent(TRequest) → NativeCommandIntent`, `CompensationHandler`
  (`Type` or `null` only for operations with no compensation: snapshots, readbacks, `Mutex.*`,
  `Http.GetNoRedirect`, `Process.Rollback`, `*.Rollback`) and `ReadbackHandler` (`Type` or `null`
  for the same set) `[R1-14]`. Preflight validates that each referenced `Type` is a registered
  descriptor with the request/result types the table declares.
- 29 distinct sealed handler classes, one per V2 §5 key, each with its own sealed immutable request
  type and one of the V2 result types. The executor's table is
  `Dictionary<string, IOperationHandlerDescriptor>` with `StringComparer.Ordinal`, populated from the
  29 concrete classes.
- `NativeCommandIntent` (sealed): `ContractVersion = 1`, `IntentId` (non-empty Guid), `OperationName`,
  `Adapter`, `Action`, `OrderedArguments` (name, declared CLR type, redaction, value),
  `ExpectedResultType` (exact `Type`), `MutationKind`, `RequiresElevation`, `ExecutionAllowed = false`,
  `DependsOn` (set of intent ids derived from the `ValueRef<T>` arguments).
- `ValueRef<T>` (sealed): `SourceIntentId` (non-empty Guid), `SourceOperationName`, `ValueType = typeof(T)`.
  It is the only way to reference a future output. Argument values are either a concrete validated
  value object (or an enum, a boolean, or a typed set of value objects) or a `ValueRef<T>`; `null`,
  `Guid.Empty`, empty strings, strings with control characters and secret-bearing values (any
  argument whose redaction is `Secret`) are rejected at construction with
  `SIBYLA-S1-INTENT-ARGUMENT`. `[R3-A2]` The secret-pattern scan of section 8 applies to error
  surfaces, not to argument values: the secrets *file paths* (`…\local\secrets\web.json`) are
  legitimate, contractual arguments of the IIS and SCM operations; only secret *values* are
  forbidden, and no argument in Slice 1 carries one.
- The compiler rejects a `ValueRef<T>` whose source intent's `ExpectedResultType != typeof(T)`,
  or whose source intent id is not in the current plan or in the `Plan` of an upstream contract
  instance actually received, with `SIBYLA-S1-PLAN-LINEAGE`.
- Compensation intents are separate intents with their own request types (e.g. `ProcessStopRequest`
  with `Reason = RollbackSafety` vs `Reason = Deployment`). Each compensation request carries a
  `ValueRef<TSnapshot>` to the forward snapshot intent and a `ValueRef<MutationReceipt>` to the
  forward apply intent; its `PlannedOperation.CompensatesIntentId` equals that apply intent. Its
  readback carries `ValueRef<RollbackReceipt>` to the compensation intent.
- `Complete` and lease state are not operations, intents or types in Slice 1 `[R1-14]`.

## 7. Plan compiler, phase allocation, PlanOnly

`DeploymentPlanCompiler.Compile(phaseRequest)` is pure and returns `DeploymentPlan`: ordered
`PlannedOperation` entries (intent, role `Forward | Compensation | CompensationReadback`, phase,
`CompensatesIntentId` where applicable). The mutex descriptor is only
`Global\GOTT.Apollo.Deployment.v1`; no `System.Threading.Mutex` is referenced.

Phase allocation `[R1-2]` (forward order within each phase; `→` marks the compensation entries the
phase appends after its forward entries, in the order they would execute):

| Phase | Forward operations (in order) | Compensation entries appended |
|---|---|---|
| Gate | `FileSystem.GetSnapshot` (RepositoryRoot, ExpectedCommit, LineageSnapshots = []) | none |
| Publish | `FileSystem.GetSnapshot` (StagingRoot, ExpectedCommit, LineageSnapshots = [gate snapshot ref]), `Acl.GetSnapshot` (StagingRoot) | none |
| Install | `Mutex.Acquire`, `FileSystem.GetSnapshot` (InstallRoot + BackupRoot), `Acl.GetSnapshot`, `Process.GetSnapshot`, `Process.Stop` (Deployment), `FileSystem.PublishTree`, `Acl.Apply`, `FileSystem.SetActiveInstall`, `FileSystem.Readback`, `Acl.Readback` | fixed `Process.Stop` (RollbackSafety); `Acl.Rollback` + `Acl.Readback` (compensates `Acl.Apply`); `FileSystem.Rollback` + `FileSystem.Readback` (compensates `SetActiveInstall`); `FileSystem.Rollback` + `FileSystem.Readback` (compensates `PublishTree`); `Process.Rollback` + `Process.Readback` (compensates `Process.Stop` Deployment); fixed `Mutex.Release` |
| Configure | `Iis.GetSnapshot`, `Scm.GetSnapshot`, `Tls.GetSnapshot`, `Iis.Apply`, `Scm.Apply`, `Tls.Apply`, `Iis.Readback`, `Scm.Readback`, `Tls.Readback` | fixed `Process.Stop` (RollbackSafety); `Tls.Rollback` + `Tls.Readback`; `Scm.Rollback` + `Scm.Readback`; `Iis.Rollback` + `Iis.Readback` |
| Health | `Process.Start`, `Process.Readback`, `Http.GetNoRedirect`, `Mutex.Release` | `Process.Stop` (RollbackSafety) + `Process.Readback` (compensates `Process.Start`) |

Amendment `[R3-A1]` (found while implementing sub-slice B): revision 3 placed the IIS, SCM and TLS
snapshots in Install, but the Install request carries no site name, host, port, thumbprint or store,
so those snapshot intents could not be built without null placeholders. They belong to Configure,
whose request carries every input they need. The phase-wise rule (snapshots, mutations, readbacks)
still holds inside each phase; cross-phase lineage is still exercised by Health, whose
`Mutex.Release` references Install's lease and whose `Process.Start` references Install's process
snapshot.

Rules `[R2-N1]` `[R2-N2]`:
- Order is phase-wise: within a phase, snapshots, then mutations, then readbacks, then the
  compensation entries. This table is the sole order oracle; V2's single-transaction interleaving is
  superseded.
- Compensation entries are derived, not listed ad hoc: one entry per mutating forward intent, from
  its `CompensationHandler` (`PublishTree → FileSystem.Rollback`, `SetActiveInstall → FileSystem.Rollback`,
  `Acl/Iis/Scm/Tls.Apply → *.Rollback`, `Process.Stop(Deployment) → Process.Rollback`,
  `Process.Start → Process.Stop(RollbackSafety)`), each followed by its `ReadbackHandler` entry,
  emitted in reverse forward order. In addition there are exactly two fixed entries with
  `CompensatesIntentId = null` (the only permitted null in a plan): the phase-leading safety stop of
  Install and Configure, and Install's trailing `Mutex.Release`, which references the lease by
  `ValueRef<MutexLeaseReceipt>`. `Mutex.Acquire.CompensationHandler` stays `null`.
- Configure's `Iis/Scm/Tls.Apply` reference Configure's own `Iis/Scm/Tls.GetSnapshot` intents by
  `ValueRef<T>`; Health's `Mutex.Release` references Install's `Mutex.Acquire` lease by
  `ValueRef<MutexLeaseReceipt>` and Health's `Process.Start` references Install's
  `Process.GetSnapshot` through `InstallRollbackHandle.Plan`; Install's `FileSystem.PublishTree`
  carries the `PublishedArtifact` instance as its artifact argument and references Install's own
  install-and-backup snapshot as its baseline `[R3-A1]` `[C1-4]`.
- `DeploymentResult.TransactionId` equals `InstallRollbackHandle.TransactionId`, the only transaction
  any intent references; the concatenated one-shot plan is labelled `DeploymentPhase.Deployment` and
  each entry keeps its own phase `[C1-7]`. Configure opens no transaction of its own: it runs under
  Install's lease and `ConfigureRollbackHandle.TransactionId` equals Install's `[C2-5]`.
- A snapshot's `LineageSnapshots` is an allowed-empty typed set of references to earlier snapshots
  (`ValueRefSet<FileSystemSnapshot>`): empty for the gate and for Install, the gate snapshot for
  Publish. An empty typed set is a value, not a placeholder `[C2-1]`. Likewise an empty path set is
  accepted only for the argument named `CredentialLeafExclusions`; every other empty path set is
  rejected with `SIBYLA-S1-INTENT-ARGUMENT` `[C2-6]`. In Slice 1 the Install phase's exclusions are
  empty because the Install request carries no secrets paths (V2 §2); where the credential leaves
  enter the Install plan is an open owner decision for Slice 2, recorded here and not hidden.
- Configure's `CurrentWebPath` and `CurrentWorkerPath` are the install root while Install produces no
  release-specific `ReleasePath` (always null in Slice 1); Slice 2 must switch both to the activated
  release path `[L-7]`.
- Direct phase calls must address the workloads Install snapshotted: `Configure-SibylaProduction`
  requires ordinal equality of its `AppPoolName` and `WorkerServiceName` with the Install handle's,
  else `SIBYLA-S1-CONTRACT-LINEAGE` `[C2-7]`.
- `HealthResult.Checks` declares the six checks of the health gate (exact 302 on the challenge
  endpoint; `Location` targets the expected authority and callback; `response_type = code`; PKCE
  `S256` with a nonempty challenge; the web process serves the activated release; the worker service
  runs the activated release), every one `Planned` `[C2-9]`.
- The deployment-wide compensation order (Health's, then Configure's, then Install's entries), with
  repeated safety stops collapsed, equals the V2 rollback order: `Process.Stop`, `Tls.Rollback`,
  `Scm.Rollback`, `Iis.Rollback`, `Acl.Rollback`, `FileSystem.Rollback`, `Process.Rollback`,
  `Mutex.Release`, each rollback followed by its readback.
- `DeploymentResult.DeferredCommandIntents` is the concatenation of the five `Plan`s in phase order;
  `ReleaseGateResult.DeferredCommandIntents` is the gate plan.
- `oracles/registry.json` and `oracles/lineage.json` are typed by hand from this table and V2 §5
  before any handler code exists.

### 7.1 Operation schemas `[C1-1]`

The registry oracle is `tests/Sibyla.Deployment.Tests/oracles/registry.json`: the file an independent
author typed from V2 Â§5 and the section 7 table alone (`oracles/registry.independent.json`, kept
verbatim with its recorded judgement calls), plus exactly the four adjudicated deviations D1-D4 in
`evidence/C-oracle-adjudication.txt` (each one a reading that would have required a null placeholder:
Gate has one root and no upstream snapshot; Publish knows no app pool; Install carries no site name;
the compensation of `Process.Start` returns a `MutationReceipt`). The earlier revision-4 table, which
had been written from the sub-slice B code, is withdrawn. The production handlers are adapted to the
oracle in sub-slice C, RED first (`evidence/C-red.txt`). The oracle fixes, per operation: adapter and
action, mutation kind, elevation, result type, compensation and readback links, and the exact ordered
argument names and families.

Mutex operations are `None` because they touch no host configuration, file, service, process or
network endpoint; they are excluded from the "every mutating intent has a compensation" rule and
covered by the fixed trailing `Mutex.Release` entry instead. The compensation of `Process.Start` is a
`Process.Stop` with `Reason = RollbackSafety`. Rollback handlers carry no readback link of their own;
the compiler emits the compensated operation's readback after each rollback.

`SibylaPlanOnlyCommandInvoker`: `SupportsIntentValidation = true`, `CanExecuteReads = false`,
`CanExecuteMutations = false`; `ValidateIntent` re-checks the intent against the handler descriptor;
`InvokeIntent` returns `NativeInvocationResult { IntentId, OperationName, Disposition = Planned }`
and nothing else. There is no `ActualResult`, `ExitCode`, `Succeeded` or host observation anywhere
in Slice 1.

## 8. Validators, sanitizer, and error codes

Value objects (construct-or-throw; code in parentheses) `[R1-10]`:
- `ExactGitCommit` (`SIBYLA-S1-INPUT-COMMIT`): exactly 40 lowercase hex characters.
- `AbsoluteWindowsPath` (`SIBYLA-S1-INPUT-PATH`): `^[A-Za-z]:\\` prefix, at least one segment after
  the drive (drive root rejected), no UNC/`\\?\`/`\\.\`, no `/`, no `.`/`..`/empty segments, no
  segment ending in `.` or space, no control characters, no `<>:"|?*` in segments, length ≤ 240.
  With the `FileLeaf` option (secrets paths) the last segment must contain a `.` and not be a root.
- `SafeIisName` (`SIBYLA-S1-INPUT-IIS-NAME`): 1–64 chars, no `\ / ? ; : @ & = + $ , | " < > *`, no
  control chars, no leading/trailing whitespace or dot.
- `SafeScmName` (`SIBYLA-S1-INPUT-SCM-NAME`): ordinal equality with `GottSibylaWorker`.
- `DnsHostName` (`SIBYLA-S1-INPUT-HOST`): RFC 1123 labels (`[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?`,
  lowercase), 1–253 chars, at least two labels, no trailing dot, no IP literal.
- `HttpsUri` (`SIBYLA-S1-INPUT-URI`): absolute, scheme literally `https://`, authority a lowercase
  `DnsHostName` with an optional valid port, no user-info, no query `[L-1]`, no fragment, no whitespace;
  well-formed for `System.Uri`. The challenge URI is the base URI without its trailing slash joined
  with the challenge path; with no query allowed on the base, the join is always well-formed.
- `ChallengePath` (`SIBYLA-S1-INPUT-CHALLENGE-PATH`): starts with `/`, no `?`, `#`, `\`, no
  `.`/`..`/empty segments, no control or whitespace characters, length ≤ 512.
- `CertificateThumbprint` (`SIBYLA-S1-INPUT-THUMBPRINT`): exactly 40 or 64 hex characters, no
  separators or whitespace.
- `CertificateStore` (`SIBYLA-S1-INPUT-CERT-STORE`): ordinal `My` or `WebHosting`.
- `HttpsPort` (`SIBYLA-S1-INPUT-PORT`): decimal digits only, no leading zero `[L-2]`, 1–65535.
- `OidcClientId` (`SIBYLA-S1-INPUT-CLIENT-ID`) `[C1-5]`: 1–64 chars from `[a-z0-9._-]`, lowercase,
  no leading/trailing `.` or `-`.
Value objects are pure string checks: no `System.IO.Path` or other `System.IO` call; `System.Uri`
is the only framework parser used `[R2-N8]`. Cmdlets and the one-shot construct these value objects
before anything else; the phase requests only accept value objects, so the one-shot cannot bypass
them. Public-input validation evaluates every parameter and always throws
`DeploymentAggregateException` carrying the ordered list of all `SIBYLA-S1-INPUT-*` failures, even
when there is exactly one `[R1-8]` `[R2-N7]`. `oracles/validators.json` is written from these rules
before any validator code exists.

Sanitizer `[R1-3]`: `DeploymentFailure` (sealed): `Code` (allowlist below), `OperationId` (Guid),
`OperationName` (validated against the 29 keys plus the five phase names and `Deployment`; anything
else becomes `Unknown`) `[R1-11]`, `Parameter` (the public parameter an input failure names, validated
against the closed set of the nineteen V2 §2 parameter names; anything else, and every non-input
failure, renders `None`) `[L-6]`, `Category`
(`Input | Contract | Capability | Intent | Invoker | Orchestration | Internal`), `FinalState`
(`Created | Validated | Compiled | Planned`). `DeploymentException` wraps one failure;
`DeploymentAggregateException` wraps a primary plus an ordered list; both override `Message` and
`ToString()` to render only those fields, keep `Data` empty, and carry no `InnerException`. The lower
exception type is mapped to `Category` and discarded. Every cmdlet's `ProcessRecord` wraps all work
in one handler (the catch-all mapping lives in `ErrorBoundary.Sanitize`, so it can be exercised in
process `[G-3]`): a `DeploymentException`/`DeploymentAggregateException` is rethrown via
`ThrowTerminatingError(new ErrorRecord(ex, ex.Code, ErrorCategory.InvalidOperation, null))`; any
other exception type becomes `SIBYLA-S1-INTERNAL`, category `Internal`, message dropped.

Boundaries that exist in Slice 1 and must be injected in G: public-input validation, contract
identity/version/lineage, `SIBYLA-S1-EXECUTION-DEFERRED`, capability preflight, `BuildIntent`,
intent argument construction, plan compilation, invoker `ValidateIntent`, invoker `InvokeIntent`
(including a non-`DeploymentException` type such as `InvalidOperationException("raw-secret-value")`),
invoker result echo, orchestration handoff, and the catch-all.

Reachability note `[C1-8]`: `SIBYLA-S1-CONTRACT-VERSION` cannot be produced from the public surface,
because the exact-type identity check precedes the version check and Core constructors reject any
version other than 1; foreign lookalikes with versions 0 or 2 therefore fail with
`SIBYLA-S1-CONTRACT-IDENTITY`, and G/H tests expect that code. The version code remains for the
internal construction path.

Allowlist: `SIBYLA-S1-INPUT-COMMIT`, `-INPUT-PATH`, `-INPUT-IIS-NAME`, `-INPUT-SCM-NAME`, `-INPUT-HOST`,
`-INPUT-URI`, `-INPUT-CHALLENGE-PATH`, `-INPUT-THUMBPRINT`, `-INPUT-CERT-STORE`, `-INPUT-PORT`, `-INPUT-CLIENT-ID`,
`SIBYLA-S1-EXECUTION-DEFERRED`, `SIBYLA-S1-CONTRACT-IDENTITY`, `SIBYLA-S1-CONTRACT-VERSION`,
`SIBYLA-S1-CONTRACT-LINEAGE`, `SIBYLA-S1-CAPABILITY-REGISTRY`, `SIBYLA-S1-CAPABILITY-HANDLER`,
`SIBYLA-S1-CAPABILITY-INVOKER`, `SIBYLA-S1-INTENT-ARGUMENT`, `SIBYLA-S1-INTENT-SCHEMA`,
`SIBYLA-S1-INTENT-BUILD`, `SIBYLA-S1-INVOKER-VALIDATE`, `SIBYLA-S1-INVOKER-INVOKE`,
`SIBYLA-S1-INVOKER-RESULT`, `SIBYLA-S1-PLAN-LINEAGE`, `SIBYLA-S1-ORCHESTRATION-HANDOFF`,
`SIBYLA-S1-INTERNAL`.

Secret-pattern set (used by `SIBYLA-S1-INTENT-ARGUMENT` and by the G assertions): `raw-secret-value`,
`password`, `pwd=`, `token`, `secret`, `connectionstring`, `Server=`, `Host=`, `\local\secrets`,
any newline or tab.

Deferred to Slice 2 (explicitly not Slice 1 findings): execution-time rollback, rollback readback,
release, complete and aggregate-of-execution boundaries, mutex acquisition, host observation, real
adapters, journal, artifact export.

## 9. Sub-slices, oracles, and evidence

| Sub-slice | RED test first | Oracle |
|---|---|---|
| A | import in PS 5.1, exactly six exports, contract sealed/immutable/v1, six entrypoints in fresh processes with sentinels asserted from the returned `Request` (prerequisite objects built by earlier real entrypoints in the same process; a parameter loop with zero assertions fails), `WorkerServiceName` proven negatively with `not-the-worker` → `SIBYLA-S1-INPUT-SCM-NAME`, AST: one import, one module-qualified call, no dot-source, `-WhatIf:$WhatIfPreference`, `[object]` contract params, zero adapted members on outputs | hand-written list of six names and per-cmdlet parameter names |
| B | throwing-provider sentinel fails every phase; throwing-phase sentinel fails the one-shot; recording invoker sees every phase; `OperationResults` are the invoker's instances; `ReferenceEquals` on all handoffs, in xUnit and in PS 5.1 | none needed (identity) |
| C | 29 distinct handler types; exact adapter/action/argument order per key; no generic handler; typed compensation/readback links | `oracles/registry.json`, typed by hand from V2 §5 and section 7 |
| D | every argument is a value or `ValueRef<T>`; lineage graph complete and type-checked; compensation readbacks point at compensation receipts; forward ≠ compensation intents; cross-phase lineage through `Plan` | `oracles/lineage.json` |
| E | reflection: forbidden names of section 1.1 absent; PlanOnly invoker capabilities as section 7; byte-level scan of the net48 DLLs `[R1-19]`: no referenced type among `System.Threading.Mutex`, `Semaphore`, `EventWaitHandle`, `System.IO.File`, `Directory`, `FileStream`, `System.Diagnostics.Process`, `System.ServiceProcess.*`, `System.Net.*`, `Microsoft.Win32.Registry`, `Microsoft.Web.Administration.*`, `System.Security.AccessControl.*`, `X509Store`, `System.IO.Path` `[R2-N8]`; referenced assemblies only `mscorlib`, `System`, `System.Core`, `netstandard` (Core) plus `System.Management.Automation` (Cmdlets) | forbidden-name and forbidden-type lists |
| F | validator matrix, positive and negative, through cmdlets and one-shot, in xUnit and in PS 5.1; aggregate of several invalid inputs | `oracles/validators.json` |
| G | injection of the secret-pattern set at each boundary of section 8, including a non-`DeploymentException` at the invoker; outputs and the serialized `ErrorRecord` minus `InvocationInfo`/`ScriptStackTrace` contain only allowlisted fields, and markers appear nowhere else `[R2-N3]` | `oracles/sanitizer.json` |
| H | capability matrix through the pure check on corrupted tables and one integration case per corruption class through the real provider with a recording invoker asserting zero calls: each key missing, extra key, case alias, null handler, wrong request/result type, foreign same-name type, wrong adapter/action, reordered/missing/extra argument, wrong mutation kind, invoker with `SupportsIntentValidation` false or a `CanExecute*` true, throwing `BuildIntent` | derived from `oracles/registry.json` |

RED evidence per sub-slice `[R1-13]`: `tests/Sibyla.Deployment.Tests/evidence/<sub-slice>-red.txt`
is saved before implementation and `<sub-slice>-green.txt` after; each starts with the framed
SHA-256 over the test files, the oracle files and `local/deploy/src/**` at that moment, so the
reviewer can confirm the oracle predates the implementation. A behaviour test that passes on its
first run is a HARD STOP.

Preserved C# paths, SHA-256 of approved bytes (V2 candidate), status in V3:

| Path | Approved hash | V3 |
|---|---|---|
| `src/Apollo.Worker.Documents/Program.cs` | `3ed157c63c44a5ad88fe769799974846cd8676c87c61f6a1a293e0f6237b2fb7` | byte-equal |
| `src/Apollo.Worker.Documents/WindowsServiceNameResolver.cs` | `8345dd41b6ac92f11627a45ae1bb4052fd6f77890bf937f151b34342c18ed079` | byte-equal |
| `tests/Apollo.Tests.Sibyla/Apollo.Tests.Sibyla.csproj` | `8de91475051c05c55b9a5253a6089ce6b1f1421a7f7d69daee6b4f3437336de2` | byte-equal |
| `tests/Apollo.Tests.Sibyla/WindowsServiceNameResolverTests.cs` | `0516ec4c481c1da32d3c432cd1de0ec6eaa4acf832ecf894ab09b57a117a30a4` | byte-equal |
| `src/Sibyla.Web/Program.cs` | n/a (base moved) | approved hunk applied verbatim |

## 10. Operational restrictions (unchanged)

No deployment, no IIS/SCM/TLS/ACL/process/database/network mutation, no reading of `local\secrets`
or the SCM password, no commit, no push, no merge. `GottSibylaWorker`, the three Sibyla sites,
`gott_sibyla`, the paused cron and the disabled intake plugin are not touched.

## 11. Recovery after the naming shift (2026-09-02)

The accepted snapshot (section 9, `FINAL-verification.txt`, commit `89a8dfb`) was cut against
`main` at `aed729c`. Between that commit and the merge, `main` renamed the module Sibyla to Argus,
the platform Sibyla to Sibyla and the agent Hermes to Sibyla (`docs/naming-glossary.md`,
`docs/apollo-naming-shift-prompt-260902.md`). The branch was rebased onto `main` at `cdaaf2c` and
recovered as follows. Every earlier evidence file is kept verbatim; the recovery adds
`evidence/RECOVERY-green.txt` with the new fingerprint.

**Platform side (outside the module's fingerprint; forced by the rename).** The approved hunks
now live in `src/Sibyla.Web/Program.cs` and `src/Sibyla.Worker.Documents/Program.cs`;
`WindowsServiceNameResolver` moved to `src/Sibyla.Worker.Documents/` with the namespace
`Sibyla.Worker.Documents` and the default service name `Sibyla.Worker.Documents` (the name `main`
gave the host in Phase 3; the mandated SCM name `GottSibylaWorker` is unchanged); the resolver test
moved to `tests/Sibyla.Tests.Argus/` and that project references the worker. The hashes in
section 9 therefore no longer match these four paths; the hunks are the approved ones, applied to
the renamed files.

**Inside the fingerprint (two deltas, both forced).** `Infrastructure/RepoPaths.cs` finds the repo
root by `Sibyla.slnx`, because `Sibyla.slnx` no longer exists; without it every probe fails to
locate the module. The default `BaseUri` and `CallbackUri` are `https://sibyla.gottsolutions.net/`
and `…/signin-oidc` (ruling N2: the platform deploys on the sibyla hostname after Phase L), in
`TestSibylaProductionCommand.cs`, `Invoke-SibylaDeployment.ps1`, `Test-SibylaProduction.ps1` and
`oracles/entrypoints.json`. The validator examples that use `sibyla.gottsolutions.net` as a
syntactically valid hostname are untouched. The `SIBYLA_SECRETS_FILE` environment variable is
unchanged: it is this module's contract with the hosts.

**Renamed, by the owner's word (2026-09-02, after the recovery).** The module and its entry points now carry the platform's name: `Sibyla.Deployment` (folder, solution, both projects, the test project, the manifest), `Configure-/Install-/Publish-/Test-SibylaProduction`, `Invoke-SibylaDeployment`, `Invoke-SibylaReleaseGate`, the cmdlet and provider classes, the error-code prefix `SIBYLA-S1-*`, the hosts' secrets variable `SIBYLA_SECRETS_FILE` (read by `src/Sibyla.Web/Program.cs` and `src/Sibyla.Worker.Documents/Program.cs`), and every oracle and probe that named them. Before the rename they were `Apollo.Deployment`, `*-ApolloProduction`, `APOLLO-S1-*` and `APOLLO_SECRETS_FILE`; the evidence transcripts of sections 9 and 11 keep those names because they are records of the runs that produced them. The mandated SCM name `GottSibylaWorker`, the database roles, the IdP clients and the `D:\ApolloData` folders are unchanged (naming rulings N1, N3). `evidence/RENAME-green.txt` records the suite and the fingerprint after the rename.

**Proof.** `dotnet test` on the deployment tooling after the deltas: 585/585. The review of
2026-09-02 recorded 543/543 before the rebase; the recovery did not investigate the difference in
the enumerated count. Platform suites on the rebased tree: Argus 137/137 (136 plus the resolver
test), Browser 121/121, TenantIsolation and Platform unchanged by the branch.

## 12. Reframed scope for Slice 2 (2026-09-02): two hosts and one service

The channel-intake API exists now (`src/Sibyla.Api`, spec `apollo-channel-intake-api-spec.md`,
revision 2). Slice 1 modelled one IIS site (`IisTarget`, `SafeIisName`, `TlsTarget` families) and
one Windows service; the production shape is **two sites and one service**, and Slice 2 plans
them as follows. Nothing here changes Slice 1's contracts or evidence.

- **A second site** `api.sibyla.gottsolutions.net`: its own `Iis.Apply` / `Tls.Apply` pair with
  the same readbacks and rollback entries as the web site's, its own app pool (No Managed Code),
  physical path `<install root>\api\<release>`, `maxAllowedContentLength` ≥ 52 500 000 and a
  120 s request timeout, and the environment `ConnectionStrings__SibylaDb` (on `apollo_api`),
  `SIBYLA_SECRETS_FILE`, `Identity__Authority`, `Identity__Audience`. No Data Protection ring.
- **Publish** adds `src/Sibyla.Api` to the two artifacts of Slice 1 (framework-dependent,
  net10.0, Release), with its own manifest hash in `PublishedArtifact`.
- **Health** gains two checks on the API host: `GET /health` → 200 and `GET /health/ready` → 200
  (the database `SELECT 1` on the API role), beside the six checks of the web site; the health
  phase's compensation order is unchanged.
- **Configure** carries the API site's current path beside `CurrentWebPath` and
  `CurrentWorkerPath`; the open decision on the activated release path (section 7) covers all
  three.
- **Inputs**: a second `DnsHostName` (`api.sibyla.gottsolutions.net`), a second `CertificateThumbprint`
  or the same wildcard certificate, the API role name as a `SafeScmName`-style value object
  (`apollo_api`, the only accepted value in Slice 2, like `GottSibylaWorker` for the service).
- **Preconditions the plan must verify, not perform**: the `apollo_api` role exists (created by
  `local/setup-db.ps1`, a superuser step), the `ChannelIntake` migration is applied on Main and
  Preview, and the staging root grants the API app-pool identity the same write ACL as the web
  host's. A plan that finds any of them missing declares it as a failed precondition operation.
- **A third site** `docs.sibyla.gottsolutions.net` (added 2026-09-03): a static site over the
  repository's `docs\` folder (`D:\fileStorage\repos\GOTT.Apollo\docs`, served from the working
  copy, not from a release folder), its own `Iis.Apply` / `Tls.Apply` pair, app pool No Managed
  Code on `ApplicationPoolIdentity`, anonymous, directory browsing on, MIME maps `.md` →
  `text/markdown; charset=utf-8`, `.svg`, `.json`; one health check `GET /` → 200; no service,
  database or environment. Inputs: a third `DnsHostName` and certificate; the IIS site name
  `Sibyla.Docs` presumes the legacy site is renamed `Sibyla.Legacy.Docs` first (a precondition
  the plan verifies).
- **Slice 2 specification drafted (2026-09-03):** `apollo-deployment-slice2-spec.md`, draft 1 for
  the owner's review, with the six decisions D-S2-1…6 (credential leaves, activated release path,
  service name `Sibyla.Worker.Documents`, legacy sites, the docs path, the `-Execute` switch) and
  the hand-path facts as its oracle. No Slice 2 code before that review.
- **Hand path in force (2026-09-03).** Until Slice 2 lands, production is deployed by
  `local\publish-release.ps1`, `deploy-release.ps1`, `rollback-release.ps1` and
  `provision-production.ps1` (run record `apollo-deployment-run-260903.md`). They fix the shape
  Slice 2 must take over: install root `C:\Apps\Sibyla\{web,api,worker}\<release>`, secrets at
  `C:\ProgramData\Sibyla\secrets\{web,api,worker}.json` reached only through `SIBYLA_SECRETS_FILE`
  in applicationHost location sections, the key ring at `D:\ApolloData\dp-keys`, the service
  `Sibyla.Worker.Documents` under `.\SibylaWorker` (the mandated `GottSibylaWorker` name of Slice 1
  remains the legacy service's; Slice 2 takes the deployed name), the legacy sites as
  `Sibyla.Legacy.*`, and win-acme renewals `[Platform] <host>`.
- **Phase L** (naming document) precedes any of this: `api.sibyla.gottsolutions.net` is Sibyla
  Legacy's live API hostname until the legacy sites move to `api.legacy.gottsolutions.net`.
