shared replay mode refused (seed-only rule, contract 3 SS4.3/SS7 item 4); concurrency loser semantics and scope-mismatch collision added to rule 5 and witness 5; query-side correlation envelope specified; no-oracle indistinguishability probe added to witness 9; fence authorization scope pinned; SHARED-CONTRACT SS5.3 citation fixed, fleet-side ASKS reference removed.
This commit is contained in:
@@ -112,10 +112,10 @@ One command, one query. Module: `apps/gateway/src/enrollment/`
|
|||||||
Request DTO (shared types package, class-validator at the boundary):
|
Request DTO (shared types package, class-validator at the boundary):
|
||||||
|
|
||||||
| Field | Type | Rule |
|
| Field | Type | Rule |
|
||||||
| ---------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ---------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `harness` | string | syntactically invalid (empty/malformed) → `validation_failed`; well-formed but not in the harness registry → `precondition_failed` |
|
| `harness` | string | syntactically invalid (empty/malformed) → `validation_failed`; well-formed but not in the harness registry → `precondition_failed` |
|
||||||
| `correlationId` | string (uuid) | optional; generated when absent (contract 5 §4.3); carried into audit events and returned in the result |
|
| `correlationId` | string (uuid) | optional; generated when absent (contract 5 §4.3); carried into audit events and returned in the result |
|
||||||
| `replayMode` | 'actor-bound' \| 'shared' | optional, default `actor-bound` (contract 3 §4.3) |
|
| `replayMode` | 'actor-bound' | optional, default `actor-bound`. `shared` is seed-only (contract 3 §4.3 binds it to the §3.4 canonical seed key set and "no other operation can carry a shared declaration"; §7 item 4 closes it); a `shared` declaration here is refused `validation_failed`, executes nothing, and records no fence row |
|
||||||
| `name` | string | non-empty, trimmed, ≤ 200 chars |
|
| `name` | string | non-empty, trimmed, ≤ 200 chars |
|
||||||
| `persona` | string \| null | optional; stored as the agent's system prompt |
|
| `persona` | string \| null | optional; stored as the agent's system prompt |
|
||||||
| `model` | string | non-empty (provider-qualified model id) |
|
| `model` | string | non-empty (provider-qualified model id) |
|
||||||
@@ -149,21 +149,35 @@ Rules:
|
|||||||
authorization scope, a digest of the canonicalized request payload
|
authorization scope, a digest of the canonicalized request payload
|
||||||
(the digest input EXCLUDES the credential value — it covers
|
(the digest input EXCLUDES the credential value — it covers
|
||||||
provider + credentialMode, never plaintext), the declared replay
|
provider + credentialMode, never plaintext), the declared replay
|
||||||
mode (`actor-bound` default / `shared`), and a reference to the
|
mode (always `actor-bound` for this family — the `shared` refusal
|
||||||
committed outcome (the agent id). Fence uniqueness is the pair
|
in the table above means no shared fence row can exist here; the
|
||||||
(operation identifier, key). **Replay:** a submission whose
|
column is kept for envelope-shape fidelity and mode-mismatch
|
||||||
|
collision checks), and a reference to the committed outcome (the
|
||||||
|
agent id). The recorded **authorization scope** for this family is
|
||||||
|
pinned to the acting principal's platform-user scope (v1
|
||||||
|
authorization is grant-free per rule 4, so the scope is the
|
||||||
|
authenticated-user identity domain — recorded so the §4.3
|
||||||
|
scope-equality check has a defined value). Fence uniqueness is the
|
||||||
|
pair (operation identifier, key). **Replay:** a submission whose
|
||||||
(operation, key) is recorded is first authorized exactly as a fresh
|
(operation, key) is recorded is first authorized exactly as a fresh
|
||||||
submission; then replay-mode, scope, and digest equality are
|
submission; then replay-mode, scope, and digest equality are
|
||||||
checked; then **target-result authorization** — the submitter must
|
checked (a mismatch on any — including scope — is a collision);
|
||||||
hold, at replay time, read authority on the referenced agent row
|
then **target-result authorization** — the submitter must hold, at
|
||||||
under §3.2's rule (owner or admin) — in every mode, with
|
replay time, read authority on the referenced agent row under
|
||||||
recorded-actor equality as the additional `actor-bound` condition.
|
§3.2's rule (owner or admin) — plus recorded-actor equality
|
||||||
A passing replay executes nothing, returns the recorded outcome,
|
(`actor-bound`). A passing replay executes nothing, returns the
|
||||||
and appends a replay access event (non-mutation audit class:
|
recorded outcome, and appends a replay access event (non-mutation
|
||||||
accessing principal, current correlation id, fence-row reference).
|
audit class: accessing principal, current correlation id,
|
||||||
Any equality or authorization failure refuses with the single
|
fence-row reference). Any equality or authorization failure refuses
|
||||||
bounded `conflict` shape — constant, identifying no record —
|
with the single bounded `conflict` shape — constant, identifying no
|
||||||
preserving the no-existence-oracle rule.
|
record — preserving the no-existence-oracle rule. **Concurrency
|
||||||
|
(contract 3 §4.3's rule, ratified via §7 item 4):** two submissions
|
||||||
|
with the same (operation, key) serialize on the fence's unique
|
||||||
|
constraint — exactly one executes; the loser waits for the winner's
|
||||||
|
transaction, and is then handled as a replay if it committed
|
||||||
|
(through the full replay path above) or executes afresh if it
|
||||||
|
aborted. A unique-violation race never surfaces as an unhandled
|
||||||
|
internal fault.
|
||||||
6. **Audit + outbox, same transaction.** Insert into `agents` +
|
6. **Audit + outbox, same transaction.** Insert into `agents` +
|
||||||
sealed credential write (intake mode) + fence row + semantic audit
|
sealed credential write (intake mode) + fence row + semantic audit
|
||||||
event (`agent.enrolled`: actor, agent id, harness, provider, name,
|
event (`agent.enrolled`: actor, agent id, harness, provider, name,
|
||||||
@@ -184,6 +198,14 @@ By agent id; actor must be the owner (or admin). Unauthorized and
|
|||||||
missing fold to the same `not_found` wire shape (contract 2
|
missing fold to the same `not_found` wire shape (contract 2
|
||||||
no-existence-oracle rule, applied family-wide for uniformity).
|
no-existence-oracle rule, applied family-wide for uniformity).
|
||||||
|
|
||||||
|
The query carries the same non-state envelope as the mutation
|
||||||
|
(contract 5 §4.3; contract 3's envelope reconciliation confirms closed
|
||||||
|
query responses carry it): typed request DTO with an optional
|
||||||
|
`correlationId` (generated when absent) and a typed result —
|
||||||
|
`found { agent, correlationId }` | `not_found` (the folded shape,
|
||||||
|
also carrying the correlation id). Queries take no idempotency key
|
||||||
|
(the fence binds mutations).
|
||||||
|
|
||||||
### 3.3 Error enum (closed, §4.2)
|
### 3.3 Error enum (closed, §4.2)
|
||||||
|
|
||||||
`validation_failed` 400 · `authentication_failed` 401 ·
|
`validation_failed` 400 · `authentication_failed` 401 ·
|
||||||
@@ -227,8 +249,9 @@ including after the credential write), fence uniqueness on
|
|||||||
(operation, key).
|
(operation, key).
|
||||||
|
|
||||||
Sequencing: additive DDL via the same migration path as 0018–0020
|
Sequencing: additive DDL via the same migration path as 0018–0020
|
||||||
(hierarchy). The KBN-101 §5.3 gate binds KBN-100 kanban DDL, not this
|
(hierarchy). The docs/native-kanban-sot/SHARED-CONTRACT.md §5.3 DDL
|
||||||
lane; if the pending ASKS-5 ruling changes migration mechanics
|
gate binds the kanban lane's audit/proposal DDL, not this lane; if a
|
||||||
|
pending operator ruling on migration sequencing changes mechanics
|
||||||
lane-wide, re-check before generating 0021.
|
lane-wide, re-check before generating 0021.
|
||||||
|
|
||||||
## 5. Witnesses the implementation slice must ship
|
## 5. Witnesses the implementation slice must ship
|
||||||
@@ -246,10 +269,15 @@ lane-wide, re-check before generating 0021.
|
|||||||
5. Idempotency (contract 3 §4.3 set): actor-bound replay returns the
|
5. Idempotency (contract 3 §4.3 set): actor-bound replay returns the
|
||||||
recorded outcome and executes nothing (no new agent/audit/outbox
|
recorded outcome and executes nothing (no new agent/audit/outbox
|
||||||
mutation rows; a replay access event is appended); payload-digest
|
mutation rows; a replay access event is appended); payload-digest
|
||||||
mismatch, replay-mode mismatch, and different-actor actor-bound
|
mismatch, replay-mode mismatch, scope mismatch, and different-actor
|
||||||
replay each refuse with the single bounded `conflict` shape; a
|
actor-bound replay each refuse with the single bounded `conflict`
|
||||||
replay is re-authorized fresh (a submitter whose authorization was
|
shape; a replay is re-authorized fresh (a submitter whose
|
||||||
revoked since the original is refused, not replayed).
|
authorization was revoked since the original is refused, not
|
||||||
|
replayed); a `shared` declaration on `agent.enroll` is refused
|
||||||
|
`validation_failed` with nothing executed and no fence row
|
||||||
|
recorded (seed-only rule); two concurrent same-(operation, key)
|
||||||
|
submissions produce exactly one mutation, the loser resolving
|
||||||
|
through the replay path (no unhandled unique-violation fault).
|
||||||
6. Same-tx atomicity fault injection (agent / credential write / fence
|
6. Same-tx atomicity fault injection (agent / credential write / fence
|
||||||
/ audit / outbox), including a failure injected after the intake
|
/ audit / outbox), including a failure injected after the intake
|
||||||
credential write commits its statement — everything rolls back, no
|
credential write commits its statement — everything rolls back, no
|
||||||
@@ -260,8 +288,11 @@ lane-wide, re-check before generating 0021.
|
|||||||
8. `is_system` injection attempt is rejected by DTO validation.
|
8. `is_system` injection attempt is rejected by DTO validation.
|
||||||
9. Correlation-id witness (contract 5 §6.3): a correlation id submitted
|
9. Correlation-id witness (contract 5 §6.3): a correlation id submitted
|
||||||
on `agent.enroll` appears in its audit event(s) and in the result;
|
on `agent.enroll` appears in its audit event(s) and in the result;
|
||||||
the §6.3 static companions (no `any`-typed boundary pass-through;
|
the same holds for `agent.enrollment.get`'s result; the §6.3 static
|
||||||
single audit emitter) apply.
|
companions (no `any`-typed boundary pass-through; single audit
|
||||||
|
emitter) apply. §6.3's no-existence-oracle probe: an unauthorized
|
||||||
|
`agent.enrollment.get` of an existing agent and a get of a
|
||||||
|
nonexistent id return indistinguishable results.
|
||||||
10. CLI-parity witness (contract 5 §6.4): a CLI smoke invocation of
|
10. CLI-parity witness (contract 5 §6.4): a CLI smoke invocation of
|
||||||
`agent.enroll` and `agent.enrollment.get` against the Gateway
|
`agent.enroll` and `agent.enrollment.get` against the Gateway
|
||||||
succeeds with the same typed results the web client receives. The
|
succeeds with the same typed results the web client receives. The
|
||||||
|
|||||||
Reference in New Issue
Block a user