# Membership allowance renewal and lapse Operator-facing record of the decision taken **2026-11-04** on how a member's monthly allowance renews, and how a lapse is handled. The member-facing summary is `co-op/support#44`; the code lives in `co-op/member-portal`. ## The rule - **Renewal is decided by asking Open Collective, on our own schedule.** A scheduled reconciliation asks whether the member has a *live recurring contribution* (order status `ACTIVE` or `PROCESSING` — a payment in flight is not a missed payment). Renewal is a decision of the sweep, not a side effect of webhook delivery, so a lost webhook costs a delayed renewal, never a silently skipped month. - **Anchor to the member's join day, never the payment date.** Open Collective aligns a whole collective's charges onto one common billing day, so anchoring to a charge lets an early charge move the boundary and skip a cycle. The member's join day is stored (`members.anchor_day`) and the reset is pinned to its next occurrence. - **Grace before deactivation.** One reminder email per cycle; deactivate only after `PAYMENT_GRACE_DAYS` unpaid. - **Deactivate by removing group access and stopping renewal, keeping the account**, so a returning payer resumes cleanly at the next cycle. - **Log every decision** (`allowance_log`) with the Open Collective evidence — renewed / reminded / deactivated, plus the payment date or its absence — so a dispute is answered from a record, not reconstructed. ## Scope: monthly only Verified **2026-11-04** that there are **no annual contributors**: 104 orders on Open Collective, 87 MONTHLY and 17 ONETIME, zero annual, and no order has a charge gap over 45 days. Only the monthly case is implemented. One-time contributions are not an allowance cycle — they top up the non-expiring credit balance and stay in the existing credits model. ## Operating it - `ALLOWANCE_POLICY` = `report` (default) | `on`. `report` computes every decision and changes nothing; `on` performs renewals and sends the reminder. - `ALLOWANCE_DEACTIVATE` = `off` (default) | `on`. Gated separately so renewals and reminders can run before anyone loses access. - `PAYMENT_GRACE_DAYS` (default `7`). - Manual check: `POST /admin/allowance?mode=report` (`X-Admin-Token`) is a no-op report; `mode=test&to=` emails one sample reminder; `mode=send` requires `ALLOWANCE_POLICY=on`. ## The bug that prompted it A member who joined on the 15th was charged on the 2nd (Open Collective's common billing day). The reset rule re-anchored his allowance to the new payment date and pushed his renewal from the 14th to the 2nd of the next month — skipping the reset he was owed while he had already paid. The fix is both changes above: anchor to the join day, and decide renewal on a schedule rather than on the payment.