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
ci/woodpecker/pr/ci Pipeline was canceled
This commit is contained in:
@@ -122,6 +122,36 @@ 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).
|
||||
|
||||
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
|
||||
host-local install wizard (`mosaic wizard`, which drives host install and
|
||||
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
|
||||
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
|
||||
whichever currently eligible admin holding §4.3 target-result
|
||||
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 is provenance the derivation reads, never a value any
|
||||
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 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.
|
||||
submitter; a `shared` row replays for an authorized submitter
|
||||
who also passes **target-result authorization**. Returning a
|
||||
recorded outcome is a read of the canonical records that
|
||||
outcome references, and fresh-mutation authorization is not
|
||||
read authorization on records another actor already created: a
|
||||
shared replay therefore additionally requires the submitter to
|
||||
hold, at replay time, read authority on every canonical record
|
||||
the recorded outcome references, under each record's owning
|
||||
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
|
||||
recorded but whose scope, payload digest, or declared replay
|
||||
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);
|
||||
it executes nothing and discloses nothing of the recorded
|
||||
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
|
||||
mutation, so only committed outcomes are ever recorded. A failed
|
||||
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
|
||||
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
|
||||
(fresh-mutation authorization first — and, for a shared 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
|
||||
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`
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
(§1.3): losing it cannot cause duplication, because the fence is
|
||||
canonical command-layer state. A re-run offers to create
|
||||
@@ -584,14 +668,21 @@ Binding on the implementing PRs:
|
||||
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.
|
||||
platform-admin, the hierarchy authority the seed commands
|
||||
require, and **explicit target-result read authority on every
|
||||
recorded seed target** — a contract 2 grant conferring read on
|
||||
the seed company and its seeded children (B is freshly
|
||||
authorized with explicit target authority, 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 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
|
||||
the running user as actor and names the creator as `owner` in the
|
||||
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
|
||||
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
|
||||
mutation-count and mutation-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 against an **actor-bound** fence row (a
|
||||
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
|
||||
nothing, while against a **shared** row (every §3.4 seed fence) a
|
||||
different authorized actor holding target-result read authority
|
||||
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
|
||||
row's is refused with the single bounded conflict and executes
|
||||
nothing; the same key,
|
||||
@@ -662,14 +757,42 @@ Binding on the implementing PRs:
|
||||
replay by an actor who has since lost
|
||||
eligibility (identity §7.1 ban) receives the authorization refusal,
|
||||
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
|
||||
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
|
||||
key, exactly one mutation and one mutation audit event exist, and
|
||||
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
|
||||
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
|
||||
executes both independently, each committing its own mutation,
|
||||
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
|
||||
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
|
||||
for a freshly authorized actor whose scope and payload digest
|
||||
match and who additionally passes the §4.3 target-result
|
||||
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 —
|
||||
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.
|
||||
5. The presentation-and-submission obligation for applicable mandatory
|
||||
choices on wizard runs (§3.3).
|
||||
|
||||
Reference in New Issue
Block a user