= test-approvals

== purpose

Tests for the approval subsystem: tier immutability, grant semantics, mode-based approval, approval engine edge cases, and the decoupling of approval decisions from tool execution.

== responsibilities

* Verify that tier levels are immutable and cannot be downgraded
* Test grant semantics — who can approve what at which tier
* Test mode-based approval (auto-approve, prompt, deny) behavior
* Test approval engine edge cases (concurrent requests, expired requests, missing state)
* Verify that approval decisions do not couple to tool execution (decoupling invariant)
* Test the `ApprovalTrigger` mechanism for policy-driven approval initiation

== non-responsibilities

* Does not test the `ApprovalCoordinator` server module (tested via `:apps:server`'s own tests)
* Does not test the WebSocket approval flow end-to-end
* Does not test the approval UI components

== key types

=== TierImmutabilityTest
* **kind**: JUnit 5 test class
* **purpose**: Verifies that once a tier level is set, it cannot be modified — tier is an immutable value object.

=== GrantSemanticsTest
* **kind**: JUnit 5 test class
* **purpose**: Tests that the approval engine correctly grants or denies requests based on tier of the approving entity vs. tier of the request.

=== ModeApprovalTest
* **kind**: JUnit 5 test class
* **purpose**: Tests approval mode behavior: auto-approve mode skips user interaction, prompt mode requires explicit decision, deny mode rejects everything.

=== ApprovalEngineEdgeCasesTest
* **kind**: JUnit 5 test class
* **purpose**: Tests edge cases in the approval engine: duplicate request IDs, expired timestamps, null fields, concurrent resolution.

=== NoExecutionCouplingTest
* **kind**: JUnit 5 test class
* **purpose**: Verifies that approval decisions are evaluated independently of tool execution — rejecting an approval does not require understanding the tool's execution plan.

=== ApprovalTriggerTest
* **kind**: JUnit 5 test class
* **purpose**: Tests the approval trigger mechanism — which actions/conditions should trigger an approval request.

== event flow

*inbound:* Constructed `DomainApprovalRequest` and `DomainApprovalDecision` instances.

*outbound:* Assertions on approval state (approved, rejected, pending) and event outcomes.

== integration points

* `:core:approvals` — `DefaultApprovalEngine`, `ApprovalEngine`, `Tier`, `ApprovalOutcome`, `ApprovalStatus`, approval model types
* `:core:events` — approval-related event payload types
* `:testing:fixtures` — `ApprovalFixtures`

== invariants

* Tier levels are immutable — once assigned to a request or tool, the tier cannot change
* Policy denial is absolute — an approval cannot override a policy denial
* Approval decisions are independent of tool execution details
* Duplicate resolution of the same request is idempotent

== PlantUML diagram

[plantuml, test-approvals, "png"]
----
include::../../diagrams/test-approvals.puml[]
----




== known issues

* `ApprovalTriggerTest` behavior depends on how triggers are defined — if the trigger mechanism is not yet fully implemented, the test may be skeletal

== open questions

* Should there be tests for approval escalation (promoting a request to a higher tier if unresolved)?
* Should the approval engine support batch approval (approve N requests at once)?
