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
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
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
Enterprise mode conversion (contract 6); custody 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).
@@ -21,10 +38,13 @@ through the extensibility rule §2.4).
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.
composes 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. 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
it performs is an existing command with its own contract: user and
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
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.
(started/completed timestamps); bookkeeping is a cache, never the
source of truth for any decision (§4.3 defines the reconciliation
rule that makes this concrete for seeding).
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).
(bootstrap epoch in `bootstrap_state`, registration mode in settings,
mode in the contract-6 mode record).
## 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
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.
3. **Mode is an install-time input, not a wizard output.** The
deployment mode is recorded canonically at bootstrap and owned by
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
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.
§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)
@@ -75,30 +103,46 @@ the named authority:
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.
3. **Initial user.** Email, password, and display name, or SSO (PRD §6
step list: "email/password/name/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 submitted display name lands on the canonical account record
(identity §2); no field of the PRD's step list is dropped. The
wizard also presents the applicable mandatory choices — registration
mode (identity §2.2) and, for each configured SSO provider, that
provider's JIT enablement with its allowlist warning (identity §4.1,
§4.3). The wizard MUST obtain an explicit submission for each
applicable mandatory choice and MUST refuse step completion while
one is unsubmitted. This is a presentation-and-submission obligation
on wizard runs only: identity's own defaults (registration `closed`,
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
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.
and persona (D11). Enrollment specifics belong to the rank-4
agent-enrollment command family; this contract binds only that the
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,
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.
voice-matching) appear in `docs/ROADMAP.md` per D11. The deferred
profile step's custody semantics are contract 7's (D14); the v1 wizard
collects no sensitive category, so v1 ships no custody surface.
## 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
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.
3. **Idempotent seeding, reconciled from canonical state.** Step 4 on
re-run MUST NOT duplicate: the initial company/estate/project/
workspace and the example data are created at most once per bootstrap
epoch. The at-most-once key is a deterministic per-mutation
correlation id derived from the bootstrap epoch and the seed role
(e.g. epoch id + "seed-company"), submitted as the command's
correlation id (contract 5 §4.3) and therefore recorded in the
mutation's audit event in the same transaction as the mutation
itself (contract 1 §5.2). Before applying any seed mutation, the
wizard reconciles against the audit/command log for its epoch's seed
correlation ids and skips every mutation whose event exists. Wizard
bookkeeping of seed node ids is a cache of this record, never the
source of truth: losing it cannot cause duplication. 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 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)
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).
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
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
party, service actor, or wizard-privileged writer exists in this
flow.
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.
— is decided by the ruling below: any **eligible 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. Eligible means, in identity-contract
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
under the seeded company) follows contract 2 §4.3 unchanged: parent
`owner` authority, no automatic grant needed.
@@ -147,43 +210,89 @@ so v1 ships no custody surface.
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
1. **D8 mapping witness:** every Gateway call the wizard makes resolves
to a contract 5 mapping row (asserted by contract 5 §6.1's inventory
scoped to the wizard surface); 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
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
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
new users, zero new grants, zero duplicated example content, and the
bootstrap epoch still completed (identity §8's epoch witnesses cover
the transition itself). **Reconfigurability:** a re-run changes a
mutable value (registration mode) and the canonical setting reflects
it. **Canonical-state drift:** mutate state outside the wizard (a
rename through the hierarchy command), then re-run — the wizard
renders the current canonical value, not a stored answer.
**Second company:** a re-run creating a second company succeeds with
the running user as actor, names the creator as `owner` by default
(grant row asserted), and leaves the first company's exact node and
content set untouched (row-set and content-digest assertions).
4. **Seed-set witness:** after a first completed run, the created seed
set is exactly the declared set — one company, one estate, one
project, one workspace, the example content (fixed digest), the one
§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
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.
7. **Interrupted-run witness:** inject failure after each internal
mutation of a run — after the bootstrap transaction, after each
individual seed command (company, estate, project, workspace, each
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
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).
- Decision (§5.2): post-bootstrap, any eligible platform user
(authenticated, not banned, not deactivated — identity §2/§5) 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).