Evaluate the active promotion rules against a cart
DRY-RUN: loads every rule whose validity window contains the current instant, runs them against the cart snapshot you pass, and returns the best NON-CONFLICTING set of outcomes. Writes nothing and does not touch the cart — it answers ‘what would this basket earn automatically?’. Two rules that claim the same SKU conflict, and only the more valuable one survives, so the reply is a selection, not the sum of everything that matched. Use it to preview or verify an offer’s effect on a concrete basket, or to explain a till total; do NOT use it to grant a reduction — POST /v1/checkout/finalize re-computes promotions server-side and is the only thing that makes them real. Cart money is integer cents; applied[].benefitCents is a positive magnitude while discountLines[].amountCents is SIGNED (<= 0) so a breakdown sums straight into a total. Scope gotcha (tracked as solya-pos#943): despite being the till’s read path, this rides the back-office pos.promotion.manage scope, so a plain cashier token holding only pos.checkout.operate is refused 403 at the router gate. In practice pos.promotion.manage is the grant that works here.
Authorizations
Authorization: Bearer <token>. Accepts EITHER a Keycloak access token (scopes-in-token) OR an opaque POS session token; both resolve to the same pos.* scope vocabulary the route guards enforce.

