0006: Command outcomes and audit history
Distinguish access denial, business rejection, and execution failure in durable command history
- ID: PRD-0006
- Status: Accepted
- Decision maker: Trevor Gerhardt
- Scope: Shared audited commands, Auth, Services, and administrator audit history
- Product owner: Trevor Gerhardt
- Design owner: Trevor Gerhardt
- Engineering owner: Trevor Gerhardt
- Last reviewed: 2026-09-25
- Related issues or projects: N/A; this record follows the audited-command design interview.
- Related designs: N/A; the existing audit table remains the interface.
- Related ADRs: 0010: Compose audited commands in phases
- Related user documentation: Not yet published.
Summary
Administrators need to distinguish refused access, rejected business changes, and execution failures. Ordinary form errors must not fill durable business history. Commands use one permission decision at execution start. An accepted command can finish after permission revocation, including during transaction retries.
User problem and evidence
The previous audit outcome combined all refusals and storage errors under failure.
HTTP validation and direct service validation also produced different audit evidence.
The Project commands and audit writer provide the implementation context.
Goals and success measures
| Goal | Measure | Target or review method |
|---|---|---|
| Explain each terminal result | Outcome and safe reason | Integration tests distinguish four outcomes |
| Keep routine request errors out of business history | Rows after validation and freshness refusals | No business audit row |
| Define permission timing | Revocation during an accepted command | The accepted command can complete; the next command is denied |
| Preserve current business rules | Concurrent changes | No missing owner, invalid tenant relationship, or false success |
Non-goals
- A general workflow framework or a replacement for vendor authentication.
- Reclassification of historical failure events.
- Logging complete request inputs, credentials, or internal error messages.
Users and use cases
Use case: Explain an attempted change
- Actor: System administrator
- Need: Read the outcome and safe reason for a command.
- Goal: Distinguish access misuse, ordinary business conflicts, and system failures.
Requirements
PRD-0006-US-01: Classify command outcomes
- Story status: Current
- Replaces: N/A
- Replaced by: N/A
- User need: As an administrator, I want distinct outcomes so that I can explain an attempted change.
- Requirement: Record
success,denied,rejected, orfailurewith a safe reason when applicable. - Done when:
- A successful mutation and its success event commit together.
- Access refusal records
denied; a current business constraint recordsrejected. - Storage errors and defects record
failureafter rollback, without replacing the original error. - Ordinary validation and session-freshness refusals produce safe request diagnostics without business audit rows.
- Retries produce one terminal event. Audit facts from abandoned attempts do not leak into later attempts.
- Facts from request phases, preparation, and the final transaction attempt accumulate without losing unrelated metadata keys. Later supplied keys win, nested values are replaced whole, omitted fields make no change, and explicit null values remain explicit.
- Concurrent executions keep separate contexts. Each attempt starts from prepared facts. Safe facts collected before an authorization refusal remain available to its best-effort audit event.
- Domain operations cannot overwrite writer-owned outcomes, reason codes, timestamps, or event identifiers, or independently persist their context. Dynamic SSO operations retain their create/update event names.
PRD-0006-US-02: Authorize once at command start
- Story status: Current
- Replaces: N/A
- Replaced by: N/A
- User need: As a caller, I want one permission decision so that accepted commands have a clear execution policy.
- Requirement: Authorize before semantic input validation and retain that decision for the command's transaction retries.
- Done when:
- An accepted command can complete after caller permission changes; a later command reads the new permissions.
- Input validation and generated IDs run once per execution, outside retry attempts.
- Every attempt reads current target existence, tenant binding, lifecycle, uniqueness, and owner or administrator invariants.
- Target deletion cannot produce a success event for a mutation that changed nothing.
- Unknown and inaccessible resources retain their existing concealed response.
- HTTP decoding and minimum target-identifier decoding can precede domain authorization.
PRD-0006-US-03: Read and filter the expanded history
- Story status: Current
- Replaces: N/A
- Replaced by: N/A
- User need: As an administrator, I want outcome filters so that I can find relevant command events.
- Requirement: The existing audit page and API expose all four outcomes and safe reason codes.
- Done when:
- Each outcome can be displayed and filtered through the API, SDK, and audit page.
- Historical events retain their original outcome and have a null reason when none was recorded.
- Credentials, internal causes, and private audit metadata remain absent from the public projection.
Implementation
Audited commands record denied, rejected, failed, and successful outcomes. Commands authorize once before validation and preparation. The administrator history filters events by outcome and shows the safe reason code with each event. Services and Auth integration tests cover the stored classifications.
Experience and content
The audit table retains its existing pagination, access control, and empty state. The Outcome filter includes Success, Denied, Rejected, and Failure. A safe reason appears with the outcome when available. Existing labels and keyboard-accessible native controls remain in use.
Constraints and dependencies
The command ADR owns composition and authorization timing. Multi-phase vendor, delivery, and Rackspace workflows retain their explicit transaction boundaries.
User documentation
- Audience: System administrators
- Tasks to explain: Filter history by outcome, and interpret outcomes and reason codes.
- Agreed terms: Audit event, audit outcome, command, denied, rejected, failure.
- Examples or screenshots needed: One filtered result for each outcome.
- Published documentation: Not yet published.
Revision history
- 2026-09-25 — PRD-0006-US-01 through PRD-0006-US-03: Replace the delivery notes with a summary of the current implementation, and accept the implemented stories. PR #168