docs: onboarding wizard contract (S2 contract 3)
ci/woodpecker/pr/ci Pipeline was canceled

This commit is contained in:
fred
2026-08-26 18:46:14 -05:00
parent 49b7943420
commit 1c9a3ddefb
+189
View File
@@ -0,0 +1,189 @@
# Onboarding Wizard Contract (D4)
Status: DRAFT — awaiting ratification (webui-audit S2, contract 3 of 9).
Authority: PRD D4 (Part I §6), D11 v1 slice (Part I §9), D8 architecture
gate (Part I §8), the identity account-lifecycle contract
(`docs/requirements/identity-lifecycle.md`, §§24), and the RBAC grant
model contract (`docs/requirements/rbac-grant-model.md`, §4.3). This
document turns D4 into a concrete contract: what the wizard is
architecturally, its v1 step model, mode branching, re-run/idempotency
semantics, and what it seeds under whose authority.
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);
Enterprise mode conversion (contract 6); custody enforcement semantics
(contract 7); the deferred-beyond-v1 steps themselves (connectors, comms
integrations, voice-matching, M365 — D11 defers them; they bind here only
through the extensibility rule §2.4).
## 1. Placement and architecture
1. The wizard is a **product surface over the Gateway command API** — a
web UI flow (and equivalently scriptable command sequence) that
composes existing audited Gateway commands. It is subject to the D8
hard rule like every other webUI surface: no wizard operation reaches
the database or filesystem directly, and no wizard-only privileged
write path exists.
2. **The wizard introduces no new mutation surface.** Every state change
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.
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
can drift from reality. The wizard MAY persist run bookkeeping
(started/completed timestamps, mode) and MUST persist the
explicit-choice records other contracts mandate (registration mode,
identity §2.2; per-provider JIT enablement, identity §4.1) — those are
settings writes, not private wizard state.
4. If a wizard-completion marker is stored, it is presentational only
(which entry screen to show). No authorization or gating decision may
read it: gating state lives where its owning contract puts it
(bootstrap epoch in `bootstrap_state`, registration mode in settings).
## 2. Modes and extensibility
1. The wizard **differs by mode** (D4): Standalone and Enterprise share
one skeleton; Enterprise makes personal data optional and moves focus
to business structure, RBAC, and external systems.
2. **v1 ships the Standalone flow only** (D11). The mode branch point and
skeleton MUST still exist in v1 — mode is a property of the flow, not
a fork of it — but no Enterprise-only step ships, and mode conversion
is contract 6.
3. Mode is chosen at bootstrap and recorded as an explicit operator
choice. Changing it later is conversion (contract 6), not a wizard
re-run.
4. **Extensibility:** new wizards attach as tabs (D4). Attaching a wizard
tab is a registration of additional steps against the same skeleton,
inheriting this contract's rules (§1 architecture, §3 step contract,
§4 re-runnability). A tab cannot opt out of them.
## 3. v1 step model (Standalone)
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 write. Company
name feeds step 4's company creation.
2. **Component choices.** Mosaic Comms/Matrix vs external; Mosaic
SSO/Authentik vs external; Mosaic DB/PostgreSQL vs external; vector
DB (D4). v1 records the choices as settings and configures what is
installable in-product; component provisioning beyond that is host
tooling, out of scope here.
3. **Initial user.** Email/password or SSO, per identity §3: the
first-admin transition is atomic, one per bootstrap epoch, and the SSO
variant runs inside the bootstrap transaction (identity §3.6). The
wizard also presents registration mode (identity §2.2) and, when SSO
is configured, per-provider JIT with its allowlist warning (identity
§4.1, §4.3) — each recorded as an explicit choice, none silently
defaulted.
4. **Initial hierarchy and seeding.** Creates the first company (naming
the initial `owner` grant in the same audited operation, contract 2
§4.3), an initial estate, an initial project, and an initial workspace
with seeded example data (D4, D11). All through hierarchy commands
(contract 1 §5.1); seeded examples are ordinary workspace content
created by ordinary commands, attributable in audit to the wizard run
actor.
5. **Minimal agent enrollment.** One harness, API-key login, agent name
and persona (D11). Enrollment specifics belong to the agent-enrollment
command family; this contract binds only that the step exists, is
skippable, and uses that family.
Steps deferred beyond v1 (user onboarding profile, connectors, comms,
voice-matching) appear in `docs/ROADMAP.md` per D11. Note for the profile
step when it lands: sensitive profile categories are custody-bound to the
user's own brain (D14, contract 7); the v1 wizard collects none of them,
so v1 ships no custody surface.
## 4. Re-runnability and idempotency (D4 "no lock-in")
1. **Re-run is a first-class operation.** After completion, running the
wizard again re-opens every step against current state (§1.3) for
reconfiguration. Nothing about completion locks the wizard.
2. **The bootstrap epoch does not re-open** (identity §3.4). On re-run,
step 3 shows the existing admin/registration/JIT configuration and
allows changing the mutable parts through their normal commands;
"setup already completed" is a stable state, and factory reset — a
future, explicitly destructive operation — is the only path to a new
epoch.
3. **Idempotent seeding.** Step 4 on re-run MUST NOT duplicate: the
initial company/estate/project/workspace are created at most once per
bootstrap epoch, keyed by recorded seed identity (the created node
ids), not by name matching. A re-run offers to create _additional_
hierarchy nodes (PRD: users can create N companies, N estates, N
projects) but never re-creates or resets the originals, and never
touches user content added since. Example-data seeding is likewise
at-most-once per epoch and is skippable.
4. **Interrupted runs strand nothing.** The wizard is resumable at step
granularity: each step's apply either commits through its command (and
is then visible as current state to the resumed run) or leaves nothing
(identity §3.5 for the bootstrap step). There is no wizard-level
transaction spanning steps and no compensating rollback of completed
steps.
## 5. Seeding authority (resolves contract 2 review NEW-1)
1. During the bootstrap epoch, the wizard's authority to create the first
company is the bootstrap writer's (identity §3): there is no earlier
user to authorize it. The first company creation names the first admin
(or the operator-designated initial user) as initial `owner` (contract
2 §4.3).
2. **Post-bootstrap top-level company creation** — the "N companies" flow
— is decided by the ruling below: any ACTIVE platform user MAY create
a top-level company and MUST name an initial `owner` grant in the same
audited operation (contract 2 §4.3); the creator naming themselves is
the default. Until that ruling, deny-by-default holds (contract 2
§3.1): no implicit creation authority exists.
3. Child-node creation inside the wizard (estate, project, workspace
under the seeded company) follows contract 2 §4.3 unchanged: parent
`owner` authority, no automatic grant needed.
## 6. Verification requirements
Binding on the implementing PRs:
1. **No-new-writers witness:** the wizard modules appear in no
class-table writer allowlist (contract 1 §6.3b) and hold no direct DB
access; a static assertion that wizard code reaches state only through
Gateway command clients.
2. **Re-run witnesses:** complete the wizard, then re-run it to
completion making no changes — assert zero new hierarchy nodes, zero
new users, zero duplicated example content, and the bootstrap epoch
still completed (identity §8's epoch witnesses cover the transition
itself). Then a re-run that adds a second company succeeds and leaves
the first company and its content untouched (row-count and content
assertions).
3. **Seed-audit witness:** every node, grant, and example item created by
a wizard run has its command audit event (contract 1 §5.2, contract 2
§4.4) attributing the wizard-run actor; the first-company event names
the initial owner grant in the same audited operation.
4. **Explicit-choice witnesses:** after a completed run, registration
mode, per-provider JIT flags, mode (Standalone/Enterprise), and
component choices each read back as recorded values; the identity
contract's defaults (registration `closed`, JIT off) hold for any
choice the run did not explicitly make.
5. **Gating-independence witness:** with any wizard-completion marker
deleted (§1.4), authorization and registration gating behave
identically — proving no gate reads wizard state.
6. **Interrupted-run witness:** kill a run between steps; assert no
stranded partial outcome (identity §8 covers the bootstrap step; for
step 4, either the node set committed with its audit events or is
absent) and that a resumed run completes against the committed state.
## Ruling request
Ratify sections 16 as written, with one decision embedded:
- Decision (§5.2): post-bootstrap, any ACTIVE platform user may create a
top-level company, naming an initial `owner` grant (default: self) in
the same audited operation. Basis: PRD Part I §4 "Users can create N
companies, N estates, N projects" read as end-user capability, not
admin-only. Alternative if rejected: top-level creation stays
deny-by-default and becomes a platform-admin-granted capability in a
later contract — nothing in this contract or contract 2 breaks either
way, because deny-by-default is the resting state (contract 2 §3.1).