1. Add `estimateRequestCost(request, model)` to PricingService in pricing.ts
- Unified method combining estimateInputTokens + estimateOutputTokens + calculateWorkFeeUsd
- Replaces duplicated token estimation logic at call sites in jobs.ts, sessions.ts, estimate.ts
2. Move partial free-tier `recordGrant()` from invoice creation to post-work in runWorkInBackground
- Previously called at invoice creation for partial path (before user pays) — economic DoS vulnerability
- Now deferred to after work completes, using new `partialAbsorbSats` parameter in runWorkInBackground
- Fully-free jobs still record grant at eval time (no payment involved)
3. Sessions pre-gate refactor: estimate → decide → execute → reconcile
- Free-tier `decide()` now runs on ESTIMATED cost BEFORE `executeWork()` is called
- After execution, `absorbedSats` is capped at actual cost (Math.min) to prevent over-absorption
- Uses new `estimateRequestCost()` for clean single-call estimation