docs: onboarding wizard revision 2 — first-company authority, mode as input, choice/witness repairs (sol F1-F9)
ci/woodpecker/pr/ci Pipeline is running

This commit is contained in:
fred
2026-08-26 19:13:36 -05:00
parent 1c9a3ddefb
commit 666e3dbf20
+201 -92
View File
@@ -9,11 +9,28 @@ document turns D4 into a concrete contract: what the wizard is
architecturally, its v1 step model, mode branching, re-run/idempotency architecturally, its v1 step model, mode branching, re-run/idempotency
semantics, and what it seeds under whose authority. semantics, and what it seeds under whose authority.
Revision 2 (sol review F1F9): first-company authority repaired — the
bootstrap writer creates only the admin and closes the epoch; step 4
runs as the new admin through the ordinary top-level company command
(F1). Mode is an install-time input the wizard reads, never writes
(F2). The initial user's `name` restored from the PRD step list, and
enrollment skippability flagged as a §12.1 drafting addition (F3).
Explicit-choice obligations restated as wizard-run presentation rules
that leave identity's defaults untouched, with a submitted-vs-canonical
witness (F4). The D8 witness bound to contract 5's mapping and
authorization-parity probes (F5). Witness coverage extended to the mode
branch, reconfigurability, canonical-state drift, second-company actor
semantics, exact seed sets, tab inheritance, and enrollment (F6). Step
4's at-most-once semantics grounded in same-transaction audit
reconciliation with per-mutation failure injection (F7). The custody
note reduced to a cross-reference (F8). Creation eligibility defined in
identity terms with an actor matrix (F9).
Scope: the Gateway-backed product onboarding wizard. Out of scope: the Scope: the Gateway-backed product onboarding wizard. Out of scope: the
host-local install wizard (`mosaic wizard`, which drives host install and host-local install wizard (`mosaic wizard`, which drives host install and
gateway bootstrap and is not this artifact — audit REPORT.md layer 3); gateway bootstrap and is not this artifact — audit REPORT.md layer 3);
Enterprise mode conversion (contract 6); custody enforcement semantics Enterprise mode conversion (contract 6); custody semantics (contract 7);
(contract 7); the deferred-beyond-v1 steps themselves (connectors, comms the deferred-beyond-v1 steps themselves (connectors, comms
integrations, voice-matching, M365 — D11 defers them; they bind here only integrations, voice-matching, M365 — D11 defers them; they bind here only
through the extensibility rule §2.4). through the extensibility rule §2.4).
@@ -21,10 +38,13 @@ through the extensibility rule §2.4).
1. The wizard is a **product surface over the Gateway command API** — a 1. The wizard is a **product surface over the Gateway command API** — a
web UI flow (and equivalently scriptable command sequence) that web UI flow (and equivalently scriptable command sequence) that
composes existing audited Gateway commands. It is subject to the D8 composes Gateway commands. It is subject to the D8 hard rule like
hard rule like every other webUI surface: no wizard operation reaches every other webUI surface: no wizard operation reaches the database
the database or filesystem directly, and no wizard-only privileged or filesystem directly, and no wizard-only privileged write path
write path exists. exists. Concretely, the wizard is contract 5's rank-6 family,
composing the rank-1 hierarchy commands and the rank-4 enrollment
command (contract 5 §3.1): those families are built first, and every
wizard operation is a row in contract 5's mapping.
2. **The wizard introduces no new mutation surface.** Every state change 2. **The wizard introduces no new mutation surface.** Every state change
it performs is an existing command with its own contract: user and it performs is an existing command with its own contract: user and
epoch writes under the identity contract §3, hierarchy writes under epoch writes under the identity contract §3, hierarchy writes under
@@ -37,14 +57,14 @@ through the extensibility rule §2.4).
system's current configuration (read through the same commands) and system's current configuration (read through the same commands) and
applies deltas; the wizard does not keep an answer file whose contents applies deltas; the wizard does not keep an answer file whose contents
can drift from reality. The wizard MAY persist run bookkeeping can drift from reality. The wizard MAY persist run bookkeeping
(started/completed timestamps, mode) and MUST persist the (started/completed timestamps); bookkeeping is a cache, never the
explicit-choice records other contracts mandate (registration mode, source of truth for any decision (§4.3 defines the reconciliation
identity §2.2; per-provider JIT enablement, identity §4.1) — those are rule that makes this concrete for seeding).
settings writes, not private wizard state.
4. If a wizard-completion marker is stored, it is presentational only 4. If a wizard-completion marker is stored, it is presentational only
(which entry screen to show). No authorization or gating decision may (which entry screen to show). No authorization or gating decision may
read it: gating state lives where its owning contract puts it read it: gating state lives where its owning contract puts it
(bootstrap epoch in `bootstrap_state`, registration mode in settings). (bootstrap epoch in `bootstrap_state`, registration mode in settings,
mode in the contract-6 mode record).
## 2. Modes and extensibility ## 2. Modes and extensibility
@@ -55,13 +75,21 @@ through the extensibility rule §2.4).
skeleton MUST still exist in v1 — mode is a property of the flow, not 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 a fork of it — but no Enterprise-only step ships, and mode conversion
is contract 6. is contract 6.
3. Mode is chosen at bootstrap and recorded as an explicit operator 3. **Mode is an install-time input, not a wizard output.** The
choice. Changing it later is conversion (contract 6), not a wizard deployment mode is recorded canonically at bootstrap and owned by
re-run. contract 6 (§2 there): the wizard reads the recorded mode and
branches on it; it never writes mode and never derives it from
feature state. Changing mode later is conversion (contract 6), not a
wizard re-run. In v1 a recorded mode of `enterprise` is refused at
bootstrap (contract 6 §5), so the wizard's Enterprise branch is
unreachable in v1; a wizard invoked against an unsupported or
unreadable mode record produces a single bounded refusal (contract
5 §4.2 precondition class), never a partial flow.
4. **Extensibility:** new wizards attach as tabs (D4). Attaching a wizard 4. **Extensibility:** new wizards attach as tabs (D4). Attaching a wizard
tab is a registration of additional steps against the same skeleton, tab is a registration of additional steps against the same skeleton,
inheriting this contract's rules (§1 architecture, §3 step contract, inheriting this contract's rules (§1 architecture, §3 step contract,
§4 re-runnability). A tab cannot opt out of them. §4 re-runnability). A tab cannot opt out of them: tab steps are
subject to the same §6 witnesses as the built-in steps.
## 3. v1 step model (Standalone) ## 3. v1 step model (Standalone)
@@ -75,30 +103,46 @@ the named authority:
DB (D4). v1 records the choices as settings and configures what is DB (D4). v1 records the choices as settings and configures what is
installable in-product; component provisioning beyond that is host installable in-product; component provisioning beyond that is host
tooling, out of scope here. tooling, out of scope here.
3. **Initial user.** Email/password or SSO, per identity §3: the 3. **Initial user.** Email, password, and display name, or SSO (PRD §6
first-admin transition is atomic, one per bootstrap epoch, and the SSO step list: "email/password/name/SSO"), per identity §3: the
variant runs inside the bootstrap transaction (identity §3.6). The first-admin transition is atomic, one per bootstrap epoch, and the
wizard also presents registration mode (identity §2.2) and, when SSO SSO variant runs inside the bootstrap transaction (identity §3.6).
is configured, per-provider JIT with its allowlist warning (identity The submitted display name lands on the canonical account record
§4.1, §4.3) — each recorded as an explicit choice, none silently (identity §2); no field of the PRD's step list is dropped. The
defaulted. wizard also presents the applicable mandatory choices — registration
4. **Initial hierarchy and seeding.** Creates the first company (naming mode (identity §2.2) and, for each configured SSO provider, that
the initial `owner` grant in the same audited operation, contract 2 provider's JIT enablement with its allowlist warning (identity §4.1,
§4.3), an initial estate, an initial project, and an initial workspace §4.3). The wizard MUST obtain an explicit submission for each
with seeded example data (D4, D11). All through hierarchy commands applicable mandatory choice and MUST refuse step completion while
(contract 1 §5.1); seeded examples are ordinary workspace content one is unsubmitted. This is a presentation-and-submission obligation
created by ordinary commands, attributable in audit to the wizard run on wizard runs only: identity's own defaults (registration `closed`,
actor. JIT off) continue to govern everything a wizard run never touches,
and this contract creates no new stored-record obligation beyond
those identity itself defines.
4. **Initial hierarchy and seeding.** Runs strictly after step 3's epoch
transition, authenticated as the newly created admin. The bootstrap
writer (identity §3) creates only the first account and closes the
epoch; it has no hierarchy authority and creates no hierarchy node.
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
(contract 2 §4.3). The initial estate, initial project, and initial
workspace with seeded example data (D4, D11) follow through hierarchy
commands (contract 1 §5.1) under the admin's `owner` authority
(contract 2 §4.3). Seeded examples are ordinary workspace content
created by ordinary commands, attributable in audit to the acting
admin with the wizard run's correlation ids (contract 5 §4.3).
5. **Minimal agent enrollment.** One harness, API-key login, agent name 5. **Minimal agent enrollment.** One harness, API-key login, agent name
and persona (D11). Enrollment specifics belong to the agent-enrollment and persona (D11). Enrollment specifics belong to the rank-4
command family; this contract binds only that the step exists, is agent-enrollment command family; this contract binds only that the
skippable, and uses that family. step exists, uses that family, and is skippable. Skippability is a
drafting addition under PRD §12.1 (the PRD step list does not mark
the step optional); it is ratified with this contract.
Steps deferred beyond v1 (user onboarding profile, connectors, comms, Steps deferred beyond v1 (user onboarding profile, connectors, comms,
voice-matching) appear in `docs/ROADMAP.md` per D11. Note for the profile voice-matching) appear in `docs/ROADMAP.md` per D11. The deferred
step when it lands: sensitive profile categories are custody-bound to the profile step's custody semantics are contract 7's (D14); the v1 wizard
user's own brain (D14, contract 7); the v1 wizard collects none of them, collects no sensitive category, so v1 ships no custody surface.
so v1 ships no custody surface.
## 4. Re-runnability and idempotency (D4 "no lock-in") ## 4. Re-runnability and idempotency (D4 "no lock-in")
@@ -111,34 +155,53 @@ so v1 ships no custody surface.
"setup already completed" is a stable state, and factory reset — a "setup already completed" is a stable state, and factory reset — a
future, explicitly destructive operation — is the only path to a new future, explicitly destructive operation — is the only path to a new
epoch. epoch.
3. **Idempotent seeding.** Step 4 on re-run MUST NOT duplicate: the 3. **Idempotent seeding, reconciled from canonical state.** Step 4 on
initial company/estate/project/workspace are created at most once per re-run MUST NOT duplicate: the initial company/estate/project/
bootstrap epoch, keyed by recorded seed identity (the created node workspace and the example data are created at most once per bootstrap
ids), not by name matching. A re-run offers to create _additional_ epoch. The at-most-once key is a deterministic per-mutation
hierarchy nodes (PRD: users can create N companies, N estates, N correlation id derived from the bootstrap epoch and the seed role
projects) but never re-creates or resets the originals, and never (e.g. epoch id + "seed-company"), submitted as the command's
touches user content added since. Example-data seeding is likewise correlation id (contract 5 §4.3) and therefore recorded in the
at-most-once per epoch and is skippable. mutation's audit event in the same transaction as the mutation
4. **Interrupted runs strand nothing.** The wizard is resumable at step itself (contract 1 §5.2). Before applying any seed mutation, the
granularity: each step's apply either commits through its command (and wizard reconciles against the audit/command log for its epoch's seed
is then visible as current state to the resumed run) or leaves nothing correlation ids and skips every mutation whose event exists. Wizard
(identity §3.5 for the bootstrap step). There is no wizard-level bookkeeping of seed node ids is a cache of this record, never the
transaction spanning steps and no compensating rollback of completed source of truth: losing it cannot cause duplication. A re-run offers
steps. 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 the
granularity of a single command: each mutation either commits through
its command with its same-transaction audit event, or leaves nothing
(identity §3.5 for the bootstrap step). Step 4 is a sequence of
individually atomic commands, not one transaction: an interruption
between them leaves a prefix of committed seed nodes, and the §4.3
reconciliation rule makes the resumed run complete exactly the
remaining suffix, without duplication and without compensating
rollback of completed commands. There is no wizard-level transaction
spanning steps.
## 5. Seeding authority (resolves contract 2 review NEW-1) ## 5. Seeding authority (resolves contract 2 review NEW-1)
1. During the bootstrap epoch, the wizard's authority to create the first 1. During the bootstrap epoch, the bootstrap writer's authority (identity
company is the bootstrap writer's (identity §3): there is no earlier §3) covers exactly what identity §3 defines: creating the first
user to authorize it. The first company creation names the first admin account and closing the epoch. It creates no hierarchy node. The
(or the operator-designated initial user) as initial `owner` (contract first company is created post-epoch by the first admin through the
2 §4.3). ordinary top-level company command (§5.2), naming that admin as
initial `owner` (contract 2 §4.3). No operator-designated third
party, service actor, or wizard-privileged writer exists in this
flow.
2. **Post-bootstrap top-level company creation** — the "N companies" flow 2. **Post-bootstrap top-level company creation** — the "N companies" flow
— is decided by the ruling below: any ACTIVE platform user MAY create — is decided by the ruling below: any **eligible platform user** MAY
a top-level company and MUST name an initial `owner` grant in the same create a top-level company and MUST name an initial `owner` grant in
audited operation (contract 2 §4.3); the creator naming themselves is the same audited operation (contract 2 §4.3); the creator naming
the default. Until that ruling, deny-by-default holds (contract 2 themselves is the default. Eligible means, in identity-contract
§3.1): no implicit creation authority exists. terms: an authenticated account (identity §2) that is not banned and
not deactivated (identity §5). No further role or grant is required.
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 3. Child-node creation inside the wizard (estate, project, workspace
under the seeded company) follows contract 2 §4.3 unchanged: parent under the seeded company) follows contract 2 §4.3 unchanged: parent
`owner` authority, no automatic grant needed. `owner` authority, no automatic grant needed.
@@ -147,43 +210,89 @@ so v1 ships no custody surface.
Binding on the implementing PRs: Binding on the implementing PRs:
1. **No-new-writers witness:** the wizard modules appear in no 1. **D8 mapping witness:** every Gateway call the wizard makes resolves
class-table writer allowlist (contract 1 §6.3b) and hold no direct DB to a contract 5 mapping row (asserted by contract 5 §6.1's inventory
access; a static assertion that wizard code reaches state only through scoped to the wizard surface); wizard modules appear in no
Gateway command clients. class-table writer allowlist (contract 1 §6.3b) and hold no direct
2. **Re-run witnesses:** complete the wizard, then re-run it to database or filesystem access (static assertion, plus a runtime
probe that a wizard-context filesystem/database access attempt is
refused). **Authorization parity:** for each mutating wizard
operation, the same actor invoking the underlying command directly
receives the same authorization outcome as through the wizard —
probed for at least one allowed and one refused actor per operation.
2. **Mode witnesses:** the branch point exists (the flow resolves its
step set from the canonical mode record, read through contract 6's
read surface); v1 with mode `standalone` yields the §3 step set; a
simulated unsupported or unreadable mode record yields one bounded
precondition refusal (§2.3) and no partial flow; wizard sources
contain no mode write and no feature-state mode derivation.
3. **Re-run witnesses:** complete the wizard, then re-run it to
completion making no changes — assert zero new hierarchy nodes, zero completion making no changes — assert zero new hierarchy nodes, zero
new users, zero duplicated example content, and the bootstrap epoch new users, zero new grants, zero duplicated example content, and the
still completed (identity §8's epoch witnesses cover the transition bootstrap epoch still completed (identity §8's epoch witnesses cover
itself). Then a re-run that adds a second company succeeds and leaves the transition itself). **Reconfigurability:** a re-run changes a
the first company and its content untouched (row-count and content mutable value (registration mode) and the canonical setting reflects
assertions). it. **Canonical-state drift:** mutate state outside the wizard (a
3. **Seed-audit witness:** every node, grant, and example item created by rename through the hierarchy command), then re-run — the wizard
a wizard run has its command audit event (contract 1 §5.2, contract 2 renders the current canonical value, not a stored answer.
§4.4) attributing the wizard-run actor; the first-company event names **Second company:** a re-run creating a second company succeeds with
the initial owner grant in the same audited operation. the running user as actor, names the creator as `owner` by default
4. **Explicit-choice witnesses:** after a completed run, registration (grant row asserted), and leaves the first company's exact node and
mode, per-provider JIT flags, mode (Standalone/Enterprise), and content set untouched (row-set and content-digest assertions).
component choices each read back as recorded values; the identity 4. **Seed-set witness:** after a first completed run, the created seed
contract's defaults (registration `closed`, JIT off) hold for any set is exactly the declared set — one company, one estate, one
choice the run did not explicitly make. project, one workspace, the example content (fixed digest), the one
5. **Gating-independence witness:** with any wizard-completion marker §4.3 `owner` grant, and no other node or grant attributable to the
run's correlation ids. Every seeded node, grant, and example item
has its command audit event (contract 1 §5.2, contract 2 §4.4)
carrying the deterministic seed correlation id (§4.3) and the acting
admin; the first-company event names the initial owner grant in the
same audited operation.
5. **Explicit-choice witness:** a run submitting explicit values
completes, and each canonical value equals the value the run
submitted (asserted against the captured submissions, not by reading
the canonical store twice); a run with an applicable mandatory
choice unsubmitted is refused at step 3 (§3.3); identity's defaults
are asserted for a provider the run never touched (registration
`closed`, JIT off — identity §2.2, §4.1).
6. **Gating-independence witness:** with any wizard-completion marker
deleted (§1.4), authorization and registration gating behave deleted (§1.4), authorization and registration gating behave
identically — proving no gate reads wizard state. identically — proving no gate reads wizard state.
6. **Interrupted-run witness:** kill a run between steps; assert no 7. **Interrupted-run witness:** inject failure after each internal
stranded partial outcome (identity §8 covers the bootstrap step; for mutation of a run — after the bootstrap transaction, after each
step 4, either the node set committed with its audit events or is individual seed command (company, estate, project, workspace, each
absent) and that a resumed run completes against the committed state. example item), and after the bookkeeping cache write — and for each
injection point assert: no stranded partial outcome (every committed
command has its same-transaction audit event; nothing else exists),
and a resumed run completes exactly the remaining mutations with no
duplication (identity §8 covers the bootstrap step; §4.3–§4.4 define
the reconciliation the witness exercises). Deleting the bookkeeping
cache between failure and resume MUST NOT change the outcome.
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, a banned
account, and a deactivated account (negatives), with contract 2's
error classes.
9. **Tab-inheritance witness:** a registered test tab's steps are
subject to the same assertions — its modules fail the §6.1 static
assertion if they access the database directly, and its mutations
appear in the §6.1 mapping inventory — proving §2.4 is enforced by
machinery, not convention.
10. **Enrollment witness:** the enrollment step exists, invokes only the
rank-4 family, and a run that skips it completes with zero
enrollment-family mutations.
## Ruling request ## Ruling request
Ratify sections 16 as written, with one decision embedded: Ratify sections 16 as written, with one decision embedded:
- Decision (§5.2): post-bootstrap, any ACTIVE platform user may create a - Decision (§5.2): post-bootstrap, any eligible platform user
top-level company, naming an initial `owner` grant (default: self) in (authenticated, not banned, not deactivated — identity §2/§5) may
the same audited operation. Basis: PRD Part I §4 "Users can create N create a top-level company, naming an initial `owner` grant (default:
companies, N estates, N projects" read as end-user capability, not self) in the same audited operation. Basis: PRD Part I §4 "Users can
admin-only. Alternative if rejected: top-level creation stays create N companies, N estates, N projects" read as end-user
deny-by-default and becomes a platform-admin-granted capability in a capability, not admin-only. Alternative if rejected: top-level
later contract — nothing in this contract or contract 2 breaks either creation stays deny-by-default and becomes a platform-admin-granted
way, because deny-by-default is the resting state (contract 2 §3.1). 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).