Whether a license has a Paddle subscription, and its lifecycle state
(IBS-2121). None on TenantLicenseWithGridResponse.paddle_subscription
means the license has no paddle_subscriptions row at all -- trial,
sales-led, pre-Paddle-import, manual, or the grid-move orphan edge case
documented on the PaddleSubscription model -- distinguishable from "has
one, active, no scheduled change" (scheduled_change_effective_at=None).
This distinction is the frontend's render-gate condition for the cancel
button (D-2121-COORD-13).
No scheduled_change_action field (schema collapsed post-review): Paddle's
action (cancel/pause/resume) is used only as a write-time filter on the
paddle_subscriptions row, never stored -- scheduled_change_effective_at
is populated only for a scheduled cancellation, so its mere presence here
already means "will not renew," with no separate action to check.
current_period_end/cadence/billing_amount/currency_code (IBS-2358)
are straight passthroughs of the same-named PaddleSubscription columns --
see that model's docstring for provenance. cadence/billing_amount/
currency_code are nullable because a pre-IBS-2358 row has no backfill and
stays NULL until its next transaction.completed delivery.
payment_recovery_deadline (IBS-2407) is past_due_since + 30 days,
computed in _paddle_subscription_state rather than stored -- present
only when status == "past_due" and the subscription actually has a
past_due_since (a pre-existing past_due row with no past_due_since,
or any other status, exposes no deadline rather than a wrong one). 30
days is Paddle's confirmed fixed dunning-recovery-window default for this
account (no Retain add-on enabled, so no dashboard override exists) --
see spec.md Q2, not a guess.