docs: onboarding-wizard contract revision 7 (sol r6 F6 residual + NEW-8)
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
This commit is contained in:
@@ -104,6 +104,24 @@ under two different operations executes both independently
|
|||||||
authorization refusal records no fence row so an authorized retry
|
authorization refusal records no fence row so an authorized retry
|
||||||
executes afresh (F7).
|
executes afresh (F7).
|
||||||
|
|
||||||
|
Revision 7 (sol re-review 5: residual F6, new N8): the fence gains a
|
||||||
|
**replay mode** — each keyed submission declares `actor-bound`
|
||||||
|
(default) or `shared`, recorded in the fence row; a shared row replays
|
||||||
|
for any freshly authorized actor whose scope and payload digest match,
|
||||||
|
while an actor-bound row keeps the revision-6 actor-equality rule, and
|
||||||
|
a declared-mode mismatch is a collision. Every §3.4 seed submission
|
||||||
|
declares shared, reconciling actor-bound replay with re-runnability:
|
||||||
|
the seed set is a per-epoch singleton, so a fresh-authorized second
|
||||||
|
admin's no-change re-run replays the first run's recorded outcomes
|
||||||
|
instead of colliding (N8). §6.7's different-actor witness splits into
|
||||||
|
the actor-bound refusal and the shared replay, plus a mode-mismatch
|
||||||
|
collision and a shared-row lost-eligibility refusal; §6.3 adds the
|
||||||
|
second-admin re-run witness (N8). §6.3's changed-name case now
|
||||||
|
continues through step 4 with the bookkeeping cache deleted — original
|
||||||
|
digests asserted, every seed outcome replayed, zero new nodes, run
|
||||||
|
completed — proving the dirty form value never enters derivation and
|
||||||
|
the renamed row resolves cache-independently (F6).
|
||||||
|
|
||||||
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);
|
||||||
@@ -325,7 +343,10 @@ the named authority:
|
|||||||
byte-stable across every re-run and resume: the same keys carry
|
byte-stable across every re-run and resume: the same keys carry
|
||||||
the same payload digests, so already-committed mutations replay
|
the same payload digests, so already-committed mutations replay
|
||||||
(recorded outcomes) rather than collide, regardless of any
|
(recorded outcomes) rather than collide, regardless of any
|
||||||
hierarchy rename performed since. The §4.3 fence, not the
|
hierarchy rename performed since — and, because every seed
|
||||||
|
submission declares §4.3's `shared` replay mode, they replay for
|
||||||
|
whichever currently eligible admin performs the re-run, not only
|
||||||
|
the actor the fence rows record. The §4.3 fence, not the
|
||||||
parameter's presence or absence, is what prevents re-seeding; the
|
parameter's presence or absence, is what prevents re-seeding; the
|
||||||
parameter is provenance the derivation reads, never a value any
|
parameter is provenance the derivation reads, never a value any
|
||||||
later step may change.
|
later step may change.
|
||||||
@@ -375,18 +396,32 @@ collects no sensitive category, so v1 ships no custody surface.
|
|||||||
as the mutation and its audit event: the key, the operation
|
as the mutation and its audit event: the key, the operation
|
||||||
identifier, the acting principal, the mutation's authorization
|
identifier, the acting principal, the mutation's authorization
|
||||||
scope (the target company, or the platform scope for top-level
|
scope (the target company, or the platform scope for top-level
|
||||||
operations), a digest of the canonicalized request payload, and
|
operations), a digest of the canonicalized request payload, the
|
||||||
|
submission's declared **replay mode** — `actor-bound` (the
|
||||||
|
default) or `shared` (§7.4) — and
|
||||||
a reference to the committed outcome. Fence uniqueness is the
|
a reference to the committed outcome. Fence uniqueness is the
|
||||||
pair (operation identifier, key).
|
pair (operation identifier, key).
|
||||||
- **Replay.** A submission whose (operation, key) pair is recorded
|
- **Replay.** A submission whose (operation, key) pair is recorded
|
||||||
is first authorized exactly as a fresh submission would be — an
|
is first authorized exactly as a fresh submission would be — an
|
||||||
actor who is not authorized receives the authorization refusal,
|
actor who is not authorized receives the authorization refusal,
|
||||||
never the recorded outcome. If authorization passes and the
|
never the recorded outcome. If authorization passes, the
|
||||||
recorded actor, scope, and payload digest all equal the
|
submission's declared replay mode equals the recorded row's, and
|
||||||
submission's, the command executes nothing and returns the
|
the recorded scope and payload digest equal the submission's,
|
||||||
recorded outcome.
|
the row's replay mode decides the actor rule: an `actor-bound`
|
||||||
|
row additionally requires the recorded actor to equal the
|
||||||
|
submitter; a `shared` row replays for **any** authorized
|
||||||
|
submitter. On replay the command executes nothing and returns
|
||||||
|
the recorded outcome. A shared replay adds no audit event and
|
||||||
|
leaves the fence row untouched: audit attributes each mutation
|
||||||
|
to the actor who performed it, the recorded acting principal is
|
||||||
|
immutable, and the recorded outcome discloses nothing beyond
|
||||||
|
what the replaying actor's just-verified live authorization
|
||||||
|
already grants — the same mutation that actor could have
|
||||||
|
performed afresh had no fence row existed.
|
||||||
- **Collision.** A submission whose (operation, key) pair is
|
- **Collision.** A submission whose (operation, key) pair is
|
||||||
recorded but whose actor, scope, or payload digest differs is
|
recorded but whose scope, payload digest, or declared replay
|
||||||
|
mode differs — or, against an `actor-bound` row, whose actor
|
||||||
|
differs — is
|
||||||
refused with a single bounded conflict error (contract 5 §4.2);
|
refused with a single bounded conflict error (contract 5 §4.2);
|
||||||
it executes nothing and discloses nothing of the recorded
|
it executes nothing and discloses nothing of the recorded
|
||||||
outcome.
|
outcome.
|
||||||
@@ -405,7 +440,15 @@ collects no sensitive category, so v1 ships no custody surface.
|
|||||||
|
|
||||||
The wizard submits deterministic keys derived from the bootstrap
|
The wizard submits deterministic keys derived from the bootstrap
|
||||||
epoch and the seed role (e.g. epoch id + "seed-company") for every
|
epoch and the seed role (e.g. epoch id + "seed-company") for every
|
||||||
seed mutation. Correlation ids (contract 5 §4.3) remain pure trace
|
seed mutation, and every seed submission declares the `shared`
|
||||||
|
replay mode: the seed set is a per-epoch singleton (§4.4), derived
|
||||||
|
from immutable provenance (§3.4), so whichever currently eligible
|
||||||
|
admin performs a re-run or resume must replay the recorded
|
||||||
|
outcomes rather than collide on actor identity — re-runnability is
|
||||||
|
not restricted to the original acting admin (witness §6.3). All
|
||||||
|
other submissions default to `actor-bound`; nothing in this
|
||||||
|
contract declares `shared` outside the seed sequence. Correlation
|
||||||
|
ids (contract 5 §4.3) remain pure trace
|
||||||
linkage and carry no idempotency semantics. Wizard bookkeeping of
|
linkage and carry no idempotency semantics. Wizard bookkeeping of
|
||||||
seed node ids remains a cache
|
seed node ids remains a cache
|
||||||
(§1.3): losing it cannot cause duplication, because the fence is
|
(§1.3): losing it cannot cause duplication, because the fence is
|
||||||
@@ -519,17 +562,36 @@ Binding on the implementing PRs:
|
|||||||
rename through the hierarchy command), then re-run — the wizard
|
rename through the hierarchy command), then re-run — the wizard
|
||||||
renders the current canonical value, not a stored answer.
|
renders the current canonical value, not a stored answer.
|
||||||
**Seed-provenance witnesses (§3.1, §3.4):** rename the seed
|
**Seed-provenance witnesses (§3.1, §3.4):** rename the seed
|
||||||
company through the hierarchy command, then re-run to completion —
|
company through the hierarchy command, delete the wizard's
|
||||||
|
seed-node bookkeeping cache, then re-run to completion —
|
||||||
the re-derived seed sequence carries the same keys and payload
|
the re-derived seed sequence carries the same keys and payload
|
||||||
digests as the first run (asserted digest equality), every seed
|
digests as the first run (asserted digest equality), every seed
|
||||||
submission replays with the recorded outcome, zero new nodes are
|
submission replays with the recorded outcome, zero new nodes are
|
||||||
created, and the company keeps its renamed name; a re-run
|
created, the run completes, and the company keeps its renamed
|
||||||
|
name — the deleted cache proving the renamed row was resolved
|
||||||
|
from canonical state alone (§1.3), not from a stored id. A re-run
|
||||||
submitting a different company name renames the company row and
|
submitting a different company name renames the company row and
|
||||||
commits no settings write to the seed key; a direct post-epoch
|
commits no settings write to the seed key, **and that same run**,
|
||||||
|
with the bookkeeping cache likewise deleted beforehand, continues
|
||||||
|
through step 4 deriving the seed sequence from the immutable seed
|
||||||
|
parameter — asserted to carry the first run's keys and payload
|
||||||
|
digests, not digests of the newly submitted name — replays every
|
||||||
|
seed outcome, creates zero new nodes, zero new users, and zero
|
||||||
|
new grants, and completes; a direct post-epoch
|
||||||
settings write to `bootstrap.seed-company-name`, by any actor, is
|
settings write to `bootstrap.seed-company-name`, by any actor, is
|
||||||
refused; and a control run that force-mutates a seed payload
|
refused; and a control run that force-mutates a seed payload
|
||||||
digest receives the §4.3 collision refusal, proving the fence
|
digest receives the §4.3 collision refusal, proving the fence
|
||||||
still discriminates.
|
still discriminates.
|
||||||
|
**Second-admin re-run witness (§4.3 shared replay):** after admin
|
||||||
|
A's completed first run, create a second account B and grant it
|
||||||
|
platform-admin and the hierarchy authority the seed commands
|
||||||
|
require (B is freshly authorized, and no text restricts re-runs
|
||||||
|
to A); delete the bookkeeping cache; B re-runs the wizard to
|
||||||
|
completion making no changes — every seed submission replays with
|
||||||
|
A's recorded outcome (asserted by mutation-count and
|
||||||
|
audit-event-count equality across the run, the fence rows still
|
||||||
|
recording A as acting principal), zero new hierarchy nodes,
|
||||||
|
users, grants, or example content exist, and the run completes.
|
||||||
**Second company:** a re-run creating a second company succeeds with
|
**Second company:** a re-run creating a second company succeeds with
|
||||||
the running user as actor and names the creator as `owner` in the
|
the running user as actor and names the creator as `owner` in the
|
||||||
same audited operation — asserted on the single audit event naming
|
same audited operation — asserted on the single audit event naming
|
||||||
@@ -586,13 +648,21 @@ Binding on the implementing PRs:
|
|||||||
mutation-count and audit-event-count equality); the same key with a
|
mutation-count and audit-event-count equality); the same key with a
|
||||||
changed payload digest is refused with the single bounded conflict
|
changed payload digest is refused with the single bounded conflict
|
||||||
and executes nothing; the same key and payload submitted by a
|
and executes nothing; the same key and payload submitted by a
|
||||||
different authorized actor is refused with the same single bounded
|
different authorized actor against an **actor-bound** fence row (a
|
||||||
conflict (actor mismatch) and executes nothing; the same key,
|
control row recorded outside the seed sequence) is refused with
|
||||||
|
the same single bounded conflict (actor mismatch) and executes
|
||||||
|
nothing, while against a **shared** row (every §3.4 seed fence) it
|
||||||
|
replays with the recorded outcome, executing nothing and adding no
|
||||||
|
audit event, the fence row still recording the original actor; a
|
||||||
|
submission whose declared replay mode differs from the recorded
|
||||||
|
row's is refused with the single bounded conflict and executes
|
||||||
|
nothing; the same key,
|
||||||
actor, and payload submitted against a different authorization
|
actor, and payload submitted against a different authorization
|
||||||
scope is likewise refused (scope mismatch) and executes nothing; a
|
scope is likewise refused (scope mismatch) and executes nothing; a
|
||||||
replay by an actor who has since lost
|
replay by an actor who has since lost
|
||||||
eligibility (identity §7.1 ban) receives the authorization refusal,
|
eligibility (identity §7.1 ban) receives the authorization refusal,
|
||||||
not the recorded outcome; a submission that failed before commit
|
not the recorded outcome — asserted against a shared seed fence,
|
||||||
|
proving shared replay never bypasses fresh authorization; a submission that failed before commit
|
||||||
leaves no fence row and its retry executes; two concurrent resumed
|
leaves no fence row and its retry executes; two concurrent resumed
|
||||||
runs executing the seed sequence yield exactly one seed set — per
|
runs executing the seed sequence yield exactly one seed set — per
|
||||||
key, exactly one mutation and one audit event exist, and the losing
|
key, exactly one mutation and one audit event exist, and the losing
|
||||||
@@ -665,7 +735,15 @@ contracts and are not additions:
|
|||||||
fence, with the §4.3 replay, collision, no-error-replay, and
|
fence, with the §4.3 replay, collision, no-error-replay, and
|
||||||
concurrency rules — an addition to contract 5 §4's command
|
concurrency rules — an addition to contract 5 §4's command
|
||||||
envelope, proposed and ratified here, severable from the rest of
|
envelope, proposed and ratified here, severable from the rest of
|
||||||
this contract.
|
this contract. Including the **replay mode**: each keyed
|
||||||
|
submission declares `actor-bound` (default) or `shared`, the
|
||||||
|
declaration is recorded in the fence row, a shared row replays
|
||||||
|
for any freshly authorized actor whose scope and payload digest
|
||||||
|
match while an actor-bound row also requires recorded-actor
|
||||||
|
equality, and a declared-mode mismatch is a collision. This
|
||||||
|
contract declares `shared` for exactly the §3.4 seed sequence —
|
||||||
|
deterministic, epoch-scoped singletons any eligible admin must be
|
||||||
|
able to re-run (§4.1) — and for nothing else.
|
||||||
5. The presentation-and-submission obligation for applicable mandatory
|
5. The presentation-and-submission obligation for applicable mandatory
|
||||||
choices on wizard runs (§3.3).
|
choices on wizard runs (§3.3).
|
||||||
6. The no-server-side-orchestrator architectural constraint (§1.1),
|
6. The no-server-side-orchestrator architectural constraint (§1.1),
|
||||||
|
|||||||
Reference in New Issue
Block a user