diff --git a/docs/requirements/onboarding-wizard.md b/docs/requirements/onboarding-wizard.md index 1f51dc68..858bb6c6 100644 --- a/docs/requirements/onboarding-wizard.md +++ b/docs/requirements/onboarding-wizard.md @@ -68,6 +68,26 @@ outcomes are recorded; the concurrent loser receives the winner's recorded outcome (F7). §7 now names the contract 5 §3.1 rank-6 mapping rows the composition expansion amends (F5, N4). +Revision 5 (sol re-review 3: residual F2/F7/N1/N3, new N5/N6): the +finalize command is now honestly scoped as the wizard's **single +disclosed server-side composed transaction** — a bounded, severable +amendment to the §1.1 client-side-composition rule, reachable only +while the epoch is open, executing under the bootstrap writer's +amended authority (never by authenticating the caller as the created +admin), with a dedicated finalize-write inventory witness proving its +internal write set equals the §3.3 carried-value list; §1.2 and §5.1 +no longer claim identity §3 binds unchanged (N1, N5). The epoch field's +wire values are pinned to the closed token pair `open`/`completed` +(identity §3 names the states but no wire enumeration; the pin is +disclosed) (F2). The company-name seed parameter gains an owning +record: the declared `bootstrap.seed-company-name` settings value, +committed by finalize and read through the ordinary settings surface +(N3). The §6.7 fence witnesses add the different-actor collision, the +different-scope collision, and the aborted-winner concurrency case +(F7). The password-only first admin is restated as a disclosed PRD +deviation (deferment) of the initial-user SSO option, not as its +satisfaction (N6). + Scope: the Gateway-backed product onboarding wizard. Out of scope: the host-local install wizard (`mosaic wizard`, which drives host install and gateway bootstrap and is not this artifact — audit REPORT.md layer 3); @@ -84,11 +104,19 @@ through the extensibility rule §2.4). every other webUI surface: no wizard operation reaches the database or filesystem directly, and no wizard-only privileged write path exists. Concretely, the wizard is contract 5's rank-6 family, and it - is a **client-side composition with no server-side wizard - orchestrator**: every wizard operation is an ordinary outbound - Gateway call issued from the wizard's web modules (or the equivalent - scripted sequence), so contract 5 §6.1's outbound-call inventory, - scoped to those modules, sees the wizard's complete operation set. + is a **client-side composition with exactly one disclosed + exception**: every wizard operation except step 3's finalize is an + ordinary outbound Gateway call issued from the wizard's web modules + (or the equivalent scripted sequence), and the exception is the + §3.3 **bootstrap finalize command** — one server-side composed + transaction on identity §3's bootstrap surface, reachable only + while the bootstrap epoch is open, disclosed and ratified as the + §7.3 architecture amendment. No other server-side module composes + wizard operations. Contract 5 §6.1's outbound-call inventory, + scoped to the wizard modules, therefore sees the wizard's complete + outbound call set; the finalize command's internally composed + writes are proved complete by the dedicated §6.1 finalize-write + inventory, not by the outbound inventory. The composed operations span six existing families: the rank-1 hierarchy commands and the rank-4 enrollment command (contract 5 §3.1 — built first), the settings command family (steps 1–2), the @@ -104,10 +132,15 @@ through the extensibility rule §2.4). it performs is an existing command with its own contract: user and epoch writes under the identity contract §3, hierarchy writes under contract 1 §5, grant writes under contract 2 §4, settings writes under - their owning command family. The one exception is the bootstrap epoch - transition, where the wizard drives the bootstrap writer defined by - identity §3 — that writer's constraints (§3.1–§3.6) bind unchanged; - this contract adds nothing to them. + their owning command family. The one exception is the bootstrap + surface, where the wizard drives the bootstrap writer defined by + identity §3 **as amended by the disclosed §7.3 finalize + extension**: the writer's constraints (§3.1–§3.6) bind, and this + contract's single change to them — extending the epoch-closing + command to carry the §3.3 value set inside the same transaction — + is exactly the §7.3 amendment, severable and ratified with this + contract. Beyond that amendment, nothing is added to identity §3, + and no undisclosed authority exists. 3. **Wizard state derives from canonical state.** Each step renders the system's current configuration (read through the same commands) and applies deltas; the wizard does not keep an answer file whose contents @@ -147,10 +180,13 @@ through the extensibility rule §2.4). record server-side. The bootstrap-status response is a **closed two-field schema**: `epoch` — one field whose value set is exactly the bootstrap epoch states identity §3 defines for - `bootstrap_state`, closed to that enumeration — and `mode` — the - recorded mode value, present **only while the epoch is open** and - absent from the response schema once the epoch has completed. No - other field exists in the response. The unauthenticated pre-epoch + `bootstrap_state`, closed to the exact wire-token pair **`open`** + and **`completed`** — identity §3 names the two epoch states in + prose but defines no wire enumeration, so this contract pins the + tokens, as the second clause of the disclosed §7.9 amendment — and + `mode` — the recorded mode value, present **only while the epoch + is open** and absent from the response schema once the epoch has + completed. No other field exists in the response. The unauthenticated pre-epoch mode disclosure is a disclosed amendment to contract 6 §2.2's authenticated-read rule (§7.9); post-epoch, §2.2's authenticated-only rule holds unchanged and the bootstrap-status @@ -173,7 +209,12 @@ through the extensibility rule §2.4). The v1 wizard consists of exactly these steps, in order, each backed by the named authority: -1. **System and company name.** System name is a settings value; company +1. **System and company name.** System name and the seed company name + are both settings values: the company name is recorded under the + declared settings key **`bootstrap.seed-company-name`** — the §3.4 + seed parameter, a disclosed drafting addition (§7.11) — committed + by step 3's finalize command among the ordinary settings writes and + readable through the ordinary settings read surface. The company name feeds step 4's company creation. On a first run this step collects and validates only — the collected values are committed by step 3's finalize command (§3.3). On a re-run (an authenticated admin exists) @@ -191,11 +232,16 @@ the named authority: v1 first admin is password-only.** A step-2 SSO choice cannot yield a canonically configured provider before the epoch closes, so an SSO-authenticated first admin is not constructible in this flow; - the v1 wizard does not compose identity §3.6's SSO variant, and the - PRD step list's SSO option is satisfied post-epoch (providers - configured and JIT-enabled after finalize; identity §5 governs - every SSO-created account). This is a disclosed sequencing decision - (§7.10). The password path's canonical `users.name` MUST equal the + the v1 wizard does not compose identity §3.6's SSO variant. The + PRD step list's SSO option **for the initial user is not + implemented in v1 — a disclosed PRD deviation (deferment, §7.10)**: + no v1 step configures a provider before finalize and no v1 step + links the first admin to a provider afterwards, so the initial user + cannot be SSO-created or SSO-linked in v1. SSO first becomes + available to accounts created post-epoch (providers configured and + JIT-enabled after finalize; identity §5 governs every SSO-created + account) — those are different users, not a satisfaction of the + initial-user option. The password path's canonical `users.name` MUST equal the submitted display name; any SSO-created account's name is bound to identity §5's mapped name claim (witness §6.5); no field of the PRD's step list is dropped. The wizard also presents the applicable @@ -218,11 +264,17 @@ the named authority: seed parameter), the step-2 component choices, the registration-mode submission, and the applicable JIT submissions. The command executes **in one transaction**: it creates the admin - and closes the epoch exactly as identity §3 defines, then — with - the new admin existing inside the same transaction, holding the - RBAC §1.1 platform authority those writes require — commits every - carried value through the ordinary settings and identity - configuration writes, each attributed in audit to the new admin. + and closes the epoch exactly as identity §3 defines, then commits + every carried value through the ordinary settings and identity + configuration write implementations — the same code paths the + post-epoch commands use; no parallel write path. The executing + authority is the **bootstrap writer's own authority as amended by + §7.3**, never an authentication of the caller: the finalize + request begins and ends unauthenticated, and creating the admin + row does not authenticate the caller as that admin. Each carried + write is attributed in audit to the newly created admin as the + accountable principal the transaction establishes; the admin + authenticates afterwards by ordinary login. Either the whole transaction commits or none of it exists (identity §3.5's atomicity extends over the carried writes). Before finalize the run holds collected values only: no canonical write of any kind @@ -236,11 +288,15 @@ the named authority: closes the epoch, and commits the §3.3 carried values; it has no hierarchy authority and creates no hierarchy node. The seed sequence is derived entirely from canonical state: the seed - parameter the finalize command recorded (the company name) and the - fixed example set (§4.3). A resumed run — including a fresh client - holding none of the original run's transient state — reconstructs - the same ordered sequence and the same deterministic §4.3 keys from - that canonical state alone. + parameter the finalize command recorded (the company name, read + from the `bootstrap.seed-company-name` settings value, §3.1) and + the fixed example set (§4.3). A resumed run — including a fresh + client holding none of the original run's transient state — + reconstructs the same ordered sequence and the same deterministic + §4.3 keys from that canonical state alone. Once the first company + exists the seed parameter is inert bookkeeping: the §4.3 fence, + not the parameter's presence or absence, is what prevents + re-seeding. The first company is created by the ordinary top-level company command under §5.2's eligibility policy, with the new admin as actor, naming the admin as initial `owner` in the same audited operation @@ -351,9 +407,11 @@ collects no sensitive category, so v1 ships no custody surface. ## 5. Seeding authority (resolves contract 2 review NEW-1) -1. During the bootstrap epoch, the bootstrap writer's authority (identity - §3) covers exactly what identity §3 defines: creating the first - account and closing the epoch. It creates no hierarchy node. The +1. During the bootstrap epoch, the bootstrap writer's authority + (identity §3, as amended by the §7.3 finalize extension) covers + creating the first account, closing the epoch, and committing the + §3.3 carried values inside the finalize transaction — nothing + else. It creates no hierarchy node. The first company is created post-epoch by the first admin through the ordinary top-level company command (§5.2), naming that admin as initial `owner` (contract 2 §4.3). No operator-designated third @@ -380,11 +438,21 @@ Binding on the implementing PRs: 1. **D8 mapping witness:** every Gateway call the wizard makes resolves to a contract 5 mapping row, asserted by contract 5 §6.1's outbound-call inventory scoped to the wizard modules — an inventory - that is complete for the wizard because §1.1 forbids a server-side - wizard orchestrator, and the witness statically asserts that - prohibition (no server-side module composes wizard operations). The - inventoried operation set is asserted equal, in both directions, to - the §1.1 declared family list. Wizard modules appear in no + that is complete for the wizard's outbound calls because §1.1 + forbids server-side wizard composition outside the single declared + §3.3 finalize handler, and the witness statically asserts that + scoped prohibition (no server-side module other than the declared + finalize handler composes wizard operations). The inventoried + operation set is asserted equal, in both directions, to the §1.1 + declared family list. **Finalize-write inventory:** the finalize + handler's internal write set is statically enumerated and asserted + equal, in both directions, to the §3.3 carried-value list — the + admin creation and epoch transition plus the settings writes + (including `bootstrap.seed-company-name`), the registration-mode + write, and the applicable JIT writes, nothing else; each internal + write is asserted to invoke the owning command family's ordinary + write implementation (no parallel write path); and the handler is + asserted refused once the epoch has completed (identity §3.4). Wizard modules appear in no class-table writer allowlist (contract 1 §6.3b) and hold no direct database or filesystem access (static assertion, plus a runtime probe that a wizard-context filesystem/database access attempt is @@ -396,7 +464,8 @@ Binding on the implementing PRs: resolves its step set from the bootstrap-status mode field (§2.3), a post-epoch run from contract 6 §2.2's authenticated read; the bootstrap-status response matches §2.3's closed two-field schema - exactly while the epoch is open, and after the epoch completes + exactly while the epoch is open — the epoch field carrying one of + §2.3's two exact wire tokens — and after the epoch completes contains the epoch field only — the mode field absent from the response (closed-field assertion on the response schema in both phases); post-epoch, an unauthenticated mode read through any @@ -472,13 +541,21 @@ Binding on the implementing PRs: executes nothing and returns the recorded outcome (asserted by mutation-count and audit-event-count equality); the same key with a changed payload digest is refused with the single bounded conflict - and executes nothing; a replay by an actor who has since lost + and executes nothing; the same key and payload submitted by a + different authorized actor is refused with the same single bounded + conflict (actor mismatch) and executes nothing; the same key, + actor, and payload submitted against a different authorization + scope is likewise refused (scope mismatch) and executes nothing; a + replay by an actor who has since lost eligibility (identity §7.1 ban) receives the authorization refusal, not the recorded outcome; a submission that failed before commit leaves no fence row and its retry executes; two concurrent resumed runs executing the seed sequence yield exactly one seed set — per key, exactly one mutation and one audit event exist, and the losing - submission received the winner's recorded outcome. + submission received the winner's recorded outcome; and with the + winner's transaction forced to abort, the waiting loser finds no + fence row, executes, and commits exactly one mutation and one + audit event. 8. **Actor-matrix witness (§5.2):** post-bootstrap top-level company creation succeeds for an ordinary authenticated non-admin user (positive), and is refused for an unauthenticated caller and for a @@ -523,9 +600,14 @@ contracts and are not additions: identity §3's bootstrap surface: one transaction carrying the first-admin fields, the collected settings, registration-mode, and JIT values, and the §3.4 seed parameter, committing the carried - writes under the new admin's authority with identity §3.5's - atomicity extended over them. Severable from the rest of this - contract. + writes under the bootstrap writer's amended authority (never by + authenticating the caller as the created admin; §3.3) with + identity §3.5's atomicity extended over them. This item is also a + disclosed, bounded amendment to the §1.1 client-side-composition + rule: the finalize handler is the wizard's single server-side + composed transaction, reachable only while the epoch is open, + witnessed by §6.1's finalize-write inventory. Severable from the + rest of this contract. 4. The idempotency-key field and its same-transaction uniqueness fence, with the §4.3 replay, collision, no-error-replay, and concurrency rules — an addition to contract 5 §4's command @@ -533,7 +615,8 @@ contracts and are not additions: this contract. 5. The presentation-and-submission obligation for applicable mandatory choices on wizard runs (§3.3). -6. The no-server-side-orchestrator architectural constraint (§1.1). +6. The no-server-side-orchestrator architectural constraint (§1.1), + scoped by the single disclosed §3.3 finalize exception (item 3). 7. The wizard-completion-marker presentational-only rule (§1.4). 8. The contract 5 §3.1 rank-6 mapping expansion (§1.1): the rank-6 composition row, which today names only the rank-1 hierarchy and @@ -547,10 +630,24 @@ contracts and are not additions: under contract 5 §5. 9. The contract 6 §2.2 amendment permitting the single unauthenticated pre-epoch mode disclosure through the §2.3 bootstrap-status field; - post-epoch, §2.2's authenticated-only rule is unchanged. -10. The password-only v1 first admin (§3.3): identity §3.6's SSO - variant is not composed by the v1 wizard; the PRD step list's SSO - option is satisfied post-epoch. + post-epoch, §2.2's authenticated-only rule is unchanged. Second + clause: the pin of the `epoch` field's wire enumeration to exactly + the tokens `open` and `completed` (§2.3) — identity §3 names the + two epoch states in prose but defines no wire values, so this + contract fixes them. +10. The password-only v1 first admin (§3.3) — a disclosed **PRD + deviation (deferment)**: PRD Part I §6's initial-user SSO option + is not implemented in v1. Identity §3.6's SSO variant is not + composed by the v1 wizard, the initial user cannot be SSO-created + or SSO-linked in v1, and SSO first becomes available to accounts + created post-epoch (different users, not a satisfaction of the + initial-user field). The deviation narrows the PRD field for v1 + and is severable. +11. The **`bootstrap.seed-company-name`** settings key (§3.1) — the + owning record of the §3.4 seed parameter: written by the finalize + transaction among the ordinary settings writes, read through the + ordinary settings read surface, inert once the first company + exists (§3.4). ## Ruling request