Files
stack/docs/requirements/onboarding-wizard.md
T
2026-08-26 21:08:33 -05:00

723 lines
44 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.
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).
Revision 3 (sol re-review: residual F2/F3/F5/F6/F7/F9, new N1/N2): the
wizard is now explicitly a client-side composition with no server-side
orchestrator, spanning six named command families, every operation an
ordinary outbound Gateway call inside contract 5 §6.1's inventory scope
(F5). First runs collect steps 12 without writing; the collected
settings are applied immediately after the epoch transition under the
first admin's platform authority, so no pre-admin write authority
exists or is invented (N1). Pre-epoch mode branching reads the mode
value from the unauthenticated bootstrap-status response, a disclosed
one-field addition; post-epoch runs use contract 6's authenticated read
(F2). The SSO display-name source is bound to identity §5's mapped name
claim, with a canonical-name witness (F3). At-most-once seeding is
fenced by a caller-supplied idempotency key recorded under a unique
constraint in the same transaction as the mutation; correlation ids
revert to pure trace linkage (F7). Re-run witnesses now cover every
mutable family, assert the second-company grant is same-operation, and
extend tab inheritance to re-run and explicit-choice machinery (F6).
Eligibility is restated in identity §7.1's terms — deactivation is the
better-auth ban, with no separate state (F9). Example-data seeding is
mandatory; the skippability policy is removed (PRD §6.4) (N2). All
drafting additions are consolidated in §7.
Revision 4 (sol re-review 2: residual F2/F5/F7/N1, new N3/N4): the
post-epoch application phase is replaced by a single **bootstrap
finalize command** — step 3 submits the first-admin fields and every
collected value (settings, registration mode, applicable JIT choices,
seed parameters) in one command on identity §3's bootstrap surface,
executed server-side in one transaction that creates the admin, closes
the epoch, and commits the carried values under the new admin's
authority; after it, every collected value is canonical state, so an
interrupted run resumes from canonical state alone (N1, N3). The v1
first admin is password-only; identity §3.6's SSO variant is not
composed by the v1 wizard (N1's SSO ordering). The bootstrap-status
response is a closed two-field schema (epoch state plus a
pre-epoch-only mode field), with the contract 6 §2.2 amendment
disclosed (F2). The idempotency envelope is completed: fence rows
record operation, actor, scope, and payload digest; replay is
re-authorized; changed-payload collision is refused; only committed
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).
Revision 6 (sol re-review 4: residual F7, new N7): the seed parameter
becomes **immutable seed provenance**`bootstrap.seed-company-name`
is written exactly once by the finalize transaction and any later
write to it is refused, so a re-run's re-derived seed sequence is
byte-stable and replays cleanly against the §4.3 fence instead of
colliding with it; the current company name's canonical home is the
company row (renamed through the ordinary hierarchy command), and the
wizard renders the row, never the provenance value (N7). §6.3 gains
the changed-name re-run and rename-then-re-run witnesses plus the
immutability refusal probe, with a mutated-digest collision control
(N7). §6.7 adds the two missing envelope witnesses: the same raw key
under two different operations executes both independently
(pair-uniqueness, not global key-uniqueness), and a fresh
authorization refusal records no fence row so an authorized retry
executes afresh (F7).
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 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 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, and it
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 12), the
identity bootstrap and registration surface (step 3, including the
§3.3 finalize command), the mode reads (contract 6 §2.2 post-epoch;
the §2.3 bootstrap-status field pre-epoch), and the ordinary
content commands used for example seeding (step 4). Two of these
families (ranks 1 and 4) are in contract 5 §3.1's live rank-6
composition row; the other four are added by the disclosed §7.8
mapping amendment, without which their operations are unmapped and
blocked under contract 5 §5.
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
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
can drift from reality. Values a first run has collected but not yet
committed by the §3.3 finalize command are transient run state, not
a persisted answer file; after finalize every collected value is
canonical state, and no transient value is needed to resume
(§4.4). The wizard MAY persist run bookkeeping
(started/completed timestamps); bookkeeping is a cache, never the
source of truth for any decision. The §4.3 idempotency fence is
command-layer canonical state, not wizard bookkeeping — losing
bookkeeping never affects it.
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,
mode in the contract-6 mode record).
## 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 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. During the bootstrap epoch no authenticated account
exists, so contract 6 §2.2's authenticated read surface is
unreachable there; the pre-epoch flow instead branches on the mode
value reported by the **unauthenticated bootstrap-status response**
of the bootstrap surface (identity §3), which evaluates the mode
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 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
response carries no mode field. Post-epoch wizard runs read mode
through contract 6 §2.2 unchanged. 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: tab steps are
subject to the same §6 witnesses as the built-in steps.
## 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 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. **The seed parameter is
immutable seed provenance:** it is written exactly once, by the
finalize transaction, and every later write to the key — through
any surface, any actor — is refused by the settings family (a
disclosed immutable-key rule, §7.11). It records what the seed
sequence was derived from, not what the company is currently
named: the current name's canonical home is the company row, and
renaming the seed company is the ordinary hierarchy rename
command against that row, never a settings edit. 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) the system name and other settings
apply directly through the settings commands; the company-name
field renders the company row's current canonical name and
applies a change as the hierarchy rename.
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 (first run: collected,
committed by step 3's finalize command §3.3; re-run: applied
directly) and
configures what is installable in-product; component provisioning
beyond that is host tooling, out of scope here.
3. **Initial user and finalize.** Email, password, and display name
(PRD §6 step list: "email/password/name/SSO"), per identity §3: the
first-admin transition is atomic and one per bootstrap epoch. **The
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. 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
mandatory choices — registration mode (identity §2.2) and, for each
SSO provider canonically configured at finalize time, that
provider's JIT enablement with its allowlist warning (identity
§4.1, §4.3); a provider configured after finalize receives its JIT
choice at configuration time under identity §4.1's default. The
wizard MUST obtain an explicit submission for each applicable
mandatory choice and MUST refuse finalize 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. **Finalize rule (first runs):** step 3
ends in a single **bootstrap finalize command** on identity §3's
bootstrap surface — a disclosed extension of that surface (§7.3) —
carrying the first-admin fields and every collected value: the
step-1 system name, the step-1 company name (recorded as the §3.4
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 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
occurs pre-epoch, and no pre-admin write authority exists or is
invented (witness §6.11). After finalize, every collected value is
canonical state; no transient value is needed to resume (§4.4,
witness §6.7).
4. **Initial hierarchy and seeding.** Runs strictly after step 3's
finalize transaction, authenticated as the newly created admin. The
bootstrap writer (identity §3) creates only the first account,
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, 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. Because the seed
parameter is immutable (§3.1), the re-derived sequence is
byte-stable across every re-run and resume: the same keys carry
the same payload digests, so already-committed mutations replay
(recorded outcomes) rather than collide, regardless of any
hierarchy rename performed since. The §4.3 fence, not the
parameter's presence or absence, is what prevents re-seeding; the
parameter is provenance the derivation reads, never a value any
later step may change.
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, carrying the run's trace correlation ids (contract 5 §4.3)
and the §4.3 idempotency keys.
5. **Minimal agent enrollment.** One harness, API-key login, agent name
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 disclosed in §7 and ratified with this
contract.
Steps deferred beyond v1 (user onboarding profile, connectors, comms,
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")
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, fenced at the command layer.** 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 mechanism is an **idempotency key**, a
disclosed drafting addition to contract 5's §4 command envelope
ratified with this contract (§7): a mutating command MAY carry a
caller-supplied idempotency key. The complete envelope:
- **Fence row.** The command layer records, in a
uniqueness-constrained fence table **in the same transaction**
as the mutation and its audit event: the key, the operation
identifier, the acting principal, the mutation's authorization
scope (the target company, or the platform scope for top-level
operations), a digest of the canonicalized request payload, and
a reference to the committed outcome. Fence uniqueness is the
pair (operation identifier, key).
- **Replay.** A submission whose (operation, key) pair is recorded
is first authorized exactly as a fresh submission would be — an
actor who is not authorized receives the authorization refusal,
never the recorded outcome. If authorization passes and the
recorded actor, scope, and payload digest all equal the
submission's, the command executes nothing and returns the
recorded outcome.
- **Collision.** A submission whose (operation, key) pair is
recorded but whose actor, scope, or payload digest differs is
refused with a single bounded conflict error (contract 5 §4.2);
it executes nothing and discloses nothing of the recorded
outcome.
- **No error replay.** The fence row commits only with its
mutation, so only committed outcomes are ever recorded. A failed
or refused submission records no fence row; a retry executes
afresh. There is no recorded-error state.
- **Concurrency.** Two submissions with the same (operation, key)
pair serialize on the fence's unique constraint: exactly one
executes. The loser waits for the winner's transaction to
resolve; if it committed, the loser is handled as a replay
(authorization first, then the recorded outcome, or the
collision refusal on mismatch); if it aborted, no fence row
exists and the loser executes. The loser never performs a second
mutation and is never left without a defined response.
The wizard submits deterministic keys derived from the bootstrap
epoch and the seed role (e.g. epoch id + "seed-company") for every
seed mutation. Correlation ids (contract 5 §4.3) remain pure trace
linkage and carry no idempotency semantics. Wizard bookkeeping of
seed node ids remains a cache
(§1.3): losing it cannot cause duplication, because the fence is
canonical command-layer state. 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; the example set is fixed and its
seeding is not skippable (PRD §6.4: a completed first run contains
the fixed example set).
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 and fence
row, or leaves nothing (identity §3.5, extended over the carried
writes, for the §3.3 finalize command). A run interrupted before
finalize has written nothing; its collected values are re-entered.
A run interrupted after finalize resumes from canonical state
alone: every collected value was committed by the finalize
transaction, and the remaining work — the step 45 command
sequence — is derivable from it (§3.4). 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
fence makes the resumed run complete exactly the remaining suffix —
the run re-derives the full ordered seed sequence from canonical
state and re-submits it with the same deterministic keys,
already-committed mutations return their recorded outcomes, and
only the remainder executes, 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 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
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 **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
(identity §7.1 — deactivation on this platform IS the better-auth
ban; no separate deactivated state exists). 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.
## 6. Verification requirements
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'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
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 — a pre-epoch flow
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 — 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
surface is refused (contract 6 §2.2, as amended by §7.9, holds); 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 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 one
value in each mutable family — the system name (settings), a
component choice (settings), registration mode, and a configured
provider's JIT enablement — and each canonical value reflects the
change; a run that skipped enrollment enrolls an agent on re-run
through the rank-4 family and the enrollment exists canonically.
**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.
**Seed-provenance witnesses (§3.1, §3.4):** rename the seed
company through the hierarchy command, then re-run to completion —
the re-derived seed sequence carries the same keys and payload
digests as the first run (asserted digest equality), every seed
submission replays with the recorded outcome, zero new nodes are
created, and the company keeps its renamed name; a re-run
submitting a different company name renames the company row and
commits no settings write to the seed key; a direct post-epoch
settings write to `bootstrap.seed-company-name`, by any actor, is
refused; and a control run that force-mutates a seed payload
digest receives the §4.3 collision refusal, proving the fence
still discriminates.
**Second company:** a re-run creating a second company succeeds with
the running user as actor and names the creator as `owner` in the
same audited operation — asserted on the single audit event naming
both the creation and the grant (contract 2 §4.3–§4.4), not merely
on the grant row's existence — 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 idempotency keys or trace correlation ids. Every seeded node,
grant, and example item has its command audit event (contract 1
§5.2, contract 2 §4.4) committed in the same transaction as its
mutation and §4.3 fence row, attributed to 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); canonical `users.name` equals the
declared source — for the first admin (password path), the
submitted display name; for an SSO-created account (a post-epoch
JIT-provisioned user), the identity §5 mapped name claim (each
asserted against the captured submission or captured assertion); 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.
7. **Interrupted-run witness:** inject failure at each point of a
run — **inside the finalize transaction** (after admin creation but
before the carried writes commit: assert nothing exists — no
account, the epoch still open, canonical settings untouched, no
fence row, no audit event), after the committed finalize
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 and fence row; nothing else exists), and a resumed run
completes exactly the remaining mutations with no duplication
(identity §8 covers the epoch transition; §4.3–§4.4 define the
fence the witness exercises). The resume after the committed
finalize MUST be performed by a fresh client holding none of the
original run's transient state, deriving the remaining seed
sequence from canonical state alone (§3.4). Deleting the
bookkeeping cache between failure and resume MUST NOT change the
outcome. **Idempotency-fence witnesses (§4.3):** re-submitting a
committed seed command with its same key, actor, and payload
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; 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; 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. Two envelope-shape witnesses complete the §4.3
coverage: the same raw key submitted to two DIFFERENT operations
executes both independently, each committing its own mutation,
audit event, and fence row — proving uniqueness is the
(operation, key) pair, so a globally key-unique fence fails this
witness; and a fresh submission refused by authorization records
no fence row — the same actor, made eligible, retries the same
(operation, key, payload) and the command executes afresh,
distinguishing an authorization refusal from a pre-commit failure
and proving refusals record nothing.
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
banned account (identity §7.1's deactivation-as-ban) (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, its mutations
appear in the §6.1 mapping inventory, a tab re-run making no
changes produces zero new mutations (§6.3 style), and a tab
declaring a mandatory choice is refused while it is unsubmitted
(§6.5 style) — 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.
11. **Pre-epoch authority and finalize witness (§3.3):** during a
first run, before finalize, canonical state is untouched
(settings-state comparison against the pre-run capture), and an
injected settings-write attempt from the unauthenticated pre-epoch
flow is refused with contract 5 §4.2's **authentication-failure
class** (the caller is unauthenticated, not an
authorized-but-refused actor); the finalize command commits the
admin, the epoch transition, and every carried value in one
transaction, each carried write attributable in audit to the new
admin; the §6.7 inside-finalize injection covers the atomicity
negative.
## 7. Drafting additions (PRD §12.1 disclosure)
Proposed drafting additions, visible here for ratification, each
severable; the step list, mode branching, re-runnability, and seeding
obligations themselves are traced to PRD D4/D11 and the named sibling
contracts and are not additions:
1. Enrollment-step skippability (§3.5) — the PRD step list does not
mark the step optional.
2. The unauthenticated bootstrap-status mode disclosure — the closed
two-field response schema (epoch state plus the recorded mode
value, the latter present during the bootstrap epoch only) (§2.3).
3. The **bootstrap finalize command** (§3.3) — an extension of
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 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
envelope, proposed and ratified here, severable from the rest of
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),
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
rank-4 enrollment families, is amended to name all six composed
families — adding the settings command family, the identity
bootstrap and registration surface (including the §3.3 finalize
command), the mode reads (contract 6 §2.2 and the §2.3
bootstrap-status field), and the ordinary content commands used for
example seeding — with one mapping row per newly named family.
Without this amendment those operations are unmapped and blocked
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. 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 exactly once by
the finalize transaction among the ordinary settings writes, read
through the ordinary settings read surface, and **immutable
thereafter** — the settings family refuses every later write to
the key, from any surface and any actor. The key is seed
provenance for §3.4's derivation; the current company name lives
on the company row and changes only through the ordinary
hierarchy rename (§3.1, witnesses §6.3).
## Ruling request
Ratify sections 17 as written, with one decision embedded:
- Decision (§5.2): post-bootstrap, any eligible platform user
(authenticated, not banned — identity §2/§7.1) 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).