## The two variables

| Variable | What it holds |
|---|---|
| `STRIPE_PRICE_KIT_LAUNCH` | The discounted price id, used while the window is open. |
| `KIT_LAUNCH_PRICE_ENDS_AT` | An ISO date. After it, the standard price id is used. |

`STRIPE_PRICE_KIT` is the standard price and is what the app falls back to.

```bash
bin/rails runner 'puts KitPrice.current.cents'
```

That prints the price the app will actually charge right now, which is the number worth checking
before you announce anything.

## Why it is derived rather than written twice

The obvious version of this feature is a price id in the config and a number typed into the pricing
page. They drift the first time someone edits one and not the other, and the failure is a customer
charged one amount after being shown another, which is a refund and an apology at minimum.

Here the displayed price, the checkout price and the `offers.price` in the page's structured data all
read the same object. A spec asserts the structured data matches, so the three cannot separate
without failing `bin/check`.

## Expiry is evaluated per request, not cached at boot

The window closes on its own at the date you set. There is no deploy to remember and no job to
schedule. That also means moving the date is a configuration change and a restart, not a release.

## Do not delete the old price in Stripe

Archive it instead. Existing customers on a recurring launch price keep that price, and deleting it
breaks their renewals. Archiving hides it from new checkouts and leaves the existing ones alone.

## Test the boundary

Set `KIT_LAUNCH_PRICE_ENDS_AT` to yesterday in development and reload the pricing page. It should
show the standard price, and checkout should use the standard id. Then set it to tomorrow and confirm
both switch back. Two minutes, and it is the only way to know the boundary works before the night it
matters.
