docs: onboarding-wizard contract revision 8 (sol r7 NEW-9: shared replay target-result authorization, seed-only boundary, replay access event)
ci/woodpecker/pr/ci Pipeline was canceled

This commit is contained in:
fred
2026-08-26 22:30:22 -05:00
parent 84fe8b6ef1
commit eff3b91478
+177 -36
View File
@@ -122,6 +122,36 @@ digests asserted, every seed outcome replayed, zero new nodes, run
completed — proving the dirty form value never enters derivation and completed — proving the dirty form value never enters derivation and
the renamed row resolves cache-independently (F6). the renamed row resolves cache-independently (F6).
Revision 8 (sol re-review 6: NEW-9): shared replay gains a
**target-result authorization boundary** — returning a recorded
outcome is a read of the canonical records it references, authorized
separately from fresh-mutation authorization: a shared replay
requires the submitter to hold, at replay time, read authority on
every record the recorded outcome references, and a submitter who
passes the fresh-mutation check but lacks target read authority is
refused with the same constant-shape single bounded conflict as a
§4.3 collision, identifying no record — the response confirms no
tenant target's existence, preserving RBAC §7's no-existence-oracle
rule (§4.3). `shared` becomes server-verified seed-only policy: the
command layer re-derives the epoch's **canonical seed tuple set**
from canonical state alone and refuses any shared declaration whose
(operation, key, scope, digest) tuple is not a member, and a missing
seed fence is originated only by a submission passing the full
fresh-mutation authorization for that seed command — a wrong actor
cannot win an unrecorded seed key, and no shared row can exist
outside the seed sequence (§4.3). An authorized shared replay appends
a **replay access event** — a distinct non-mutation audit event class
recording the replaying actor, the current request's correlation ids,
and the fence row whose outcome was returned — so every access to a
recorded outcome is attributed without a duplicate semantic mutation
event, while the fence row and the mutation event immutably retain
the original actor (§4.3, §7.4). §6.7 adds the unauthorized-target
replay refusal, the non-seed shared declaration refusal, and the
unrecorded-seed-key race; §6.3's second-admin witness grants B
explicit read authority on the recorded seed targets and asserts B's
replay access events; replay-affected count equalities are scoped to
the mutation event class (NEW-9).
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);
@@ -345,8 +375,9 @@ the named authority:
(recorded outcomes) rather than collide, regardless of any (recorded outcomes) rather than collide, regardless of any
hierarchy rename performed since — and, because every seed hierarchy rename performed since — and, because every seed
submission declares §4.3's `shared` replay mode, they replay for submission declares §4.3's `shared` replay mode, they replay for
whichever currently eligible admin performs the re-run, not only whichever currently eligible admin holding §4.3 target-result
the actor the fence rows record. The §4.3 fence, not the read authority on the recorded seed targets 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.
@@ -409,15 +440,37 @@ collects no sensitive category, so v1 ships no custody surface.
the recorded scope and payload digest equal the submission's, the recorded scope and payload digest equal the submission's,
the row's replay mode decides the actor rule: an `actor-bound` the row's replay mode decides the actor rule: an `actor-bound`
row additionally requires the recorded actor to equal the row additionally requires the recorded actor to equal the
submitter; a `shared` row replays for **any** authorized submitter; a `shared` row replays for an authorized submitter
submitter. On replay the command executes nothing and returns who also passes **target-result authorization**. Returning a
the recorded outcome. A shared replay adds no audit event and recorded outcome is a read of the canonical records that
leaves the fence row untouched: audit attributes each mutation outcome references, and fresh-mutation authorization is not
to the actor who performed it, the recorded acting principal is read authorization on records another actor already created: a
immutable, and the recorded outcome discloses nothing beyond shared replay therefore additionally requires the submitter to
what the replaying actor's just-verified live authorization hold, at replay time, read authority on every canonical record
already grants — the same mutation that actor could have the recorded outcome references, under each record's owning
performed afresh had no fence row existed. contract's read-authorization rules (for the seed targets, the
contract 2 grant model — RBAC §1.1 platform-admin standing
confers none of it). A submitter who passes the fresh-mutation
check but fails target-result authorization is refused with the
same single bounded conflict error as a collision below —
constant in shape, identifying no record, disclosing nothing of
the recorded outcome or its targets — so the refusal confirms
no tenant target's existence or identity and RBAC §7's
no-existence-oracle rule is preserved. On replay the command
executes nothing and returns the recorded outcome. A shared
replay adds no **mutation** audit event and leaves the fence
row untouched — audit attributes each mutation to the actor who
performed it, and the recorded acting principal is immutable —
but it appends a **replay access event**: a distinct
non-mutation audit event class recording the replaying actor as
accessing principal, the current request's correlation ids
(contract 5 §4.3), and a reference to the fence row whose
outcome was returned. The current submission's correlation
travels only in that access event and the trace layer; the
recorded outcome and its original mutation event are returned
and retained unchanged. Every access to a recorded outcome is
thereby attributed to its accessing actor without a duplicate
semantic mutation event ever existing.
- **Collision.** A submission whose (operation, key) pair is - **Collision.** A submission whose (operation, key) pair is
recorded but whose scope, payload digest, or declared replay recorded but whose scope, payload digest, or declared replay
mode differs — or, against an `actor-bound` row, whose actor mode differs — or, against an `actor-bound` row, whose actor
@@ -425,6 +478,30 @@ collects no sensitive category, so v1 ships no custody surface.
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.
- **Shared-declaration boundary.** `shared` is a server-verified,
seed-only policy, never a caller privilege. The command layer
re-derives, from canonical state alone, the **canonical seed
tuple set** of the current bootstrap epoch: the exact
(operation identifier, key, authorization scope, payload
digest) tuples of §3.4's ordered seed sequence, derived from
the epoch id, the immutable `bootstrap.seed-company-name`
provenance, and the fixed example set — the same derivation
§3.4 requires of a fresh client. A submission declaring
`shared` whose tuple is not a member of that set is refused
with a single bounded refusal (contract 5 §4.2 validation
class) that executes nothing and records no fence row. No
other operation can carry a shared declaration, so no shared
fence row can exist outside the seed sequence — the seed-only
rule is enforced by the command layer, not by wizard
convention. **Origination.** A shared fence row not yet
recorded is originated only by executing its seed mutation:
the originating submission passes the full fresh-mutation
authorization for that seed command (§5.2 eligibility plus the
hierarchy authority the command itself requires), and a
refused submission records no row (no-error replay below). An
actor without the seed mutation's authority therefore cannot
win an unrecorded seed key, and the recorded actor of every
shared row was authorized for the mutation the row fences.
- **No error replay.** The fence row commits only with its - **No error replay.** The fence row commits only with its
mutation, so only committed outcomes are ever recorded. A failed mutation, so only committed outcomes are ever recorded. A failed
or refused submission records no fence row; a retry executes or refused submission records no fence row; a retry executes
@@ -433,8 +510,9 @@ collects no sensitive category, so v1 ships no custody surface.
pair serialize on the fence's unique constraint: exactly one pair serialize on the fence's unique constraint: exactly one
executes. The loser waits for the winner's transaction to executes. The loser waits for the winner's transaction to
resolve; if it committed, the loser is handled as a replay resolve; if it committed, the loser is handled as a replay
(authorization first, then the recorded outcome, or the (fresh-mutation authorization first — and, for a shared row,
collision refusal on mismatch); if it aborted, no fence row target-result authorization — 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 exists and the loser executes. The loser never performs a second
mutation and is never left without a defined response. mutation and is never left without a defined response.
@@ -443,13 +521,19 @@ collects no sensitive category, so v1 ships no custody surface.
seed mutation, and every seed submission declares the `shared` seed mutation, and every seed submission declares the `shared`
replay mode: the seed set is a per-epoch singleton (§4.4), derived replay mode: the seed set is a per-epoch singleton (§4.4), derived
from immutable provenance (§3.4), so whichever currently eligible from immutable provenance (§3.4), so whichever currently eligible
admin performs a re-run or resume must replay the recorded admin holding target-result read authority on the recorded seed
targets performs a re-run or resume must replay the recorded
outcomes rather than collide on actor identity — re-runnability is outcomes rather than collide on actor identity — re-runnability is
not restricted to the original acting admin (witness §6.3). All not restricted to the original acting admin (witness §6.3). All
other submissions default to `actor-bound`; nothing in this other submissions default to `actor-bound`; nothing in this
contract declares `shared` outside the seed sequence. Correlation contract declares `shared` outside the seed sequence, and the
shared-declaration boundary makes that exclusivity
server-enforced: a shared declaration outside the canonical seed
tuple set is refused, not merely unconventional. Correlation
ids (contract 5 §4.3) remain pure trace ids (contract 5 §4.3) remain pure trace
linkage and carry no idempotency semantics. Wizard bookkeeping of linkage and carry no idempotency semantics; a shared replay's
current correlation is carried by its §4.3 replay access event,
never by rewriting the recorded outcome or its mutation event. 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
canonical command-layer state. A re-run offers to create canonical command-layer state. A re-run offers to create
@@ -584,14 +668,21 @@ Binding on the implementing PRs:
still discriminates. still discriminates.
**Second-admin re-run witness (§4.3 shared replay):** after admin **Second-admin re-run witness (§4.3 shared replay):** after admin
A's completed first run, create a second account B and grant it A's completed first run, create a second account B and grant it
platform-admin and the hierarchy authority the seed commands platform-admin, the hierarchy authority the seed commands
require (B is freshly authorized, and no text restricts re-runs require, and **explicit target-result read authority on every
to A); delete the bookkeeping cache; B re-runs the wizard to recorded seed target** — a contract 2 grant conferring read on
completion making no changes — every seed submission replays with the seed company and its seeded children (B is freshly
A's recorded outcome (asserted by mutation-count and authorized with explicit target authority, and no text restricts
audit-event-count equality across the run, the fence rows still re-runs to A); delete the bookkeeping cache; B re-runs the
recording A as acting principal), zero new hierarchy nodes, wizard to completion making no changes — every seed submission
users, grants, or example content exist, and the run completes. replays with A's recorded outcome (asserted by mutation-count
and mutation-audit-event-count equality across the run, the
fence rows still recording A as acting principal), exactly one
§4.3 replay access event exists per replayed submission, each
naming B as accessing principal and carrying B's run's
correlation ids while referencing A's fence row, 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
@@ -645,15 +736,19 @@ Binding on the implementing PRs:
outcome. **Idempotency-fence witnesses (§4.3):** re-submitting a outcome. **Idempotency-fence witnesses (§4.3):** re-submitting a
committed seed command with its same key, actor, and payload committed seed command with its same key, actor, and payload
executes nothing and returns the recorded outcome (asserted by executes nothing and returns the recorded outcome (asserted by
mutation-count and audit-event-count equality); the same key with a mutation-count and mutation-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 against an **actor-bound** fence row (a different authorized actor against an **actor-bound** fence row (a
control row recorded outside the seed sequence) is refused with control row recorded outside the seed sequence) is refused with
the same single bounded conflict (actor mismatch) and executes the same single bounded conflict (actor mismatch) and executes
nothing, while against a **shared** row (every §3.4 seed fence) it nothing, while against a **shared** row (every §3.4 seed fence) a
replays with the recorded outcome, executing nothing and adding no different authorized actor holding target-result read authority
audit event, the fence row still recording the original actor; a replays with the recorded outcome, executing nothing, adding no
mutation audit event, and appending exactly one replay access
event naming the replaying actor and its correlation ids, the
fence row still recording the original actor; a
submission whose declared replay mode differs from the recorded submission whose declared replay mode differs from the recorded
row's is refused with the single bounded conflict and executes row's is refused with the single bounded conflict and executes
nothing; the same key, nothing; the same key,
@@ -662,14 +757,42 @@ Binding on the implementing PRs:
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 — asserted against a shared seed fence, not the recorded outcome — asserted against a shared seed fence,
proving shared replay never bypasses fresh authorization; a submission that failed before commit proving shared replay never bypasses fresh authorization.
**Target-authorization and boundary witnesses (§4.3, NEW-9):**
an **unauthorized-target shared replay** — a platform admin
holding §5.2 fresh-create eligibility but no contract 2 grant on
the seed company derives the canonical seed tuple per §3.4 and
submits it with the recorded `shared` mode — is refused with the
single bounded conflict, and the refusal response is asserted
byte-shape-identical to the changed-digest collision refusal
above (same error class, same fields, no record identifier, no
scope detail beyond the caller's own submission), executes
nothing, changes no fence row, and appends no mutation audit
event — proving the recorded target is neither returned nor
confirmed to exist and RBAC §7's no-existence-oracle rule holds
at the fence; a **non-seed shared declaration** — an ordinary
hierarchy or content command whose tuple is outside the
canonical seed tuple set, submitted with `shared` declared by an
actor fully authorized for the mutation — is refused with the
§4.3 validation refusal, executes nothing, and records no fence
row (asserted absent); an **unrecorded-seed-key race** — with
one seed tuple deliberately left unrecorded, an actor lacking
that seed command's hierarchy authority races the authorized
resume for the same (operation, key): the unauthorized
submission receives the authorization refusal and records no
fence row, the authorized submission executes afresh, and the
resulting fence row records the authorized actor — proving
origination of a missing seed fence is bound to full
fresh-mutation 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 mutation audit event exist, and
submission received the winner's recorded outcome; and with the the losing
submission received the winner's recorded outcome (its access
attributed by the §4.3 replay access event); and with the
winner's transaction forced to abort, the waiting loser finds no winner's transaction forced to abort, the waiting loser finds no
fence row, executes, and commits exactly one mutation and one fence row, executes, and commits exactly one mutation and one
audit event. Two envelope-shape witnesses complete the §4.3 mutation audit event. Two envelope-shape witnesses complete the §4.3
coverage: the same raw key submitted to two DIFFERENT operations coverage: the same raw key submitted to two DIFFERENT operations
executes both independently, each committing its own mutation, executes both independently, each committing its own mutation,
audit event, and fence row — proving uniqueness is the audit event, and fence row — proving uniqueness is the
@@ -738,11 +861,29 @@ contracts and are not additions:
this contract. Including the **replay mode**: each keyed this contract. Including the **replay mode**: each keyed
submission declares `actor-bound` (default) or `shared`, the submission declares `actor-bound` (default) or `shared`, the
declaration is recorded in the fence row, a shared row replays declaration is recorded in the fence row, a shared row replays
for any freshly authorized actor whose scope and payload digest for a freshly authorized actor whose scope and payload digest
match while an actor-bound row also requires recorded-actor match and who additionally passes the §4.3 target-result
equality, and a declared-mode mismatch is a collision. This authorization — read authority on every canonical record the
recorded outcome references, refused otherwise with the
constant-shape conflict that preserves RBAC §7's
no-existence-oracle rule — while an actor-bound row also
requires recorded-actor
equality, and a declared-mode mismatch is a collision. Including
the **shared-declaration boundary**: `shared` is server-verified
against the epoch's canonical seed tuple set re-derived from
canonical state, a shared declaration outside that set is
refused recording nothing, and origination of a missing seed
fence requires the full fresh-mutation authorization for that
seed command (§4.3). Including the **replay access event**: a
distinct non-mutation audit event class, appended on every
shared replay, recording the accessing actor, the current
request's correlation ids, and the fence row returned — the
disclosed mechanism by which a replay's access is attributed
without a duplicate semantic mutation event, the fence row and
mutation event immutably retaining the original actor. This
contract declares `shared` for exactly the §3.4 seed sequence — contract declares `shared` for exactly the §3.4 seed sequence —
deterministic, epoch-scoped singletons any eligible admin must be deterministic, epoch-scoped singletons any eligible,
target-authorized admin must be
able to re-run (§4.1) — and for nothing else. 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).