# Sibyla.Deployment — Slice 2 specification (execution), revision 10 — ACCEPTED

*Revision 9 was **accepted by both reviewers** in round 9 (2026-09-03; record:
`apollo-deployment-slice2-spec-review.md`; reviewer P = protocol fidelity to Slice 1, reviewer O =
operations and safety on the live host). Revision 10 is the editorial pass that applies the six
Low notes both reviewers left for A2 (P9-N1…N4, O9-N1…N2); no rule of revision 9 changed in
substance and no further review round was required by either reviewer. This is the
specification sub-slice A2 starts from, under the evidence rules of section 9. Slice 1
V3 (`apollo-deployment-slice1-v3-spec.md`, "S1") is the planning-only module on `main`. Spec
first: no S2 code before a revision is accepted by both reviewers.*

## 0. What Slice 2 delivers

1. **Execution behind one switch, one entry point.** `Invoke-SibylaDeployment -Execute` runs the
   V2 plan. The five phase cmdlets accept `-Execute` for parity and refuse it
   (`SIBYLA-S2-EXECUTION-REFUSED`). Without `-Execute` every entry point behaves byte-for-byte as
   S1. `-Execute -WhatIf` previews the V2 plan through the V2 plan-only invoker (5.6); the plan is
   release-agnostic (5.7), so the preview needs no release.
