# GetActiveApprovalRequest

## Overview

GetActiveApprovalRequest returns the open `ApprovalRequest` for a given `(targetEntityType, targetEntityId)` pair, where "open" means status is `PENDING` or `REVISION_REQUESTED` (a request awaiting revision still owns the target and blocks a concurrent request). The query is the per-target exclusivity guard: wrapper commands call it at the top of orchestration commands such as `requestProductActivation` to block a second concurrent approval on the same target before issuing `createApprovalRequest`. The exclusivity invariant is enforced by the wrapper commands themselves rather than a database constraint, so this query is the read-side guard rather than a redundant check; the defensive `INVARIANT_VIOLATION_MULTIPLE_OPEN` it raises when more than one open row exists should be impossible in practice but is documented because it indicates a guard bypass elsewhere. Returns null when no open request exists, not an error — the absence of an in-flight request is the normal case, and wrappers branch on null vs. result.

## Business Rules

- Accepts `targetEntityType` (free string) and `targetEntityId` (UUID) as required inputs
- Returns the single `ApprovalRequest` whose `(targetEntityType, targetEntityId)` matches and whose status is `PENDING` or `REVISION_REQUESTED`
- Returns null when no such request exists
- Returns at most one row; an invariant violation occurs if multiple non-terminal requests are found, but the per-target exclusivity is enforced by wrapper commands rather than a database constraint, so this is a defensive check on the read path
- Terminal-state requests (`APPROVED`, `REJECTED`, `CANCELLED`, `WITHDRAWN`) are excluded — they do not block a new request

## Process Flow

```mermaid
flowchart TD
    A[Receive targetEntityType and targetEntityId] --> B[SELECT ApprovalRequest<br/>where targetEntityType matches<br/>and targetEntityId matches<br/>and status in PENDING, REVISION_REQUESTED]
    B --> C{Any row found?}
    C -->|No| D[Return null]
    C -->|Yes — exactly one| E[Return the request]
    C -->|Yes — multiple| F[Return error: INVARIANT_VIOLATION_MULTIPLE_OPEN]
```

## External Dependencies

- None

## Error Scenarios

- **INVARIANT_VIOLATION_MULTIPLE_OPEN**: Defensive guard — more than one non-terminal request exists for the same target; should be impossible if wrapper commands enforce exclusivity correctly

## Test Cases

- returns the open request when a PENDING request exists for the target
- returns the open request when a REVISION_REQUESTED request exists for the target
- returns null when no request exists for the target
- returns null when only terminal requests exist for the target
- returns null when other targets have open requests but this target does not
- raises INVARIANT_VIOLATION_MULTIPLE_OPEN when multiple non-terminal requests are found for the same target
