docs: onboarding-wizard contract revision 9 (sol r8 NEW-9 residual: prefix-derived seed tuples + seed-origin gate; NEW-10: target-result authorization on every replay mode)
ci/woodpecker/pr/ci Pipeline failed
ci/woodpecker/pr/ci Pipeline failed
This commit is contained in:
@@ -152,6 +152,33 @@ 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).
|
||||
|
||||
Revision 9 (sol re-review 7: NEW-9 residual, NEW-10): the seed
|
||||
boundary becomes server-complete and oracle-free. The **canonical
|
||||
seed key set** is fence-independent (epoch id plus the fixed
|
||||
seed-role list), while the full tuple set is **prefix-derived**: each
|
||||
position's scope and payload digest derive from the committed
|
||||
predecessors' recorded fence outcomes, the derivable members at any
|
||||
state are the committed prefix plus the next unrecorded position,
|
||||
the pre-first-company state derives exactly the seed-company tuple,
|
||||
and an out-of-order shared declaration is refused recording nothing
|
||||
(§4.3, §3.4). The epoch gains one immutable **seed-origin account**
|
||||
— the first admin the finalize transaction created — and a
|
||||
**seed-boundary gate** evaluated after fresh-mutation authorization
|
||||
and before fence presence can affect the response: a submitter on a
|
||||
canonical seed key who is neither the seed-origin account nor holds
|
||||
target-result read authority on the position's recorded targets
|
||||
receives the constant-shape bounded conflict, identical across the
|
||||
recorded and unrecorded worlds, creating nothing in either — so
|
||||
§5.2 eligibility alone can never originate a seed fence and the
|
||||
eligible-wrong-actor race on the top-level seed-company key is
|
||||
closed (NEW-9; witnesses §6.7: the two-world control and the
|
||||
top-level origination race). Target-result authorization extends to
|
||||
**every replay mode**: an `actor-bound` replay requires the recorded
|
||||
actor to hold live read authority on every record the recorded
|
||||
outcome references, actor equality remaining an additional
|
||||
condition, never a substitute — a creator whose grants were revoked
|
||||
is refused, not replayed (NEW-10; §6.7 lost-target-grant witness).
|
||||
|
||||
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);
|
||||
@@ -368,7 +395,11 @@ the named authority:
|
||||
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
|
||||
§4.3 keys from that canonical state alone, prefix-wise: each
|
||||
position's scope and payload derive from the committed
|
||||
predecessors' recorded outcomes, so the run walks the order and
|
||||
never precomputes a tuple past the next unrecorded position
|
||||
(§4.3 shared-declaration boundary). 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
|
||||
@@ -382,9 +413,13 @@ the named authority:
|
||||
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,
|
||||
command under §5.2's eligibility policy, with the new admin — the
|
||||
epoch's §4.3 seed-origin account — as actor,
|
||||
naming the admin as initial `owner` in the same audited operation
|
||||
(contract 2 §4.3). The initial estate, initial project, and initial
|
||||
(contract 2 §4.3); the §4.3 seed-boundary gate reserves
|
||||
origination of the canonical seed tuples to that account, while
|
||||
the same command outside the canonical seed key set follows §5.2
|
||||
unchanged. 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
|
||||
@@ -438,19 +473,24 @@ collects no sensitive category, so v1 ships no custody surface.
|
||||
never the recorded outcome. If authorization passes, the
|
||||
submission's declared replay mode equals the recorded row's, and
|
||||
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 an authorized submitter
|
||||
who also passes **target-result authorization**. Returning a
|
||||
the submitter must pass **target-result authorization** — in
|
||||
every replay mode. 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
|
||||
outcome references, and neither fresh-mutation authorization
|
||||
nor recorded-actor identity is
|
||||
read authorization on those records: every replay, `shared` or
|
||||
`actor-bound`, 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
|
||||
confers none of it). Actor equality is the additional
|
||||
`actor-bound` condition, never a substitute for target-result
|
||||
authorization: an `actor-bound` row replays only for the
|
||||
recorded actor, and only while that actor holds live
|
||||
target-result read authority — an original actor whose grants
|
||||
on the referenced records were since revoked is refused, not
|
||||
replayed (witness §6.7). 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
|
||||
@@ -479,29 +519,77 @@ collects no sensitive category, so v1 ships no custody surface.
|
||||
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.
|
||||
seed-only policy, never a caller privilege. The boundary has a
|
||||
fence-independent part and a prefix-derived part. The
|
||||
**canonical seed key set** — the (operation identifier, key)
|
||||
pairs of §3.4's ordered seed sequence — is derived from the
|
||||
epoch id and the fixed seed-role list alone: the keys are
|
||||
deterministic and depend on no generated id, so membership is
|
||||
decidable before any seed mutation has run and without
|
||||
consulting the fence table. The full **canonical seed tuple
|
||||
set** is prefix-derived, because later seed tuples embed
|
||||
generated ids: the tuple at seed position k — its
|
||||
authorization scope and payload digest — is derived from the
|
||||
epoch id, the immutable `bootstrap.seed-company-name`
|
||||
provenance, the fixed example set, and the canonical recorded
|
||||
outcomes of positions 1 through k−1 (the ids the committed
|
||||
predecessor fence rows reference). At any canonical state
|
||||
exactly these members are derivable: every committed-prefix
|
||||
tuple (read back from its fence row) and the next unrecorded
|
||||
tuple in order. Before the first company exists, the derivable
|
||||
set is exactly the seed-company tuple. A fresh client derives
|
||||
the same way — §3.4's derivation is this walk: submit the
|
||||
sequence in order, learning each generated id from the
|
||||
returned recorded outcome or the submission's own execution,
|
||||
never precomputing a tuple past the next position. A
|
||||
submission declaring `shared` whose (operation, key) is
|
||||
outside the canonical seed key set, whose tuple does not equal
|
||||
its position's derived tuple, or whose position lies past the
|
||||
next unrecorded position (out of order) 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.
|
||||
- **Seed-boundary gate and origination.** The epoch has one
|
||||
immutable **seed-origin account**: the account the §3.3
|
||||
finalize transaction created as the epoch's first admin
|
||||
(identity §3) — provenance the epoch record fixes at finalize
|
||||
and nothing changes afterwards. Every mutating submission
|
||||
whose (operation, key) is in the canonical seed key set —
|
||||
whatever replay mode it declares — passes, after
|
||||
fresh-mutation authorization and before the fence table is
|
||||
consulted, the **seed-boundary gate**: the submitter is the
|
||||
seed-origin account, or holds §4.3 target-result read
|
||||
authority on the canonical records the position's recorded
|
||||
outcome references. A submitter satisfying neither is refused
|
||||
with the same single bounded conflict error as a collision —
|
||||
and because the gate is evaluated without consulting fence
|
||||
presence, the refusal is byte-shape-identical whether the seed
|
||||
fence and its targets exist or not: the recorded and
|
||||
unrecorded worlds are indistinguishable to that submitter, no
|
||||
mutation or fence row is created in either, and RBAC §7's
|
||||
no-existence-oracle rule holds at the seed boundary itself,
|
||||
not merely at an existing fence (witness §6.7). For an
|
||||
unrecorded position no recorded outcome exists to hold read
|
||||
authority on, so only the seed-origin account can proceed to
|
||||
origination: §5.2 eligibility alone never originates a seed
|
||||
fence, which closes the eligible-wrong-actor race on the
|
||||
top-level seed-company key. **Origination.** A seed fence row
|
||||
not yet recorded is originated only by the seed-origin account
|
||||
executing its seed mutation in order, passing the full
|
||||
fresh-mutation authorization for that seed command (§5.2
|
||||
eligibility plus the hierarchy authority the command itself
|
||||
requires); a refused submission records no row (no-error
|
||||
replay below). The recorded actor of every shared row is
|
||||
therefore the seed-origin account, authorized for the mutation
|
||||
the row fences. If the seed-origin account is banned or
|
||||
deleted while seed positions remain unoriginated, those
|
||||
positions are unoriginatable for this epoch — an accepted
|
||||
consequence of the immutable boundary; factory reset (§4.2),
|
||||
which opens a new epoch with a new first admin, is the
|
||||
recovery path. Recorded positions are unaffected: any admin
|
||||
holding target-result read authority replays them (§6.3).
|
||||
- **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
|
||||
@@ -510,8 +598,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
|
||||
(fresh-mutation authorization first — and, for a shared row,
|
||||
target-result authorization — then the recorded outcome, or
|
||||
(fresh-mutation authorization, the seed-boundary gate where
|
||||
the key is a seed key, and target-result 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.
|
||||
@@ -770,20 +859,64 @@ Binding on the implementing PRs:
|
||||
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
|
||||
at the fence; the **two-world seed-boundary control (§4.3
|
||||
seed-boundary gate)** — the SAME eligible non-originator actor
|
||||
submits the exact canonical seed-company tuple in two prepared
|
||||
worlds: one where the seed fence and its targets exist (the
|
||||
recorded world) and one freshly finalized epoch where they do
|
||||
not (the unrecorded world, before any seed command has run) —
|
||||
and in both worlds receives the identical bounded conflict
|
||||
refusal (asserted byte-shape-identical across the two worlds and
|
||||
to the collision refusal), executes nothing, and creates no
|
||||
mutation, fence row, or hierarchy node in either — proving the
|
||||
response is computed without consulting fence presence, the
|
||||
recorded and unrecorded worlds are indistinguishable to that
|
||||
actor, and no eligible wrong actor can originate the top-level
|
||||
seed 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
|
||||
row (asserted absent); an **out-of-order shared declaration** —
|
||||
with the seed prefix committed through position k, the
|
||||
seed-origin account submits the position k+2 tuple (past the
|
||||
next unrecorded position), constructed by the test harness from
|
||||
ids it obtained out of band — and is refused with the §4.3
|
||||
validation refusal, executes nothing, and records no fence row,
|
||||
proving the prefix-aware derivation rejects positions the
|
||||
canonical walk cannot yet derive; an **unrecorded-seed-key
|
||||
race** in two variants — (child variant) with one child seed
|
||||
tuple deliberately left unrecorded, an actor lacking that seed
|
||||
command's hierarchy authority races the seed-origin account's
|
||||
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
|
||||
fence row, the origin account's submission executes afresh, and
|
||||
the resulting fence row records the seed-origin account;
|
||||
(top-level variant, NEW-9) with the seed-company tuple
|
||||
unrecorded, an eligible platform admin who is not the
|
||||
seed-origin account — passing §5.2 fresh-mutation authorization
|
||||
in full, since the top-level command requires no hierarchy
|
||||
authority — races the seed-origin account for the seed-company
|
||||
(operation, key): the non-originator receives the constant
|
||||
bounded conflict refusal from the seed-boundary gate and
|
||||
records no fence row and no company, the seed-origin account
|
||||
executes afresh, and the resulting fence row records the
|
||||
seed-origin account — proving origination of a missing seed
|
||||
fence is bound to the seed-origin account, not to eligibility
|
||||
alone; an **actor-bound lost-target-grant replay (NEW-10)** — an
|
||||
actor creates a non-seed top-level company under an
|
||||
`actor-bound` key, grants a second account `owner`, and the
|
||||
second account then revokes every grant the creator held on the
|
||||
company; the creator, still authenticated and eligible,
|
||||
resubmits the exact recorded (operation, key, scope, payload,
|
||||
mode) tuple — actor equality holds but live target-result
|
||||
authorization fails, so the submission is refused with the
|
||||
single bounded conflict, executes nothing, returns nothing of
|
||||
the recorded outcome, and appends no access or mutation event;
|
||||
re-granting the creator read authority and resubmitting returns
|
||||
the recorded outcome — proving actor equality is never a
|
||||
substitute for live target-result read authority on any replay
|
||||
mode; 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 mutation audit event exist, and
|
||||
@@ -860,21 +993,34 @@ contracts and are not additions:
|
||||
envelope, proposed and ratified here, severable from the rest of
|
||||
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 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
|
||||
declaration is recorded in the fence row, and every replay — in
|
||||
either mode — requires the submitter, freshly authorized with
|
||||
matching scope and payload digest, to pass the §4.3
|
||||
target-result authorization: read authority, live at replay
|
||||
time, on every canonical record the recorded outcome
|
||||
references, refused otherwise with the constant-shape conflict
|
||||
that preserves RBAC §7's no-existence-oracle rule. An
|
||||
actor-bound row additionally requires recorded-actor equality —
|
||||
never as a substitute for target-result authority — 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
|
||||
against the epoch's canonical seed key set (fence-independent,
|
||||
derived from the epoch id and the fixed seed-role list) and its
|
||||
prefix-derived canonical seed tuple set — each position's scope
|
||||
and digest derived from the committed predecessors' recorded
|
||||
outcomes — with a shared declaration outside the key set, off
|
||||
its position's derived tuple, or past the next unrecorded
|
||||
position refused recording nothing (§4.3). Including the
|
||||
**seed-boundary gate**: the epoch's immutable seed-origin
|
||||
account is the first admin the finalize transaction created;
|
||||
every submission on a canonical seed key must be that account
|
||||
or hold target-result read authority on the position's recorded
|
||||
targets, refused otherwise with the constant-shape conflict
|
||||
evaluated before fence presence — so recorded and unrecorded
|
||||
worlds are indistinguishable to the refused submitter — and
|
||||
origination of a missing seed fence is reserved to the
|
||||
seed-origin account passing 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
|
||||
|
||||
Reference in New Issue
Block a user