2. **Where the code lives.** Three assemblies:
   - `Sibyla.Deployment.Core` — S1's, changed in **exactly one place**: the public const
     `SafeScmName.MandatedWorkerServiceName` becomes `Sibyla.Worker.Documents` (it is also the
     default of `WorkerServiceName` in three cmdlets). Core contains no probe name, no V2 type,
     no environment lookup. The S1 byte-level scan of Core (`forbidden.json`) stays valid.
   - `Sibyla.Deployment.Execution` (`net48;net10.0`; the S1 transferability rule, `sourceBans`
     and `LangVersion 13.0` apply to it): the V2 contracts and pipeline (3), `HandlerTableV2`,
     `CapabilityPreflightV2`, `DeploymentPlanCompilerV2`, the executing and the V2 plan-only
     invokers, the journal, resume, redaction, `FailureCodesV2`, `DeploymentFailureV2`/`ErrorBoundaryV2`,
     `KnownParameterNamesV2`, `KnownOperationNamesV2`, the adapter interfaces, `DeploymentRuntimeV2`,
     the V2 value object `ServiceNameV2` (exactly `Sibyla.Worker.Documents` or
     `ZZ.Sibyla.Probe.Service`; the V2 pipeline builds it from the cmdlet's `SafeScmName`, so an
     entry point can never name the probe service; the C2 harness builds it directly), and a
     hand-rolled minimal JSON reader/writer under `Execution/Json/` (no JSON library, no extra
     namespace). May reference `System.IO` from `Journal/` only.
   - `Sibyla.Deployment.Adapters.Windows` (`net48` only, exempt from the transferability rule,
     proven through PowerShell 5.1 probes): the eight adapters. Spike done 2026-09-03 on this
     host (`Microsoft.Web.Administration` 7.0.0.0 GAC + `System.ServiceProcess`, offline build,
     loaded in PS 5.1, read the 12 sites and the service).
   - `Sibyla.Deployment.Cmdlets` references all three. **S1 oracle amendments, complete list**
     (9 A2): `forbidden.json` — `allowedAssemblyReferences["Sibyla.Deployment.Cmdlets"]` gains the
     two new assemblies; `validators.json` — SCM rows: `Sibyla.Worker.Documents` valid,
     `GottSibylaWorker` invalid; `entrypoints.json` — `WorkerServiceName` default
     `Sibyla.Worker.Documents` (row stays `onlyValidValue: true`; its positive `sentinel` becomes
     `Sibyla.Worker.Documents`; the negative sentinel `not-the-worker` lives in
     `probes/negatives.ps1` and `validators.json` and stays, P7-5) and the S2 parameter lists
     of section 4; `validators.json` SCM rows: `Sibyla.Worker.Documents` moves from `invalid` to
     `valid`, `GottSibylaWorker` to `invalid`, the case variants become
     `sibyla.worker.documents`/`SIBYLA.WORKER.DOCUMENTS` and the whitespace variants are re-based on
     the new name (P6-9). Outside Core the rename
     also touches the literal defaults in `Configure-`, `Install-` and `Invoke-SibylaDeployment.ps1`
     (compared to the oracle by `EntrypointAstTests`) and `tests/Infrastructure/ValidRequests.cs`
     (P5-L2). `parameters.json` untouched. The S1 source scans (`sourceBans`, `LangVersion`) cover
     every `src/**/*.cs`, so they apply to Execution and Adapters.Windows unchanged; hence no V2
     member is named `Environment` (the SCM snapshot's set is `EnvironmentAssignments`).
   - `forbidden.v2.json` (Execution and Adapters.Windows): S1's `forbiddenMemberNames` minus
     exactly `Succeeded`, `RolledBack`, `Acquire`; `System.Environment` banned everywhere;
     `sourceBans` and `langVersion` as S1 for Execution; `allowedAssemblyReferences`:
     `Sibyla.Deployment.Execution` = `mscorlib`, `System`, `System.Core`, `netstandard`,
     `Sibyla.Deployment.Core`; `Sibyla.Deployment.Adapters.Windows` = those plus
     `System.ServiceProcess`, `System.Management`, `System.Net.Http`, `Microsoft.Web.Administration`
     (checked byte-level on the built DLLs as S1's E test does); the per-folder namespace rule
     below is a source scan (P7-10); `System.Threading.CancellationToken` is allowed in every
     `Adapters/*` folder (the cancellation deadline of 5.1, P8-N6); allowed namespaces per folder:
     `Execution/Journal/` → `System.IO`; `Adapters/FileSystem/` → `System.IO` (incl. `DriveInfo`),
     `System.Security.Cryptography`; `Adapters/Acl/` → `System.Security.AccessControl`,
     `System.Security.Principal`, `System.IO` (`Directory`, `DirectoryInfo` only: DACL writes and
     the below-target enumeration, P5-N5); `Adapters/Process/` → `System.Diagnostics.Process`,
     `System.ServiceProcess`, `System.Management` (`Win32_Process`, w3wp module list),
     `Microsoft.Web.Administration` (pool state, start, recycle), `System.Runtime.InteropServices`
     (the `Schedule.Service` COM interface); `Adapters/Iis/` → `Microsoft.Web.Administration`;
     `Adapters/Scm/` → `System.ServiceProcess`, `Microsoft.Win32.Registry` (`ImagePath`,
     `FailureActions`, `DelayedAutostart`, `Environment` through the registry); `Adapters/Tls/` →
     `System.Security.Cryptography.X509Certificates`, `Microsoft.Web.Administration` (binding
     certificate hash and store); `Adapters/Http/` → `System.Net.Http`, `System.Net.Security`,
     `System.Net.Sockets` (`HostOverride`: connect to the address, SNI and `Host` from the site's
     name); `Adapters/Mutex/` → `System.Threading.Mutex`.
3. **Real results**: `NativeInvocationResultV2` with `Disposition ∈ {Planned, Started, Succeeded,
   Failed, Skipped}`, `SkipReason ∈ {None, NotReached, NotNeeded}`, `Receipt` (a no-op carries
   `NoChange = true`; every `MutationReceiptV2` carries the adapter's comparable post-state
   digest), `ObservedAt`, `DurationMs`, `Detail`. **Adapters never throw for a domain outcome**:
   a readback that does not match, an HTTP expectation not met, a busy mutex, a precondition
   not satisfied are typed refusals (`Matches = false`, `Acquired = false`, `Satisfied = false`)
   that the invoker turns into `Failed` with the key's code (8); an adapter exception is
   `ADAPTER-FAILED`.
4. **Execution-time rollback** (5.3): after any rollback out of any phase the web and api pools
   are `Started` on the snapshot release, the docs pool is untouched, and the service is in its
   snapshot state (P7-4).
5. **A journal** (6) with `Started` fsynced before the adapter call, per-phase plan digests, and a
   resume that walks the compiled compensation lists and defers state comparison to each
   adapter's own rule.
6. **Health checks that run** (7): twelve named checks, seven `Http.GetNoRedirect` intents plus
   the schema precondition.
7. **Three sites and one service**: the 38-key table (5.1) and the phase table (5.2) are the RED
   oracles.
8. **The owner decisions** D-S2-1…6 (1) and the hand-path facts (2).

Out of scope: remote or multi-host deployment; certificate issuance; building or publishing
(5.4); database migrations; the IdP client registration; the Hermes side; retention (Slice 3).

## 1. Owner decisions — ruled 2026-09-03

| # | Decision (final) |
|---|---|
| D-S2-1 | Secrets never enter the install root. `<SecretsRoot>\<host>.json` reaches each host only through `SIBYLA_SECRETS_FILE`. `SecretsRoot` is an input of the one-shot; the S1 inputs `WebSecretsPath`/`WorkerSecretsPath` must equal `<SecretsRoot>\web.json` / `<SecretsRoot>\worker.json` under `-Execute` (`SIBYLA-S2-INPUT-SECRETS-PATH`). The root and its three leaves are readback-only targets (2). |
| D-S2-2 | Configure on the activated release path. `Install` returns `ReleasePaths` per host; `Iis.Apply` sets `physicalPath`, `Scm.Apply` sets `binPath`; `CurrentReleasePaths` replaces `CurrentWebPath`/`CurrentWorkerPath` (`[L-7]`). `Iis.Rollback`/`Scm.Rollback` repoint; `FileSystem.Rollback(SetActiveInstall)` rewrites the three text files only. |
| D-S2-3 | `SafeScmName` per 0.2; code `SIBYLA-S1-INPUT-SCM-NAME` unchanged. The logon account is never an input, read or written. `Scm.Apply` writes start type delayed-auto as a fixed value. |
| D-S2-4 | `Precondition.Binding` verifies no site named `Sibyla.Legacy.*` binds a `sibyla.*` host and no site other than the three platform sites binds them. The module never touches a legacy site or `GottSibylaWorker`. |
| D-S2-5 | The docs site serves `DocsPath`; no `PublishTree`, no recycle; ownership rule in 2. |
| D-S2-7 | **Ruled 2026-09-04 (post-acceptance amendment, review record "Amendment D-S2-7").** The observed value of `Precondition.Schema` is not the response body. It is rendered from the parsed values — the role check, the count of migration ids, the SHA-256 of the body — and, when unsatisfied, the count of required ids that are missing. The comparison itself still uses the parsed ids; the operator reads the ids from `/health/schema`. A migration id that contains a section-8 secret pattern can therefore never turn the check into `SIBYLA-S2-REDACTION`. |
| D-S2-6 | `-Execute` is a `[switch]` on all six entry points; honoured only by `Invoke-SibylaDeployment`, where it requires `-Confirm` unless `-Force` (= `-Confirm:$false`); non-interactive without `-Force` → `SIBYLA-S2-EXECUTION-UNCONFIRMED`. `ShouldProcess` consulted only under `-Execute`. Truth table: neither switch → `SIBYLA-S1-EXECUTION-DEFERRED`; `-WhatIf` → V1 planning; `-Execute -WhatIf` → V2 preview (warning); `-Execute` → execution; `-Execute -Resume` → resume (Confirm/`-Force` as execution); `-Execute -ChecksOnly` → the ChecksOnly plan, no Confirm (`-NoRollbackOnHealth`/`-Force` with it → ignored with a warning); `-Execute -Resume -WhatIf` → preview of the resume's compensation plan, no mutation; `-Execute -Resume -NoRollbackOnHealth` → the switch is ignored with a warning (a resume only compensates, P7-8); `-Force` or `-NoRollbackOnHealth` without `-Execute` → ignored with a warning; `-ChecksOnly` without `-Execute`, `-ChecksOnly -WhatIf`, `-Resume` without `-Execute`, `-Resume -ChecksOnly` → `SIBYLA-S2-INPUT-SWITCHES`. |

## 2. Facts of the hand path, corrected against the live host (the C2/D2/E2 oracle)

- **Install root** `C:\Apps\Sibyla\{web,api,worker}\<release>`, release id regex
  `^\d{8}-\d{6}-[0-9a-f]{7}$` (the scripts select by it; `.staging\` never counts). `MANIFEST.json`
  per host carries `host, release, commit, dirty, publishedAt, deployedAt` and, from A2 on,
  `requiredMigrations` (copied by `deploy-release.ps1` from `release.json`). `CURRENT.txt`/`PREVIOUS.txt`
  exist only for `api`; S2 derives "previous" from the live `physicalPath`/`binPath`.
- **Sites**: `Sibyla.Web` (10), `Sibyla.Api` (11), `Sibyla.Docs` (12); bindings `http *:80:<host>`,
  `https *:443:<host>` SNI, store `WebHosting`; pools of the same names, `managedRuntimeVersion = ""`,
  `ApplicationPoolIdentity`, web/api `AlwaysRunning` idle 0, docs OnDemand; rapid-fail protection
  on (5 crashes / 5 min), overlapped recycle, `shutdownTimeLimit` 90 s, no preload (an in-process
  site loads its dll on the first request), ANCM in-process with **shadow copy off** (no
  `handlerSetting` in the release `web.config`); `FileSystem.Readback` asserts both on every
  web/api release folder, so a release that would load from elsewhere fails a readback, not a
  health check (O6-N5).
- **Site settings** in `applicationHost.config` `<location path="<site>">`: web/api
  `SIBYLA_SECRETS_FILE`; API `maxAllowedContentLength = 52500000`, `requestTimeout = 00:02:00`;
  docs `directoryBrowse`, `.md` mimeMap, `anonymousAuthentication enabled userName=""` (pool
  identity). Readback = effective value at the site and absence from any `web.config` in the
  served folder. Writes through `Microsoft.Web.Administration` against `applicationHost.config`.
  **Bindings are never written by the module**: certificate hash and store are `Tls.*`'s;
  `IisSnapshotV2` binding equality = `(protocol, bindingInformation, sslFlags)` (O4-N2).
- **ACL target table** (`Operator` = the running principal, journaled):

| Target | Mode | Exact ACE set beyond `SYSTEM` Full, `Administrators` Full (all CI/OI) |
|---|---|---|
| `<InstallRoot>` | Apply | none |
| `<InstallRoot>\web` / `\api` / `\worker` / `\tools` | Apply | Web RX / Api RX / `SibylaWorker` RX / `SibylaWorker` RX |
| `DocsPath` | Apply | `IIS AppPool\Sibyla.Docs` RX, `Operator` Modify |
| `<DataRoot>\staging` / `\ai` / `\work` | Apply | Web+Api+`SibylaWorker` Modify / Web Modify / `SibylaWorker` Modify |
| `KeysPath` | readback-only | Web Modify, `SibylaWorker` Modify |
| `SecretsRoot` and its three leaves | readback-only | root none; each leaf one `Read` for its host identity |
| `D:\ApolloData\worker-claude` | not a target | never read, never applied |

  M = 9 Apply targets; N = 14 snapshot/readback targets. `Acl.Readback` checks the target's own
  ACL exactly; below a target it checks explicit ACEs for `<InstallRoot>` trees and `DocsPath`
  only (explicit `SYSTEM`/`Administrators` tolerated, anything else fails), and never descends
  into the three data folders (O4-N7). Host state 2026-09-03: 0 explicit ACEs below every
  target. `FileSystem.Readback` asserts `appsettings.Production|Development|Preview.json` absent
  from every release folder and `web.config` absent from `DocsPath`.
- **Service** `Sibyla.Worker.Documents`: `binPath` = the worker release exe, `Start = 2` +
  `DelayedAutostart = 1`, failure actions 10 s / 60 s / 300 s (reset 86 400), `Environment`
  exactly the two path assignments. Stop wait 60 s (host `ShutdownTimeout` 30 s).
- **Deploy guard / ownership**: web/api activate only if the current `physicalPath` is under
  `<InstallRoot>`; docs only if it equals `DocsPath` (normalized) and `DocsPath` has no segment
  `GOTT.Sibyla`; the service only if the current `binPath` is under `<InstallRoot>\worker`.
- **Certificates**: the win-acme task runs daily from 09:00 UTC with up to 4 h random delay and a
  2 h limit (window 09:00–15:00 UTC) and rebinds sites 10/11/12; manual `wacs.exe` runs bypass
  it. `CertificateThumbprint` (web) stays an S1 mandatory input, used as given;
  `ApiCertificateThumbprint`/`DocsCertificateThumbprint` optional; the "newest" rule = the
  `WebHosting` certificate with a private key, SAN covering the host, `NotAfter > now + 3 days`,
  greatest `NotBefore`. Renewal safety: `Tls.Apply` is `NoChange` when the bound certificate is
  valid for the host and its `NotBefore` ≥ the requested one's; `Tls.Readback` matches when the
  bound certificate is the requested one or a newer valid one; `Tls.Rollback` is `NoChange` when
  the bound certificate is newer than the snapshot's; `Precondition.Renewal` fails while the task
  is `Running` or a `wacs.exe` process exists. E2 outside the renewal window.
- **Gate commit** under `-Execute`: `FileSystem.GetSnapshot(RepositoryRoot)` reads `.git\HEAD` and
  the ref it names (loose file or packed ref) and compares with `ExpectedCommit`; no git process.

## 3. Contracts (`Sibyla.Deployment.Execution.Contracts.V2`)

`ContractVersionsV2.Current = 2`; `ContractIdentityV2.Require<T>` checks exact type, `ContractName`
and the type's declared version; a V1 or foreign instance → `SIBYLA-S2-CONTRACT-IDENTITY`
(`CONTRACT-VERSION` internal only). Contracts: `ReleaseGateResultV2`, `PublishedArtifactV2`
(the `Precondition.Artifact` receipt: `release`, `commit`, `requiredMigrations`, and per host its
staging tree path, byte size and **one tree hash** — the per-file manifest is computed by the
adapter and is never a receipt field, O8-N2, P9-N1), `InstallRollbackHandleV2` (`ReleasePaths` for `Web`, `Api`, `Worker`;
`SecretsRoot`, `JournalPath`, `TransactionId`), `ConfigureRollbackHandleV2` (three `IisTargetV2`,
one `ScmTargetV2`, `CurrentReleasePaths`), `HealthResultV2` (twelve `HealthCheckV2`),
`DeploymentResultV2` (`Outcome ∈ {Planned, Executed, Failed, RolledBack, RollbackIncomplete}`;
`Failed` = a failure that compensated nothing — a precondition refusal before any `Write`, or a
Health failure under `-NoRollbackOnHealth`, P7-9),
`NativeInvocationResultV2`. Planning types: `NativeCommandIntentV2` (S1's shape: `OrderedArguments`,
`ExpectedResultType`, `MutationKind`, `RequiresElevation`, `DependsOn`; `ExecutionAllowed` = the
mode), the 38 request types of 5.1, `PlannedOperationV2` (role `Forward | Compensation |
CompensationReadback | Fixed`), `DeploymentPlanV2`, `DeploymentPlanCompilerV2`,
`SibylaProductionCommandExecutorV2`, `ISibylaCommandInvokerV2`, `IDeploymentPhasesV2`,
`ISibylaHostProviderV2`, `DeploymentOrchestratorV2`, `DeploymentRuntimeV2`, and the read-only
invoker configuration `SibylaReadOnlyCommandInvokerV2` (the executing invoker with
`CanExecuteMutations = false`, used by `-ChecksOnly`). `HostKind ∈ {Web, Api, Docs, Worker}`
(`Docs` has no release path); `MutationKind` is Core's (`None | Read | Write`). All sealed,
constructor-initialized, get-only. **Cross-phase lineage** (P5-N4): every V2 contract carries
`Plan: DeploymentPlanV2` and `OperationResults` of its phase, exactly as S1's; `PlanLineageValidatorV2`
resolves a `ref` against the current plan and the plans of the contracts actually received;
resume rebuilds those from the journaled receipts. `PlannedOperationV2` carries
`CompensatesIntentId` (derived entries) and `GuardIntentId` (conditional fixed entries only;
P5-L7). **Post-state digests** (O5-7): `MutationReceiptV2.PostState` is per adapter — Process
`(state, ExecutablePath)` (never the pid), Iis `(physicalPath, pool, location attributes,
bindings)` represented compactly as `iis|site|SHA-256(length-framed tuple)` while the snapshot
retains every raw tuple field for lossless rollback, Scm
the five written values, Tls `(hash, store)`, FileSystem the tree hash or file text, Acl the
exact ACE set; every `*.GetSnapshot` produces the same shape, so snapshot, post-state and live
object compare directly.

**Surface of a failed run**: the cmdlet throws through `ErrorBoundaryV2` after the journal is
complete: `SIBYLA-S2-ROLLED-BACK` (carrying the original failing code in `Detail`) for
`RolledBack`, `SIBYLA-S2-ROLLBACK-INCOMPLETE` for `RollbackIncomplete`, the failing code itself
for `Failed`. Outcome → sanitizer state: `Planned → Planned`, `Executed → Executed`, `Failed →
Started`, `RolledBack → RolledBack`, `RollbackIncomplete → RollbackIncomplete`.

## 4. Public surface

Six cmdlets and `.ps1` entry points; every business parameter `[string]`, every switch
`[switch]`, forwarded as `-Name:$Name`; no `[Validate*]`. The oracle is the S1 `entrypoints.json`
amended in full.

| Cmdlet | Parameters added in S2 |
|---|---|
| the five phase cmdlets | `Execute` (switch; always refused) |
| `Invoke-SibylaDeployment` | switches `Execute`, `Force`, `NoRollbackOnHealth`, `ChecksOnly`; `Resume` (`TransactionId`, optional); `JournalRoot` (mandatory); `HealthHostOverride` (optional, `HostOverride`); `RootExpectedStatus` (default literal `200`); `ApiSiteName`, `ApiAppPoolName`, `ApiDnsHostName`, `ApiCertificateThumbprint` (optional), `ApiBaseUri`, `DocsSiteName`, `DocsAppPoolName`, `DocsDnsHostName`, `DocsCertificateThumbprint` (optional), `DocsBaseUri`, `DocsPath`, `SecretsRoot`, `KeysPath`, `DataRoot`, `ApiHealthPath` (`/health`), `ApiReadyPath` (`/health/ready`), `ApiSchemaPath` (`/health/schema`), `DocsProbePath` (`/naming-glossary.md`) |

S1 parameters under `-Execute`: `BackupRoot` validated only (nothing is written under it in S2;
failed copies live under `<InstallRoot>\<host>\.staging`); `WebSecretsPath`/`WorkerSecretsPath`
must equal the D-S2-1 leaves; `CertificateThumbprint` used as given; `BaseUri`, `ChallengePath`,
`IdentityAuthority`, `CallbackUri`, `OidcClientId` feed checks 1–5; all others as S1.

Value objects (pure string checks): `SafeScmName` (D-S2-3), `TransactionId` (`D` format),
`HostOverride` (dotted-quad IPv4 or `DnsHostName`), `ExpectedStatus` (`200|302|403|404`; 403 added 2026-09-10 for the docs root), `mediatype`
(section 5.1 grammar, P9-N4), `DocsPath`
(no `GOTT.Sibyla` segment), the three site names pairwise distinct and the three pool names
pairwise distinct (each set on its own: a site and its pool may share a name, as in production,
P8-N5), none starting `Sibyla.Legacy.` (O7-F7);
`ServiceNameV2` (0.2); `EnvironmentAssignment` (internal; name ∈ `{SIBYLA_SECRETS_FILE,
CLAUDE_CONFIG_DIR}`, value an `AbsoluteWindowsPath`); `HttpsUri` reused with S1's code.
`KnownParameterNamesV2` = S1's nineteen plus the names above; `KnownOperationNamesV2` = the 38
keys plus the phase names.

## 5. Execution

### 5.1 The V2 handler table (`HandlerTableV2.CreateProduction()`, oracle `registry.v2.json`)

Typed independently before B2. `CapabilityPreflightV2.Check(tableV2, invokerV2, mode)`: `Plan`
requires the V2 plan-only invoker (`SupportsIntentValidation`, no `CanExecute*`), an executing
invoker → `SIBYLA-S2-EXECUTION-REFUSED`; `Execute` requires exactly all three capabilities;
`ChecksOnly` requires `SupportsIntentValidation && CanExecuteReads && !CanExecuteMutations`;
anything else `SIBYLA-S2-CAPABILITY-INVOKER`. Mutex descriptor: `Global\GOTT.Apollo.Deployment.v1`
(probes take it on purpose).

**Argument grammar**: `name: family`; families `path` (`AbsoluteWindowsPath`), `name` (a closed
identifier: `ExactGitCommit`, `SafeIisName`, `ServiceNameV2`, task or process name, migration id,
module file name), `host` (`DnsHostName` or `HostOverride`), `uri` (`HttpsUri`), `enum(E)` with
the named enums `HostKind`, `Workload`, `AclTargetKind`, `StopReason {Deployment, RollbackSafety}`,
`ProcessState {Running, Stopped}`, `bool`, `target(T)` (one typed record: `IisTargetV2`,
`ScmTargetV2`, `TlsTargetV2`, `HttpExpectation`, `ProcessTargetV2` = `(Workload, SafeIisName |
ServiceNameV2)` — the pool or service name travels with the workload, P6-1), `set<X>` (a typed set
of `X`, allowed empty only where stated; `AclGrant` = `(AclPrincipal {WebPool, ApiPool, DocsPool,
Worker, Operator}, AclRights {ReadExecute, Modify, Read — `Read` added by the E2 amendment of 2026-09-06 for the secrets leaves})`), `ref<T>` (`ValueRef<T>`), `receipts`
(`ReceiptRefSetV2`: S1's shape, refs to `MutationReceiptV2` or `RollbackReceiptV2`, **empty
allowed where stated**, P6-3), `?` = optional. `AclTargetKind {InstallRoot, WebRoot, ApiRoot,
WorkerRoot, ToolsRoot, DocsPath, Staging, Ai, Work, KeysPath, SecretsRoot, SecretsLeaf,
StagingRoot}` (the section 2 rows plus the artifact root; the readback's descend rule is per
kind, P6-12, P7-2). `HttpExpectation = (status: ExpectedStatus, contentType?: mediatype,
LocationAssertions?: set<LocationAssertion>)` with `mediatype` a value object (`type/subtype`
plus optional `; charset=…`, lower-cased) and `LocationAssertion = (kind ∈ {Authority,
RedirectUri, ClientId, ResponseType, CodeChallengeMethod, CodeChallengePresent}, expected?)` where
`expected` is a `host` for `Authority`, a `uri` for `RedirectUri`, a `name` for `ClientId`, and
the fixed literals `code` / `S256` for the two method kinds; evaluated by the Http adapter into
`Matches` (P7-3, P8-N3). **Invoker timeout**: 300 s per intent, above every adapter budget
(`ADAPTER-TIMEOUT`, P6-8); it is a **cancellation deadline**, never an abandonment: adapters
observe the cancellation token between files, ACEs and registry values, and the invoker never
starts a compensation while a `Write` adapter call is still executing — it waits for the call
to return, bounded by the workload's drain time (90 s for the workload-less `FileSystem`, `Acl`
and `Tls` writes, P8-N6), and a call that still does not return is journaled
`CompensationFailed` for that entry and never compensated concurrently (O7-F2); a fixed recycle
runs when its guard reached `Started` **and its paired `Iis.Rollback` is `Compensated`** (in-run
or on resume) and is `Skipped(NotNeeded)` only while that rollback is `CompensationFailed` — a
`RollbackIncomplete` resume re-evaluates it after the retry (O9-N1, P9-N3); on resume a
`CompensationFailed` entry without a receipt follows the no-receipt rule of section 6 (snapshot,
then intended post-state, else mismatch; O8-N3).
**Elevation**:
every key whose adapter is `Acl`, `Process`, `Iis`, `Scm` or `Tls`, and `FileSystem.PublishTree`,
`SetActiveInstall`, `Rollback`, requires elevation; `Http.*`, `Mutex.*`, `FileSystem.GetSnapshot`,
`FileSystem.Readback`, `Precondition.Artifact|Disk|Schema` do not (P4-F5). **Release-agnostic
plans** (5.7): release-derived values are computed at execution from `Release:
ref<PublishedArtifactV2>` (rows 2, 3, 14, 16, 20, 32, 38); the plan text never contains a release id.

| # | Key | Adapter.Action | Kind | Result | Ordered arguments | Compensation → Readback |
|---|---|---|---|---|---|---|
| 1 | `FileSystem.GetSnapshot` | FileSystem.Read | Read | `FileSystemSnapshotV2` | `Root: path`, `Host: enum(HostKind)?`, `ExpectedCommit: name?`, `Lineage: set<ref<FileSystemSnapshotV2>>` (may be empty) | — |
| 2 | `FileSystem.PublishTree` | FileSystem.Copy | Write | `MutationReceiptV2` | `Release: ref<PublishedArtifactV2>`, `Host: enum(HostKind)`, `HostRoot: path`, `Baseline: ref<FileSystemSnapshotV2>` | 5 → 7 |
| 3 | `FileSystem.SetActiveInstall` | FileSystem.Write | Write | `MutationReceiptV2` | `Release: ref<PublishedArtifactV2>`, `Host: enum(HostKind)`, `HostRoot: path`, `Baseline: ref<FileSystemSnapshotV2>` | 5 → 7 |
| 4 | `Acl.GetSnapshot` | Acl.Read | Read | `AclSnapshotV2` | `Target: path`, `TargetKind: enum(AclTargetKind)` | — |
| 5 | `FileSystem.Rollback` | FileSystem.Restore | Write | `RollbackReceiptV2` | `Snapshot: ref<FileSystemSnapshotV2>`, `ApplyReceipt: ref<MutationReceiptV2>` | — |
| 6 | `Acl.Apply` | Acl.Write | Write | `MutationReceiptV2` | `Target: path`, `Grants: set<AclGrant>`, `ProtectInheritance: bool`, `Snapshot: ref<AclSnapshotV2>` | 8 → 9 |
| 7 | `FileSystem.Readback` | FileSystem.Read | Read | `ReadbackReceiptV2` | `Target: path`, `Receipts: receipts` (may be empty) | — |
| 8 | `Acl.Rollback` | Acl.Restore | Write | `RollbackReceiptV2` | `Snapshot: ref<AclSnapshotV2>`, `ApplyReceipt: ref<MutationReceiptV2>` | — |
| 9 | `Acl.Readback` | Acl.Read | Read | `ReadbackReceiptV2` | `Target: path`, `TargetKind: enum(AclTargetKind)`, `Expected: set<AclGrant>`, `Receipts: receipts` (may be empty) | — |
| 10 | `Process.GetSnapshot` | Process.Read | Read | `ProcessSnapshotV2` | `Target: target(ProcessTargetV2)` | — |
| 11 | `Process.Stop` | Process.Stop | Write | `MutationReceiptV2` | `Target: target(ProcessTargetV2)` (Service only), `Reason: enum(StopReason)`, `Snapshot: ref<ProcessSnapshotV2>` | 13 → 14 (`Deployment`); none (`RollbackSafety`) |
| 12 | `Process.Start` | Process.Start | Write | `MutationReceiptV2` | `Target: target(ProcessTargetV2)` (Service only), `Snapshot: ref<ProcessSnapshotV2>` | 11(`RollbackSafety`) → 14 (the derived compensation; the guard "reached `Started`" is the standard `DependsOn` rule, P4-F3) |
| 13 | `Process.Rollback` | Process.Restore | Write | `RollbackReceiptV2` | `Snapshot: ref<ProcessSnapshotV2>`, `ApplyReceipt: ref<MutationReceiptV2>` | — |
| 14 | `Process.Readback` | Process.Read | Read | `ReadbackReceiptV2` | `Target: target(ProcessTargetV2)`, `Expected: enum(ProcessState)?`, `Snapshot: ref<ProcessSnapshotV2>?` (exactly one of `Expected`/`Snapshot`: the readback of a rollback compares with the snapshot state), `Release: ref<PublishedArtifactV2>?`, `LiveIis: ref<IisSnapshotV2>?`, `LiveScm: ref<ScmSnapshotV2>?` (ChecksOnly: the activated path comes from the live snapshot), `ExpectedModule: name?` (`Sibyla.Web.dll` for `Pool(Web)`, `Sibyla.Api.dll` for `Pool(Api)`), `Receipts: receipts` (may be empty) | — |
| 15 | `Iis.GetSnapshot` | Iis.Read | Read | `IisSnapshotV2` | `Target: target(IisTargetV2)` | — |
| 16 | `Iis.Apply` | Iis.Write | Write | `MutationReceiptV2` | `Target: target(IisTargetV2)`, `Release: ref<PublishedArtifactV2>?` (absent for docs), `Snapshot: ref<IisSnapshotV2>` | 17 → 18 |
| 17 | `Iis.Rollback` | Iis.Restore | Write | `RollbackReceiptV2` | `Snapshot: ref<IisSnapshotV2>`, `ApplyReceipt: ref<MutationReceiptV2>` | — |
| 18 | `Iis.Readback` | Iis.Read | Read | `ReadbackReceiptV2` | `Target: target(IisTargetV2)`, `Receipts: receipts` | — |
| 19 | `Scm.GetSnapshot` | Scm.Read | Read | `ScmSnapshotV2` | `Target: target(ScmTargetV2)` | — |
| 20 | `Scm.Apply` | Scm.Write | Write | `MutationReceiptV2` | `Target: target(ScmTargetV2)`, `Release: ref<PublishedArtifactV2>`, `Snapshot: ref<ScmSnapshotV2>` | 21 → 22 |
| 21 | `Scm.Rollback` | Scm.Restore | Write | `RollbackReceiptV2` | `Snapshot: ref<ScmSnapshotV2>`, `ApplyReceipt: ref<MutationReceiptV2>` | — |
| 22 | `Scm.Readback` | Scm.Read | Read | `ReadbackReceiptV2` | `Target: target(ScmTargetV2)`, `Receipts: receipts` | — |
| 23 | `Tls.GetSnapshot` | Tls.Read | Read | `TlsSnapshotV2` | `Target: target(TlsTargetV2)` | — |
| 24 | `Tls.Apply` | Tls.Write | Write | `MutationReceiptV2` | `Target: target(TlsTargetV2)`, `Snapshot: ref<TlsSnapshotV2>` | 25 → 26 |
| 25 | `Tls.Rollback` | Tls.Restore | Write | `RollbackReceiptV2` | `Snapshot: ref<TlsSnapshotV2>`, `ApplyReceipt: ref<MutationReceiptV2>` | — |
| 26 | `Tls.Readback` | Tls.Read | Read | `ReadbackReceiptV2` | `Target: target(TlsTargetV2)`, `Receipts: receipts` | — |
| 27 | `Http.GetNoRedirect` | Http.Get | Read | `HttpResponseEvidenceV2` (`Matches`, status, `Location` kept keys, content type, body sha256; no body) | `Uri: uri`, `Expectation: target(HttpExpectation)`, `HostOverride: host?` | — |
| 28 | `Mutex.Acquire` | Mutex.Acquire | None | `MutexLeaseReceiptV2` (`Acquired`, `Abandoned`) | `Descriptor: name` | — (fixed 29) |
| 29 | `Mutex.Release` | Mutex.Release | None | `MutexLeaseReceiptV2` | `Lease: ref<MutexLeaseReceiptV2>` | — |
| 30 | `Process.Recycle` | Process.Recycle | Write | `RecycleReceiptV2` | `Target: target(ProcessTargetV2)` (`Pool(Web)`/`Pool(Api)` only), `Snapshot: ref<ProcessSnapshotV2>` — a `Started` pool is recycled (overlapped), a `Stopped` pool is **started** (O4-N1) | none (its own undo); no readback of its own — Health's pool readbacks (checks 6 and 12) verify the served release |
| 31 | `Precondition.Artifact` | FileSystem.Read | Read | `PublishedArtifactV2` (`Satisfied`) | `StagingRoot: path`, `ExpectedCommit: name` | — |
| 32 | `Precondition.Disk` | FileSystem.Read | Read | `PreconditionReceiptV2` | `InstallRoot: path`, `JournalRoot: path`, `Release: ref<PublishedArtifactV2>` (artifact bytes) | — |
| 33 | `Precondition.Ownership` | Precondition.Read (delegates to the Iis or Scm adapter by `Workload`) | Read | `PreconditionReceiptV2` | `Target: target(ProcessTargetV2)`, `Site: name?` (present iff the workload is a pool — bound to the matching site-name parameter — else `SIBYLA-S1-INTENT-ARGUMENT`, P9-N2, O9-N2), `ExpectedUnder: path` — for a pool the Iis adapter resolves every application of every site using the named pool: exactly one, and it must be the root application of `Site` (any other application or site on that pool, zero, or several → `PRECONDITION-OWNERSHIP`; the module never re-pools a site, O7-F7, P8-N2, O8-N4); also requires `Pool(Web)`/`Pool(Api)` to be `Started` (a deliberately stopped production pool is never deployed over, O5-8); a workload/name mismatch inside `ProcessTargetV2` is `SIBYLA-S1-INTENT-ARGUMENT` (P7-1) | — |
| 34 | `Precondition.Binding` | Iis.Read | Read | `PreconditionReceiptV2` | `Hosts: set<host>`, `Sites: set<name>` | — |
| 35 | `Precondition.Certificate` | Tls.Read | Read | `PreconditionReceiptV2` | `Target: target(TlsTargetV2)` | — |
| 36 | `Precondition.Renewal` | Process.Read | Read | `PreconditionReceiptV2` | `TaskName: name`, `ProcessName: name` | — |
| 37 | `Precondition.ScmEnvironment` | Scm.Read | Read | `PreconditionReceiptV2` | `Target: target(ScmTargetV2)` | — |
| 38 | `Precondition.Schema` | Http.Get | Read | `PreconditionReceiptV2` (`Observed` carries the ≤ 4 KiB redacted body) | `Uri: uri`, `Release: ref<PublishedArtifactV2>?` (its `requiredMigrations`), `LiveIis: ref<IisSnapshotV2>?` (ChecksOnly: the Http adapter reads `MANIFEST.json` below the API snapshot's exact `physicalPath`; exactly one of `Release`/`LiveIis`), `HostOverride: host?` | — |

`Workload ∈ {Pool(Web), Pool(Api), Pool(Docs), Service}`; `AclTargetKind` as defined in the
grammar. Adapter behaviours the oracle fixes: `PublishTree` copies into
`<HostRoot>\.staging\<release>.partial` and renames into place; an existing complete target whose
tree hash equals the artifact's is `Succeeded(NoChange)`; a leftover `.partial` is renamed
`.failed-<txid>` first; the compensation of `PublishTree` renames the target into
`.staging\<release>.failed-<txid>`, and **the compensation of a `NoChange` receipt is a `NoChange`**
(a folder present in the `Baseline` snapshot is never renamed); `Iis.Apply` never creates a pool
and `Iis.*` never writes a binding; `Iis.Rollback` restores `physicalPath`, pool and `<location>`
attribute by attribute; `Scm.GetSnapshot` records `Environment` name+value and opens only the
mandated key; `Process.Rollback(Service)` compares state and `ExecutablePath` (Running from another
path is stopped and started); `Process.Readback(Service, Running)` = same pid ≥ 20 s with the
expected path; `Process.Readback(Pool)` = the newest w3wp of the pool has `ExpectedModule` from the
expected release loaded; `Http.GetNoRedirect` retries every 5 s within 90 s until the expected
status and answers `Matches = false` when the budget is exhausted (never `ADAPTER-TIMEOUT`,
P5-L12); the `.failed-<txid>` rename retries every 5 s within the host's drain time — the pool
`shutdownTimeLimit` (90 s) for web/api, the service stop wait (60 s) for worker — before
`CompensationFailed`, because a draining w3wp or the stopping worker may still map the release's
dlls (O5-4, O6-N6); `Scm.Apply`/`Scm.Rollback` write the five registry values one by one and
the resume comparison is per value (each at snapshot or at intended → compensate; any third value
→ `JOURNAL-MISMATCH`), and C2 proves `ServiceController.Start()` honours a registry-written
`ImagePath` without a reboot (O5-5); `SetActiveInstall` writes the text files as temp + atomic
rename (O5-6); `Mutex.Acquire` treats an abandoned mutex as acquired (`Abandoned = true`, journal
warning) and answers `Acquired = false` after 30 s; `Mutex.Release` is idempotent.

### 5.2 The phase-allocation table (order oracle `execution-order.json`)

Forward order within each phase. Compensation entries: one `*.Rollback` + readback per `Write`
forward intent, in the order the table gives (Install: reverse forward; Configure: as listed,
`Tls.Rollback` last; Health: as listed); exempt from the rule are `Process.Recycle` (its own undo)
and `Process.Start` (compensated by `Process.Stop(RollbackSafety)`, its derived compensation).
**Fixed entries** (role `Fixed`, `CompensatesIntentId = null`): Install's `Mutex.Release`;
Configure's conditional `Process.Stop(RollbackSafety, Service)` and the two conditional
`Process.Recycle`s — **four** in the one-shot plan.

| Phase | Forward operations | Compensation appended |
|---|---|---|
| Gate | `FileSystem.GetSnapshot` (repository root, commit) | none |
| Publish | `Precondition.Artifact`; `FileSystem.GetSnapshot` ×3 (artifact trees web, api, worker); `Acl.GetSnapshot` (`StagingRoot`) | none |
| Install | `Mutex.Acquire`; `Precondition.Renewal`, `.Disk`, `.Ownership` ×4, `.Binding`, `.Certificate` ×3, `.ScmEnvironment`, `.Schema` (against the running API); `FileSystem.GetSnapshot` ×3 (host folders); `Acl.GetSnapshot` ×14; `Process.GetSnapshot` ×3 (`Pool(Web)`, `Pool(Api)`, `Service`; the docs pool is never touched, so never snapshotted, P6-12); `FileSystem.PublishTree` ×3; `Acl.Apply` ×9; `FileSystem.SetActiveInstall` ×3; `FileSystem.Readback` ×3; `Acl.Readback` ×14 — Install never touches a process | `FileSystem.Rollback`+`Readback` ×3 (SetActiveInstall); `Acl.Rollback`+`Readback` ×9; `FileSystem.Rollback`+`Readback` ×3 (PublishTree); fixed `Mutex.Release` |
| Configure | `Precondition.Renewal`; `Iis.GetSnapshot` ×3, `Scm.GetSnapshot`, `Tls.GetSnapshot` ×3; `Iis.Apply(web)`, `Process.Recycle(web)`, `Iis.Apply(api)`, `Process.Recycle(api)`, `Iis.Apply(docs)`; `Tls.Apply` ×3; `Process.Stop(Deployment, Service)`; `Scm.Apply`; `Iis.Readback` ×3, `Tls.Readback` ×3, `Scm.Readback` | fixed conditional `Process.Stop(RollbackSafety, Service)` (only when `Scm.Apply` reached `Started`); `Scm.Rollback`+`Readback`; `Process.Rollback(Service)`+`Readback`; `Iis.Rollback(docs)`+`Readback`; `Iis.Rollback(api)`+`Readback`+fixed conditional `Process.Recycle(api)` (only when `Iis.Apply(api)` reached `Started`); `Iis.Rollback(web)`+`Readback`+fixed conditional `Process.Recycle(web)` (only when `Iis.Apply(web)` reached `Started`); `Tls.Rollback`+`Readback` ×3 last |
| Health | `Process.Start(Service)`, `Process.Readback(Service)`; **Http 1 (`<BaseUri>/`) first, then** `Process.Readback(Pool web)` (an in-process site without preload loads its dll on the first request, O5-1); Http 2; Http 3, then `Process.Readback(Pool api)`; Http 4–7; `Precondition.Schema`; `Mutex.Release` | `Process.Stop(RollbackSafety, Service)`+`Readback` (derived from `Process.Start`) |
| ChecksOnly (a separate plan) | `Iis.GetSnapshot` ×3, `Scm.GetSnapshot`; `Process.Readback(Service)` with `LiveScm` bound to the SCM snapshot; Http 1, then `Process.Readback(Pool web)` with `LiveIis` bound to the web snapshot; Http 2; Http 3, then `Process.Readback(Pool api)` with `LiveIis` bound to the api snapshot; Http 4–7; `Precondition.Schema` with `LiveIis` bound to the api snapshot so it reads that exact active path's `MANIFEST.json`; every `Receipts` empty | none (no mutex, no mutation) |

Rules: the docs pool is never recycled, stopped or snapshotted; the worker is stopped as late as
possible and never touched by Install; after any rollback out of any phase the web and api pools
are `Started` on the snapshot release and the service is in its snapshot state (B2 test); a
conditional fixed entry whose guard is false is `Skipped(NotNeeded)`; a pool recycle follows the
web/api site's `Iis.Apply`/`Iis.Rollback`.

### 5.3 Executing invoker rules (`execution-semantics.json`)

- One intent at a time in plan order; `Started` journaled and fsynced before the adapter call;
  the terminal disposition journaled and fsynced after.
- **Domain outcomes are typed, never thrown**: `Satisfied = false` (preconditions), `Matches =
  false` (readbacks, `Http.GetNoRedirect`), `Acquired = false` (mutex) make the intent `Failed`
  with the key's code (8); an adapter exception is `ADAPTER-FAILED`, a timeout `ADAPTER-TIMEOUT`, a
  redaction violation `REDACTION`.
- **No-ops are successes**: `Succeeded` with `NoChange = true`. `Skipped` is reserved for entries
  that do not run: `NotReached` (forward after a failure; a `Read`/`None` intent found `Started`
  without a terminal line on resume), `NotNeeded` (compensation entries of a run that did not
  fail; conditional fixed entries whose guard is false).
- `DependsOn`: satisfied by a `Succeeded` result, or, for a compensation entry, by the `Failed`
  forward intent it compensates (its receipt is the failed receipt) plus its `Succeeded`
  snapshot. Otherwise `Skipped(NotReached)`.
- Cross-phase: the orchestrator runs a phase's forward list; on success it holds that phase's
  compensation list; on a failure it runs the failing phase's list, then the held lists of the
  earlier phases. `OperationResults` is plan-sized. A failure with no `Write` intent `Succeeded`
  in any phase is `Outcome = Failed` (nothing to compensate; the fixed `Mutex.Release` still runs).
- **Fixed entries** (P5-N2): Install's `Mutex.Release` runs on every path. Every other fixed entry
  (Configure's conditional safety stop and the two conditional recycles) runs only when its held
  list runs for a rollback **and** its guard intent (`GuardIntentId`, section 3) reached `Started`;
  on a successful run and under `-NoRollbackOnHealth` they are `Skipped(NotNeeded)`. Both cases
  are B2 tests. The compensation link of a derived entry is `CompensatesIntentId`; `DependsOn`
  carries only its `ValueRef` sources.
- A compensation that fails is journaled `CompensationFailed`; the run continues. Outcome
  `RolledBack` iff no `CompensationFailed` line; else `RollbackIncomplete` listing what stands.
  Rollbacks are idempotent by construction (readback first, `NoChange`).
- Receipt type must equal `ExpectedResultType` (`SIBYLA-S2-INVOKER-RESULT`).
- `-NoRollbackOnHealth`: a failed Health phase triggers no compensation; Health's forward
  `Mutex.Release` is `Skipped(NotReached)` and Install's **fixed** `Mutex.Release` still runs
  (fixed entries are not compensation); the outcome is `Failed`, the `HEALTH-n` code is thrown,
  the sanitizer state is `Started`, and the journal trailer carries `NoRollbackOnHealth` (P6-2).
- The readback of a compensation of `Process.Start` (the derived `Process.Stop(RollbackSafety)`)
  is bound with `Expected = Stopped`, not with the snapshot (P6-5). When one HTTP intent feeds
  several checks, an unmet expectation fails with the **lowest-numbered** unmet check's code
  (P6-6).
- `SIBYLA-S2-JOURNAL-IO`: no further forward intent; compensation continues best-effort and
  unjournaled; outcome `RollbackIncomplete` with the list on the console.

### 5.4 Publish under `-Execute`

The module never builds. `Precondition.Artifact` verifies `<StagingRoot>\release.json` (release
id by regex, `commit = ExpectedCommit`, `dirty = false`, `requiredMigrations` present) and the
three artifact trees, and its receipt **is** `PublishedArtifactV2`; `local\publish-release.ps1`
writes `requiredMigrations` in A2.

### 5.5 `Precondition.Schema`

`Sibyla.Api` gains `GET /health/schema` (anonymous): `{ "role": "<current_user>", "migrations":
[...] }`; a C-row in `apollo-channel-intake-api-spec.md` and one contract test (A2); disclosure
accepted. The precondition passes when the body lists every required id; a 404 fails it like any
other answer. It runs in Install against the running API and in Health against the new one. Under
ChecksOnly, the earlier API `Iis.GetSnapshot` supplies the live physical path and the Http adapter
reads `MANIFEST.json` below that exact path; it never guesses a release from the install root or a
marker file. The hand path deploys the A2 API before D2.

**Observed value (D-S2-7, 2026-09-04).** The receipt's `Observed` is rendered from the parsed
values, never from the body: `role=ok|mismatch migrations=<count> sha256=<hex of the body>`
followed by ` overlimit=true` when the body exceeded four KiB and by ` missing=<n>` when `n`
required ids are absent. The body itself is not a receipt field; the digest pins the exact answer
the check saw and the operator reads the ids from `/health/schema`. Section 8's render and secret
patterns still apply to that text, which by construction contains no free text.

### 5.6 The V2 plan-only invoker

`SibylaPlanOnlyCommandInvokerV2` answers `Disposition = Planned`; `-Execute -WhatIf` runs the
whole V2 pipeline with it and renders every release-derived argument as its `ref` (5.7).

### 5.7 Compile timing (P4-F6)

Compilation is per phase, as in S1: each phase compiles its own plan from the contracts it
receives; the next contract is built from the receipts. Plans are **release-agnostic**: rows 2,
3, 14, 16, 20, 32, 38 take `Release: ref<PublishedArtifactV2>` and derive paths, ids and
migration lists at execution from that receipt. The journal carries one plan digest **per phase**,
appended when that phase compiles; `-Resume` recompiles phase by phase, rebuilding each contract
from the journaled receipts, and requires every phase digest to match.

## 6. Journal and resume

`<JournalRoot>\<transactionId>.jsonl`, append-only. Header: `transactionId`, module version,
switches, `Operator`; per phase a digest line (SHA-256 over `(phase, role, operationName, ordinal,
ordered argument names, rendered values)` with every `ValueRef` rendered as
`(sourcePhase, sourceOperationName, sourceOrdinal)`, P5-L9); per intent `Started`, then
`Succeeded | Failed` — the `Succeeded` line carries the receipt's redacted rendered fields, from
which resume rebuilds contracts; compensation outcomes as `Compensated | CompensationFailed`
lines keyed on the forward's `(phase, operationName, ordinal)`; a trailer line with the
`DeploymentResultV2` outcome.

`-Resume <transactionId>` (with `-Execute`): recompiles phase by phase from the journaled
receipts, requires each digest to match (`SIBYLA-S2-JOURNAL-MISMATCH`), re-executes
`Mutex.Acquire`/`Mutex.Release` as its own bracket (the one exception to "never re-runs forward
intents", P5-L10), then walks
the compiled compensation lists in plan order (the failing phase's, then the held ones). For each
compensation entry whose forward is journaled `Succeeded` without `Compensated`: read the live
object and hand the comparison to the **adapter's own rollback rule**: a live state the rollback
treats as at-snapshot or no-op (a newer valid certificate for `Tls`, a folder present in the
baseline for `FileSystem`) answers `NoChange`; a live state equal to the receipt's post-state
digest is compensated; anything else is `JOURNAL-MISMATCH` for that entry, never overwritten,
`-Force` cannot override. `Process.*` entries wait out a pending transition (up to the stop wait)
before comparing. A `Started` line without a terminal line, **or a `Write` journaled `Failed`
without a `Compensated`/`CompensationFailed` line** (the run died before compensating a partial
mutation, O7-F6): a `Read`/`None` intent → `Skipped(NotReached)`; a `Write` intent is handled by
the same adapter rule against the snapshot, then against the intended post-state derived from
its arguments; else `JOURNAL-MISMATCH`. For
`PublishTree` the compared object is `<host>\<release>`; a `.partial` counts as snapshot-equal and
is renamed `.failed-<txid>`. A journal in which every forward intent other than `Mutex.Acquire`
and `Mutex.Release` is `Succeeded` and no `Write` is `Started` without a terminal line (the run
died after `Precondition.Schema` had `Succeeded`; a run that died *during* it rolls back, O7-F5)
is a **completed deployment**: resume writes the trailer
`Executed` and compensates nothing (O5-2, P6-4). A journal that already carries a trailer (O6-N2):
`Executed`, `RolledBack` or plain `Failed` → resume refuses (`SIBYLA-S2-JOURNAL-MISMATCH`, O7-F4);
`RollbackIncomplete` → resume retries only the entries journaled `CompensationFailed` and then
re-evaluates the conditional fixed entries whose guard reached `Started` (P9-N3); `Failed`
with `NoRollbackOnHealth` → resume runs the full compensation (the intended way to roll back
later), **re-evaluating the conditional fixed entries from their guard intent's journaled
`Started`** — their `Skipped(NotNeeded)` lines are not terminal for resume — so both pools are
recycled onto the snapshot release (O7-F3); the B2 test asserts the recycles ran and the pools
serve the snapshot release. Resume never re-runs forward intents (the mutex
bracket excepted). The hand-path scripts and win-acme take no mutex (10).

## 7. Health (oracle `health.v2.json`)

| # | Check | Fed by | Expectation |
|---|---|---|---|
| 1 | `WebRootAnswers` | Http 1: `<BaseUri>/` | `RootExpectedStatus` |
| 2 | `ChallengeReturnsExactly302` | Http 2: `<BaseUri><ChallengePath>` | 302 |
| 3 | `LocationTargetsExpectedAuthorityAndCallback` | Http 2 | `Location` authority = `IdentityAuthority`'s host, `redirect_uri` = `CallbackUri`, `client_id` = `ClientId` (the S1 parameter; value object `OidcClientId`) |
| 4 | `ResponseTypeIsCode` | Http 2 | `response_type=code` |
| 5 | `PkceChallengePresentWithS256` | Http 2 | `code_challenge_method=S256`, nonempty `code_challenge` |
| 6 | `WebProcessServesActivatedRelease` | `Process.Readback(Pool web)` | the newest w3wp has the activated `Sibyla.Web.dll` loaded |
| 7 | `WorkerServiceRunsActivatedRelease` | `Process.Readback(Service)` | same pid ≥ 20 s, `ExecutablePath` = activated exe |
| 8 | `ApiHealthAnswers` | Http 3: `<ApiBaseUri><ApiHealthPath>`; Http 4: `<ApiReadyPath>` | 200, 200 |
| 9 | `ApiSchemaMatchesRelease` | `Precondition.Schema` (its own GET of `<ApiSchemaPath>`) | body lists the required migrations |
| 10 | `DocsServesMarkdown` | Http 5: `<DocsBaseUri>/`; Http 6: `<DocsProbePath>` | 403 (amended 2026-09-10: files by known name only, folder listing off — was 200 while listing was on); 200 with `text/markdown; charset=utf-8` |
| 11 | `DocsHidesRepositoryInternals` | Http 7: `<DocsBaseUri>/.git/HEAD` | 404 |
| 12 | `ApiProcessServesActivatedRelease` | `Process.Readback(Pool api)` after Http 3 | the newest w3wp has the activated `Sibyla.Api.dll` loaded (P5-L4, O5-9) |

Twelve checks; seven `Http.GetNoRedirect` intents. Checks 3–5 are pure predicates over Http 2's
`Location`, its kept query keys (`client_id`, `redirect_uri`, `response_type`,
`code_challenge_method`) rendered as separate `Observed` fields. Order in the plan: Http 1 before
the web pool readback, Http 3 before the api pool readback (an in-process site loads its dll on
the first request). An unmet expectation is `Matches = false` → `Failed` with `HEALTH-<n>` (8).
`HealthHostOverride` connects to that address with the site's host name as SNI and `Host` header.

## 8. Error codes, sanitizer, redaction

`FailureCodesV2` = the S2 table plus the complete S1 allowlist (the V2 compiler, preflight,
lineage and identity checks reuse S1's codes). `DeploymentFailureV2`/`ErrorBoundaryV2` in
Execution render them with `KnownParameterNamesV2`/`KnownOperationNamesV2`; `sanitizer.v2.json`
pattern `^SIBYLA-S[12]-[A-Z0-9-]+$` (digits for `HEALTH-10…12`, P6-7), categories `Input | Contract | Capability | Intent | Invoker |
Orchestration | Precondition | Readback | Health | Adapter | Journal | Rollback | Internal`,
states `Created | Validated | Compiled | Planned | Started | Executed | RolledBack |
RollbackIncomplete`.

| Code (`SIBYLA-S2-`) | Category | Producer |
|---|---|---|
| `EXECUTION-REFUSED` | Capability | a phase cmdlet with `-Execute`; an executing invoker under `Plan` |
| `EXECUTION-UNCONFIRMED` | Input | the one-shot under `-Execute` without Confirm/`-Force`, non-interactive |
| `CAPABILITY-INVOKER` | Capability | `CapabilityPreflightV2` mismatch |
| `CONTRACT-IDENTITY` / `CONTRACT-VERSION` | Contract | `ContractIdentityV2` / internal constructors |
| `INPUT-TRANSACTION-ID`, `INPUT-HOST-OVERRIDE`, `INPUT-EXPECTED-STATUS`, `INPUT-DOCS-PATH`, `INPUT-IIS-NAME`, `INPUT-SWITCHES`, `INPUT-SECRETS-PATH` | Input | the value objects and rules of section 4 (`INPUT-ENVIRONMENT` and `INPUT-SERVICE-NAME` are internal: no entry point can reach them) |
| `PRECONDITION-ARTIFACT|DISK|OWNERSHIP|BINDING|CERT|RENEWAL|SCM-ENV|SCHEMA` | Precondition | the eight `Precondition.*` keys (`Satisfied = false`) outside the Health and ChecksOnly plans |
| `READBACK-FILESYSTEM|ACL|PROCESS|IIS|SCM|TLS` | Readback | the six `*.Readback` keys (`Matches = false`) outside the Health and ChecksOnly plans |
| `HEALTH-1` … `HEALTH-12` | Health | **in the Health and ChecksOnly plans, every intent that feeds a check fails with the check's code**, which overrides the key's own (`READBACK-PROCESS` for checks 6, 7, 12; `PRECONDITION-SCHEMA` for check 9; P5-N1) |
| `ADAPTER-TIMEOUT`, `ADAPTER-FAILED` | Adapter | the executing invoker around an adapter call |
| `REDACTION` | Adapter | `Redaction.Render` |
| `INVOKER-RESULT` | Invoker | receipt type mismatch |
| `MUTEX-BUSY` | Adapter | `Mutex.Acquire` (`Acquired = false`) |
| `JOURNAL-IO`, `JOURNAL-MISMATCH` | Journal | the journal writer; resume |
| `ROLLED-BACK`, `ROLLBACK-INCOMPLETE` | Rollback | `ErrorBoundaryV2` for those outcomes |

Redaction: the S1 path patterns apply to error surfaces only (`[R3-A2]`). Journal lines,
`Detail` and `Observed` go through `Redaction.Render` (allowed `[A-Za-z0-9 ._:/\\=+-]`, others
`?`, ≤ 512; then the secret-value patterns `password`, `pwd=`, `token`, `secret=`,
`connectionstring` and any newline/tab must be absent → `SIBYLA-S2-REDACTION`). The ≤ 4 KiB body
read by `Precondition.Schema` is rendered the same way into its `Observed`. **Receipt fields on a
successful schema check budget that already-sanitized `Observed` by its final escaped-leaf cost;
the complete body is still parsed and compared before display truncation.** **Receipt fields on a
`Succeeded` line are rendered losslessly** (O6-N4, O7-F1, P8-N1, P8-N4): every character outside
the allowed set, **and the backslash itself (`\`)**, is escaped as `\uXXXX` (never
substituted), so the rendering is injective; the 512-character cap is **per scalar leaf** —
set- and list-valued members (a host folder's release list, an ACE set, a migration list) render
one leaf per element with no cap on the element count — and a leaf that would exceed it fails
the intent with `SIBYLA-S2-REDACTION`; the secret-value patterns and the newline/tab ban still
apply to the escaped text. The production literals (`SIBYLA_SECRETS_FILE=…`,
`CLAUDE_CONFIG_DIR=…`, `*:443:<host>`, the OIDC query keys, a 14-ACE set, a host-folder snapshot
with 50 releases, a `PublishedArtifactV2`) therefore round-trip; a B2 test renders every literal
of section 2 and those two synthetic cases through the receipt path and asserts no `REDACTION`
and exact reconstruction: the decoder maps every `\uXXXX` back to its character and accepts
nothing else after a backslash, so `decode(render(x)) == x` for every receipt field (O8-N1).

## 9. Sub-slices, oracles, evidence, review

| Sub-slice | Content | RED oracle (typed before code) |
|---|---|---|
| A2 | V2 contracts and planning types in Execution; switches and value objects (`ServiceNameV2`); `CapabilityPreflightV2`; `DeploymentFailureV2`/`ErrorBoundaryV2`; the S1 oracle amendments of 0.2; `/health/schema` in `Sibyla.Api` with its contract test and the API spec C-row; `publish-release.ps1` writes `requiredMigrations`, `deploy-release.ps1` copies it into `MANIFEST.json`. **Delivered 2026-09-03** on `ops/sibyla-deployment-slice2-a2` (RED `evidence/A2-red.txt` fingerprint `eae84452…d739b1de` over 164 files, 529 of 1036 failing incl. the 96 predicted S1 failures, scaffold only; GREEN `evidence/A2-green.txt` fingerprint `a4935d62…253d6f6b` over 180 files, 1036/1036 with the S1 585, API 46/46). Additions the row did not name, recorded there: `validators.v2.json` (the section 4 value objects) and the A2 part of `registry.v2.json` (the 38 descriptors, typed from 5.1 alone); the executing invoker does not exist yet, so every `-Execute` path is refused after the preflight (`SIBYLA-S2-EXECUTION-REFUSED`); migration `SchemaHealthGrant` was authored and applied before Phase D and therefore names the historical role `apollo_api`. PostgreSQL carried Main's grant to the renamed role by OID; on a fresh Phase-D database the guarded historical block skips and `db/channel-intake-api-role.sql`, applied by `local/setup-db.ps1`, grants `SELECT` on `__EFMigrationsHistory` to `sibyla_api`. Per the owner's post-checkpoint ruling, applied migration text remains immutable and no narrow follow-up migration is added; see the D2 row. Checkpoint review after B2. | `validators.json`, `entrypoints.json`, `forbidden.json` (amended); `forbidden.v2.json`, `sanitizer.v2.json` |
| B2 | executing invoker and orchestrator (net10 xUnit, fake adapters): 5.2 order incl. ChecksOnly, 5.3 semantics, 5.7 per-phase compile and digests, journal, resume, pools and service in snapshot state after any rollback, `-Execute -WhatIf`. **Delivered 2026-09-03** on `ops/sibyla-deployment-slice2-b2` (RED `evidence/B2-red.txt` fingerprint `318ef4da…750242ee` over 201 files, 184 of 1210 failing: the 177 B2 behaviour tests on the scaffold and the 7 A2 tests the B2 outcomes replace, every first-run pass structural; GREEN `evidence/B2-green.txt` fingerprint `e488195e…b532b7` over 206 files, 1208/1208 with the S1 585, API 46/46, `local\test.ps1` five suites green). Additions the row did not name, recorded there: `ChecksOnlyResultV2` as the seventh contract and `Detail` on `DeploymentFailureV2` (section 3), the eight truth-table rows with their B2 outcomes, eight test-side corrections and five engine readings listed in the evidence notes (the fixed-entry pairing, the RollbackIncomplete retry of fixed entries, compensation unjournaled after JOURNAL-IO, the digest over the typed targets, a dedicated thread per adapter call); the production runtime wires no adapter until C2, so `-Execute -WhatIf` previews and every executing path fails closed at the first adapter call (`SIBYLA-S2-ADAPTER-FAILED`) after the preflight and the journal-root check. **Checkpoint review A2+B2 held 2026-09-03** (`evidence/CHECKPOINT-A2B2-review.md`): both reviewers ACCEPT at the bar (P: Medium 3, Low 3; O: Medium 4, Low 2); the findings are answered in the revision `2e60fd7` (fingerprint `0853de1a…2e071` over 206 files from a clean export; deployment suite 1213/1213; four oracle cases and one invoker rule added, every new test replayed against the pre-revision code), except O1 (the `SchemaHealthGrant` migration names `apollo_api`), an owner decision recorded for D2. Re-reviews of the revision: both ACCEPT (P Medium 0 / Low 2, O Medium 1 / Low 1); the second revision `e1f43cd` + `49a8618` (fingerprint `97fbc290…796d` over 206 files, 1215/1215) closes O's N1 (the safety stop is not its own undo: it never re-runs on a retry resume, and a failed stop healed by the service's `Process.Rollback` is no `CompensationFailed`), O's N2 and P's two Lows, and meets O's two conditions on O1 (the D2 precondition below, the corrected A2 sentence above). **Checkpoint closed 2026-09-03: both reviewers confirm the second revision with Critical 0, High 0, Medium 0, Low 0**; O1 carried to D2 as the owner's decision; both reviewers' C2 notes are in the review record. | `registry.v2.json` (independent author), `execution-order.json`, `execution-semantics.json`, `health.v2.json` |
| C2 | the eight adapters (PS 5.1 probes, run elevated: the probe runner spawns `powershell.exe` with `runas`), exercised **at adapter level** — the harness builds the typed arguments through Execution's interfaces (`ServiceNameV2("ZZ.Sibyla.Probe.Service")` included); no entry point — on disposable targets: pools and sites `ZZ.Sibyla.Probe.{Web,Api,Docs}` bound `*:8443:zz-{web,api,docs}.sibyla.probe` (SNI; port 8443 free on this host) with a self-signed certificate in `WebHosting` (the Http adapter pins that thumbprint when the harness says so, validates the chain otherwise); service `ZZ.Sibyla.Probe.Service` from a **stub host built by the test project** (it loads a dll named as `ExpectedModule` for the pool probes) running as `NT AUTHORITY\LocalService`, start Manual; folders `C:\Apps\ZZ.Sibyla.Probe`, `D:\ApolloData\ZZ.Sibyla.Probe`; the production mutex; `HostOverride 127.0.0.1`. Harness: `Backup-WebConfiguration` first (**restore is manual only; the harness never calls `Restore-WebConfiguration`** and removes its backup in `finally`, O4-N8), pre-clean of any `ZZ.*` leftovers (sites, pools, service, folders, `zz-*.sibyla.probe` http.sys entries, the probe thumbprint), clean in `finally`, assert afterwards that `applicationHost.config` minus `ZZ.*`, the sslcert list minus `*.sibyla.probe` and `WebHosting` minus the probe thumbprint are unchanged — **compared by hash and element path only; a failing assertion never prints attribute values** (the legacy pools' environment variables in that file carry a connection string, O5-3). A source-grep test proves that no production `.ps1`, default, or source under Core, Cmdlets, Execution or Adapters.Windows references `ZZ.`, with exactly one exemption: the `ServiceNameV2.ProbeServiceName` constant in `Execution/Inputs/ValueObjectsV2.cs` (P4-F1, P5-L11). **Delivered 2026-09-03** on `ops/sibyla-deployment-slice2-c2`: RED `evidence/C2-red.txt` fingerprint `5cc72fcf…6370db` over 210 files (eight intentional family failures, 1215/1215 existing-suite guard); GREEN implementation `d8d57aa`, `evidence/C2-green.txt` fingerprint `b2abfcbb…109068` over 222 files, build 0 warnings/errors, deployment 1230/1230 and all five application suites green. The packaged module composed all eight concrete adapters plus the Windows operator provider under PS 5.1; the elevated adapter-only harness passed 54/54 cases. Its three non-probe state hashes were identical before/after and an independent cleanup count found no probe object or backup. The RED oracle's Windows allowed-reference list was amended to include `Sibyla.Deployment.Execution`, required because the adapter assembly implements those interfaces; no other allowance changed. **D2 preflight revisions:** RED `3612882` (`evidence/C2-d2-path-red.txt`) proved ChecksOnly supplied an unreadable install-root directory for check 9; GREEN `b638e1d` (`evidence/C2-d2-path-green.txt`, fingerprint `45bba5d1…f41cd20c` over 222 files) binds the captured live API IIS snapshot and reads its exact `MANIFEST.json`; deployment 1231/1231 and the elevated probe 55/55 with the same cleanup guarantees. RED `706722d` (`evidence/C2-d2-pool-path-red.txt`) then proved pool readback could accept the correct module filename from a wrong IIS physical path. GREEN `2a04901` (`evidence/C2-d2-pool-path-green.txt`, fingerprint `f091883c…27d8a3` over 222 files) requires exact loaded-module/live-IIS path equality, or a complete release-ID path segment in release mode; build 0 warnings/errors, focused 39/39, deployment 1231/1231 and elevated disposable probe 57/57 with identical protected hashes and zero cleanup residue. RED `c6eca16` (`evidence/C2-d2-iis-receipt-red.txt`) reproduced D2's first-read `SIBYLA-S2-REDACTION`: the real IIS tuple's redundant scalar digest exceeded the 512-character receipt-leaf cap. GREEN `1ae1e25` (`evidence/C2-d2-iis-receipt-green.txt`, fingerprint `e2442941…f14f3f` over 222 files) uses the compact exact state digest defined above while retaining the tuple fields; build 0 warnings/errors, focused 105/105, deployment 1231/1231 and elevated disposable probe 58/58 with identical protected hashes and zero cleanup residue. RED `a8e0951` (`evidence/C2-d2-schema-receipt-red.txt`) reproduced D2's schema-read `SIBYLA-S2-REDACTION` with a 19-migration body. GREEN `3b0dc03` (`evidence/C2-d2-schema-receipt-green.txt`, fingerprint `ad5419ec…cf21f5a` over 222 files) compares the complete body then budgets only sanitized Observed text by final receipt-leaf cost; build 0 warnings/errors, focused 105/105, deployment 1231/1231 and elevated disposable probe 59/59 with identical protected hashes and zero cleanup residue. | per-adapter oracles = section 2's facts on the probe objects |
| D2 | `Invoke-SibylaDeployment -Execute -ChecksOnly` on the live production hosts after the hand path has deployed the A2 API. **Precondition retained after the owner's post-checkpoint ruling on reviewer O finding 1:** the D2 run record shows `has_table_privilege('sibyla_api', 'public."__EFMigrationsHistory"', 'SELECT') = true` on the production database before the run. `sibyla_api` is the only current platform API role; `apollo_api` remains only in immutable applied migrations and historical evidence. Main's existing grant followed the Phase D role rename by OID; on a fresh database `db/channel-intake-api-role.sql` supplies the renamed grant through `local/setup-db.ps1`. No narrow follow-up migration is added. | section 7's table on the live host |
| E2 | full `-Execute -WhatIf`, full `-Execute` on a parallel release of the same commit, `-Resume` after an injected failure (written "Configure failure" until the final checkpoint of 2026-09-06 amended it: the owner ruling D-E2-3 placed the fault in Install — a readback/publish fault that never reaches Configure — and the delivered run took the `install-first-write-rollback-fails` path; see the "E2 passed" paragraph), roll forward — at a time the owner names, outside the renewal window, **run as the principal that holds the `Operator` Modify ACE on `DocsPath`** (today `EC2AMAZ-NTPJCNO\Administrator`; `Acl.Readback(DocsPath)` compares that ACE to the journaled `Operator`, O5-10, O6-N3) | the run record of 2026-09-03 and the journal |

**D2 passed 2026-09-03** on `ops/sibyla-deployment-slice2-d2` (`evidence/D2-run.md`). The
schema-qualified form of the mandatory query returned true. The final PS 5.1 production result was
`ChecksOnlyResultV2`, outcome `Executed`: 15/15 read operations succeeded and all 12/12 section-7
checks passed; `applicationHost.config`, production metadata and the zero-journal set were
unchanged. The record also carries the two fail-closed receipt corrections exposed by the first
reads. No production mutation or secret-content read occurred. The C2+D2 checkpoint is pending.

The B2 row records O1's status when the checkpoint closed. The owner's later ruling in the D2 row
supersedes that deferral: O1 is resolved, while its production privilege check remains mandatory.

**C2+D2 checkpoint rejected 2026-09-04.** Both independent reviewers rejected `C2 723e93f` /
`D2 fce287f`. The blocking overlap was ambiguous unframed file-tree identity and an inexact
full-execution worker path check; the spec reviewer also enforced the RED-before-GREEN hard stop.
The executable corrective RED is `6d08d2a` (`evidence/C2-checkpoint-rejection-red.txt`, fingerprint
`151c1cd4…c040ec`, 0/9 focused tests and the disposable probe failing on the ambiguous-tree case).
GREEN `d42db25` (`evidence/C2-checkpoint-rejection-green.txt`, fingerprint
`2b9d70a7…1f2922`) answers every C2 code/process finding: canonical framed trees including empty
directories, transaction-owned failed names, exact SCM-derived worker executable, typed oversized
schema rejection, compact ACL state, TLS store/absence rules, command-line overlap detection, the
one-constant probe exemption and Sibyla module wording. Build is clean; deployment 1240/1240; all
five application suites green; elevated disposable adapters 67/67 with protected hashes unchanged
and zero residue. D2 evidence controls and a fresh ChecksOnly binding to this candidate were then
completed. RED `3e6e844` plus `evidence/D2-controls-red.txt` failed 4/4 provenance-control tests;
GREEN `3a934cb` plus `evidence/D2-controls-green.txt` passed 4/4 and the full deployment suite
1244/1244. The tracked runner binds a clean exact commit, source fingerprint, C2 ancestry, runner
hash, module artifact hashes, exact privilege query/helper identity and freshness, and the actual
framed journal set. The fresh 2026-09-04 run is recorded in `evidence/D2-r2-result.json` and
`evidence/D2-r2-privilege.json`: `ChecksOnlyResultV2`, outcome `Executed`, 15/15 read operations
succeeded, 12/12 checks passed, and applicationHost.config, production metadata and the journal
set were unchanged. No production mutation or secret-content read occurred. The checkpoint is
open only for independent re-review; E2 remains prohibited.

**Re-review of the correction, 2026-09-04: both reviewers REJECT again** (P: High 1, Medium 2; O:
Medium 2), answered on the C2 branch without rewriting history: (1) the historical RED probe had
stopped at its first failing case, so the seven later cases were never shown failing — closed by an
isolated forensic replay of the committed assertions against the exact commits, each case in its own
elevated run: 8/8 fail for their named reason on RED `6d08d2a`, 8/8 pass on GREEN `d42db25`
(`evidence/C2-checkpoint-replay.txt`, with the two orchestration-only overlay diffs and their
hashes); (2) `.failed-<txid>` used the `N` Guid form where the spec requires lowercase `D` — oracle
retyped first (`b9663cb`, failing), adapter corrected in `5121db6` (clean-export fingerprint
`93195288…f1a3f6` over 223 files); (3) the GREEN record named a nonexistent full SHA — corrected in
place to `d42db25cb3a7…afb29f` with a dated addendum; (4) O's suspicion that the over-limit typed
mismatch came from a parse/throw is disproved on a live endpoint serving a complete parseable body
above four KiB (RED accepts it, GREEN answers a typed unsatisfied receipt; the regex helpers do not
throw), so no further HTTP change is made. Re-validation of `5121db6`: build clean; focused 9/9;
deployment 1240/1240; the five application suites green; elevated disposable adapters 67/67 with the
protected hashes unchanged and zero residue. **D2 rebound 2026-09-04 08:55 UTC** to candidate
`a13c46e` (merge of the corrected C2 into D2; source fingerprint `62e6a460…bd17dc` over 226 files,
equal from the clean export and the bound worktree; deployment 1244/1244): fresh interactive
privilege proof `sibyla_api` / `public."__EFMigrationsHistory"` / `SELECT` = true, 0.03 minutes
old at start; `ChecksOnlyResultV2` / `Executed`; 15/15 operations succeeded, every plan operation
`Read`; 12/12 section-7 checks passed; `applicationHost.config`, production metadata and the framed
journal set unchanged (`evidence/D2-run-r3.md`, `D2-r3-privilege.json`, `D2-r3-result.json` with
their SHA-256). **Checkpoint C2+D2 CLOSED 2026-09-04: both independent reviewers ACCEPT** on
C2 `a2def6b` / D2 `4ca647b` (`evidence/CHECKPOINT-C2D2-review.md`; spec: Critical 0, High 0,
Medium 1, Low 2; operations: Critical 0, High 0, Medium 0, Low 3; every previous finding CLOSED,
the schema adjudication verified from source by both). The spec Medium (the round-2 D2 control
record labelled a worktree fingerprint `e4fa5ae7…` as "clean"; the clean-export value of
`3a934cb`/`e4368b3` is `910d3918…1f72`) and the Lows about the record are closed by dated addenda;
the two operations Lows on the harness (protected hashes asserted only on passing runs) and the
section-8 redaction gate on the schema body are carried to E2. The D2 relation in this section is
written schema-qualified (`public."__EFMigrationsHistory"`) from here on, as the tracked helper and
runner query it. C2 and D2 merge to `main`; E2 remains prohibited until the owner names its time.

**E2 passed 2026-09-06** on `ops/sibyla-deployment-slice2-e2` (`evidence/E2-red.txt`, `E2-green.txt`,
`E2-1-whatif.md`, `E2-2-execute.md`, `E2-3-resume.md`, `E2-4-forward.md`; oracle `oracles/e2.v2.json`;
tracked runner `probes/e2-execute-v2.ps1`, fault watcher `probes/e2-fault-v2.ps1`, launcher
`probes/e2-launch-v2.ps1`). Gate commit `d6c4f79` (the main head at the session start, D-E2-1) in a
detached local clone; two clean releases of it. E2-1 `-Execute -WhatIf`: `Planned`, 161 entries, no
journal. E2-2 full `-Execute`: `Executed`, 12/12, after three stopped attempts that each surfaced a
module defect the disposable C2 root could not show and D2's read-only plan never reached — (1) the
compiler bound every ACL compensation readback to an empty grant set, (2) the adapter's install-root
descent refused its own sub-targets' grants, (3) the secrets leaves are files with one explicit
`Read` (vocabulary `AclRights.Read`, section 3 amended) — every one typed RED before its fix, and
every stopped run left the host at its snapshot. E2-3 `-Execute` on a second release with the tracked
fault: the held handle broke `PublishTree(web)`'s post-state digest, so the run was the modelled case
`install-first-write-rollback-fails` rather than the ACL-readback case typed (recorded as a
deviation), and it surfaced (4) the file-system rollback demanding the apply receipt of a forward
that failed; after the fix `-Execute -Resume` retried only the failed compensation and ended
`RolledBack`. E2-4 roll forward: `Executed`, 12/12; all hosts on the second release, `PREVIOUS.txt` on
the first, pre-E2 folders kept. The module writes bare release ids into the pointer files, so
`local\rollback-release.ps1` needs `-ToPath` from here on. Five IIS backups `SibylaE2-*` kept, none
restored; five journals under `D:\ApolloData`. The final checkpoint follows.

Checkpoints: after A2+B2 (independent reviewer), after C2+D2, final after E2 with the evidence
record. Evidence rule as S1: `<sub-slice>-red.txt` before implementation with the framed SHA-256;
a behaviour test that passes on its first run is a HARD STOP.

## 10. Operational restrictions during Slice 2

No `-Execute` against the production sites or service until E2 is scheduled by the owner
(`-ChecksOnly` for D2 excepted); adapter proof only on the `ZZ.Sibyla.Probe.*` targets; no
reading of `local\secrets`, the secrets root's contents or `D:\ApolloData\worker-claude`; the
legacy sites, `GottSibylaWorker`, `gott_sibyla`, the Hermes configuration and crons untouched. The
hand-path scripts remain the deployment method until the final checkpoint; a hand-path run, a
win-acme run (window 09:00–15:00 UTC) and a module run must never overlap.
