feat: atomically journal and deliver authorized native operation outcomes
Assistant: codex Assistant-Model: gpt-6-astra Assistant-Session: 01a0e747-8f27-7242-8df8-8bc44f88c929
This commit is contained in:
parent
3c5cbfbafe
commit
f0eff0ac92
13 changed files with 583 additions and 28 deletions
90
docs/operation-outcome-audit.md
Normal file
90
docs/operation-outcome-audit.md
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
# Transaction-linked native operation outcomes
|
||||
|
||||
HUB-WP-0012 source candidate, 2026-09-28. Live sender admission, database rollout
|
||||
and owner acceptance remain open.
|
||||
|
||||
## Coverage and transaction boundary
|
||||
|
||||
The durable native registry, message, progress-event and interaction-event writes
|
||||
already append to `runtime_audit_ledger` in their business transaction. Enforced
|
||||
requests now bind those ledger rows to the verified issuer/subject, actor/target
|
||||
tenant, principal type, policy decision/version/caller, request digest and
|
||||
server-generated authorization correlation ID. This context comes from the
|
||||
access boundary, never command payloads or caller-supplied correlation headers.
|
||||
It is scoped to handler execution and reset in `finally`.
|
||||
|
||||
The same transaction inserts one immutable `hub.operation.committed` envelope
|
||||
into `runtime_outcome_outbox`, keyed by its ledger ID. Failure to insert either
|
||||
record rolls back the business mutation. A rolled-back transaction has no
|
||||
committed outcome; the earlier authorization receipt remains an authorization
|
||||
attempt. Registry duplicate acknowledgements have `registry.duplicate` operation
|
||||
records and do not pretend a new registration was created.
|
||||
|
||||
The envelope contains business object references and a payload hash, not message
|
||||
bodies, event payloads, credentials or tokens. Business correlation IDs are
|
||||
retained separately from verified authorization correlation IDs. That verified
|
||||
ID and decision ID join the outcome to the pre-execution signed decision already
|
||||
held by Audit Core. The outcome does not duplicate the signed envelope.
|
||||
|
||||
This slice covers the native durable mutation ledger. It does not claim outcome
|
||||
coverage for compatibility/embedded-host mutations, background projection refresh,
|
||||
external services, or in-memory development stores. Non-enforced maintenance
|
||||
writes retain their existing local ledger behavior without fabricating an actor
|
||||
or emitting an attributed remote outcome.
|
||||
|
||||
## Delivery, recovery and readiness
|
||||
|
||||
When a durable store and outcome-capable audit sink are composed, the runtime
|
||||
starts a dispatcher and cancels it before closing clients or stores. It selects
|
||||
up to 25 eligible rows per batch, one database transaction per row, and waits
|
||||
one second between batches. PostgreSQL uses `FOR UPDATE SKIP LOCKED` so workers
|
||||
can select different rows. Each receiver call is bounded to three seconds.
|
||||
|
||||
`AuditCoreSink.append_outcome` reuses the operational-custody probe, rotating
|
||||
sender credential and exact accepted/duplicate receipt checks. All retries use
|
||||
the same event ID, occurrence timestamp and body; the ID is also the idempotency
|
||||
key. Only an accepted receipt marks the row delivered. Failed attempts retain
|
||||
the row with persisted exponential retry delay (one second up to sixty seconds).
|
||||
Exceptions are not stored as diagnostic text. Cancellation or a crash before the
|
||||
local delivery acknowledgement leaves the row eligible for replay. Delivery is
|
||||
at least once; receiver deduplication resolves a lost receipt or duplicate send.
|
||||
It does not change business mutation idempotency or make a client retry safe.
|
||||
|
||||
The authorization audit still requires synchronous remote custody before the
|
||||
handler. Queuing a committed outcome does not weaken that check. An outcome
|
||||
outage after authorization cannot undo an already committed operation.
|
||||
|
||||
Protected readiness adds `outcome_delivery`: missing delivery composition is
|
||||
`unavailable`, a pending row older than sixty seconds is `stale`, and a young or
|
||||
empty backlog is `ok`. Database readiness checks that the new table is accessible.
|
||||
Pending rows are never silently discarded. Delivered rows remain for inspection;
|
||||
retention/pruning needs a separately admitted operational policy.
|
||||
|
||||
## Schema and rollout
|
||||
|
||||
Migration `0006_outcome_outbox` adds the table, ledger foreign key and pending-row
|
||||
index. Apply it through the existing owner migration lane before deploying this
|
||||
candidate and admit runtime SELECT/INSERT/UPDATE privileges. Automatic downgrade
|
||||
requires an online check and refuses a nonempty pending queue. Drain pending
|
||||
outcomes and preserve required custody records before schema rollback.
|
||||
|
||||
The Audit Core sender must admit `hub.operation.committed` for source `hub-core`
|
||||
and tenant `tenant:platform`, in addition to existing authorization record classes.
|
||||
This document neither issues that grant nor claims production delivery.
|
||||
|
||||
## Local evidence
|
||||
|
||||
Tests use SQLite-backed durable stores to prove atomic rollback, handler rejection,
|
||||
all native mutation families, actor/decision attribution, concurrent request
|
||||
isolation, persisted retry delay, reopen/replay, cancellation, stale-backlog
|
||||
readiness, dispatcher drain/shutdown and migration shape/downgrade refusal.
|
||||
The real Audit Core receiver/storage source accepts the eight-field envelope and
|
||||
returns a duplicate receipt on replay. Its operational-readiness classification
|
||||
is explicitly a test fixture; this is not live custody evidence.
|
||||
|
||||
PostgreSQL multiworker lock scheduling, production grants, retention and deployed
|
||||
failure-detection/receiver acceptance still require integration receipts.
|
||||
|
||||
Validation on 2026-09-28: 366 tests pass with the opt-in owner-source suite enabled;
|
||||
inventory drift, package build and isolated installed-wheel checks pass. The
|
||||
wheel includes the current migration, authority-context and durable-store code.
|
||||
Loading…
Add table
Add a link
Reference in a new issue