Record owner decisions on credits: no payments in beta, credit balance instead of reset windows, five dollar admin-granted free tier, and withdraw the unfounded payment-geography claim
This commit is contained in:
parent
52e12f311e
commit
87be7b9238
3 changed files with 43 additions and 52 deletions
|
|
@ -13,5 +13,6 @@
|
|||
| П-3 | **Очередь и конкурентность по книге**: River на том же Postgres, сериализация по `book_id` + пиннинг книги к одному хосту на MVP, лизы `book_leases` с heartbeat — вежливое ожидание вместо аварии | Ф3-пак платформы | STACK_DECISIONS §5, D39.84 |
|
||||
| П-4 | **Учёт токенов/денег per-user + бюджет-гейт ДО старта задачи** (сырьё уже считает движок: `request_log` + `internal/ledger`; помнить: леджер = нижняя граница — строка 78 единого) | Ф3-пак платформы | platform/README, D39.84 |
|
||||
| П-6 | **OAuth-вход популярных провайдеров (Google первым) + модель аккаунта** (направление владельца 04.08): authorization code + PKCE, валидация ID-токена, связывание аккаунта по ПОДТВЕРЖДЁННОЙ почте; собственная серверная сессия сохраняется (D39.84) — OAuth даёт только СОБЫТИЕ входа. Форма и библиотеки — по ресёрч-пакету направления (ратифицирует оркестратор); писатель куки с `__Host`-атрибутами и dev-профиль — здесь же (PD-8) | P1, вместе с П-1 | владелец 04.08 |
|
||||
| П-7 | **Фри-тир + покупка токенов «как у OpenRouter»** (направление владельца 04.08): кредитный леджер в целых микро-долларах, идемпотентные списания, резервация ДО старта прогона, окна фри-тира; продажа кредитов — через провайдера с минимальной комплаенс-поверхностью (merchant-of-record vs Stripe — решение по ресёрчу). ⚠ Гейт: пер-пользовательский учёт отстаёт на попытку, пока не решён открытый канон-вопрос об источнике денег во время попытки (журнал зоны, «Ратификация приёмкой») | P1+, после П-6 | владелец 04.08 |
|
||||
| П-7 | **Кредитный баланс и фри-тир** (решения владельца 05.08; ПРОДАЖИ НЕТ — бета на предоплаченных ключах владельца): append-only леджер в целых микро-долларах, грант фри-тира из админки (дефолт $5, настраиваемый), холд ДО спавна прогона + пер-книжный потолок движку (жёсткий стоп исполняет движок), расчёт на границе попытки. ⚠ Окон с обнулением НЕТ — баланс, а не подписка: черновик `usage_windows` в подписочной форме заменяется. Платёжный провайдер не проектируется до решения продавать. Разбор — `docs/PLATFORM_DIRECTION.md` §2 | P1+, после П-6 | владелец 04–05.08 |
|
||||
| П-8 | **Минимальная админ-поверхность**: начислить/списать кредиты аккаунту (одна запись леджера), посмотреть баланс и состояние прогонов. Защищённая ручка либо CLI — форму предлагает сессия. Без неё фри-тир неуправляем | вместе с П-7 | владелец 05.08 |
|
||||
| П-5 | **API лимитов/использования + оповещение стопа по потолку** (решение владельца 04.08, D39.100/ПТ-35, механизм «как Claude Code»): страница лимитов в настройках читает СТАТУС использования (не суммы — деньги на провод не идут, D39.84); стоп по потолку → статус `paused` + оповещение «перевод остановлен: лимиты исчерпаны»; сырьё у движка есть (`request_log`/`ledger`, потолки конфига), форму API предлагает P0 | Ф3, вместе с П-1 | D39.100, ПТ-35, контракт К-8 |
|
||||
|
|
|
|||
|
|
@ -44,50 +44,44 @@ hosted IdP (связка PII + доступность, а свою сессию
|
|||
5. Первая НЕаутентифицированная ручка (`/auth/login`) — первая же поверхность для ботов: лимит
|
||||
на исходящие state-записи обязателен вместе с ней.
|
||||
|
||||
## 2. Деньги: фри-тир и покупка токенов (П-7)
|
||||
## 2. Кредиты и лимиты (П-5/П-7) — решения владельца 05.08
|
||||
|
||||
**Форма «как у OpenRouter» — предоплаченный кредитный леджер с резервацией ДО работы** (сверено по
|
||||
публичным докам OpenRouter · Anthropic · Modal). **Фри-тир — периодическим ГРАНТОМ в тот же леджер**
|
||||
(механика Modal): отдельного кода фри-тира не существует вовсе.
|
||||
**Оплаты нет и в бете не будет.** Первые аккаунты — пробные, сидят на фри-тире, ключи провайдеров
|
||||
предоплачены владельцем. Платёжный провайдер не выбирается, не проектируется и в бэклог зоны как
|
||||
работа не заходит; вернуться — когда появится решение продавать. ⚠ Прежняя редакция этого раздела
|
||||
несла вывод «покупателям из России платить нечем» — он был ВЫВЕДЕН из целевого языка перевода, а не
|
||||
установлен, и снят как необоснованный (владелец 05.08). Язык книги о географии плательщика не говорит.
|
||||
|
||||
**Минимальная схема (строить с П-7, не раньше):** к существующему `usage_windows` — три таблицы:
|
||||
`credit_ledger` (append-only, знаковые целые микро-доллары, типы `grant|purchase|hold|hold_release|settlement|adjustment`,
|
||||
`UNIQUE(source, source_id)` как ключ идемпотентности), `reservations` (одна открытая на
|
||||
`engine_run_id`), `account_balances` (кэш баланса в ТОЙ ЖЕ транзакции, что вставка в леджер, +
|
||||
тест-инвариант `balance == SUM(ledger)`). Правки строк не существует по построению: ошибка чинится
|
||||
новой записью. Дробей нет нигде — только целые микро-доллары.
|
||||
**Модель лимита — БАЛАНС кредитов, а не окна с обнулением** (владелец 05.08: «не подписки, а покупка
|
||||
токенов как у OpenRouter»). Следствия, несущие для схемы и контракта:
|
||||
- Понятия «окно сброса» и `resets_at` НЕТ. Черновик `usage_windows` (00003) в этой форме не годится:
|
||||
его `period=day|week` + `limit_micro_usd` — подписочная механика. Заменяется балансом и леджером.
|
||||
- ⚠ Это **отменяет оконную рамку П-5** (страница лимитов «как Claude Code», D39.100/ПТ-35) в части
|
||||
сброса окон. Что остаётся из D39.100 без изменений: суммы на экран не идут, стоп по исчерпании =
|
||||
статус `paused` + оповещение. Экран показывает ОСТАТОК (процентом от гранта), а не «сбросится через».
|
||||
- Вопрос «продолжать ли автоматически после сброса лимитов» отпадает вместе с окнами. Осталось:
|
||||
после пополнения баланса прогон возобновляется явным действием (кнопка/админ), а не сам.
|
||||
|
||||
**Когда резервируем:** в той же транзакции Postgres, что допускает задачу в очередь, ДО спавна
|
||||
`tmctl`; движку передаём пер-книжный потолок ≤ зарезервированного, и тогда ЕГО собственный
|
||||
жёсткий стоп остаётся последним рубежом, а наша резервация может быть консервативной, а не
|
||||
реал-таймовой. Расчёт — на границе попытки, идемпотентно по `(engine_run_id, attempt)`.
|
||||
**Фри-тир = ГРАНТ в леджер, управляется из админки** (владелец 05.08). Дефолт **$5**, настраиваемый
|
||||
пер-аккаунт; «накинуть кредитов» = одна запись леджера типа `grant`, отдельного кода фри-тира не
|
||||
существует. Это и есть стандартная механика (Modal и другие делают так же): начисление и есть весь
|
||||
фри-тир. Нужна минимальная админ-поверхность — защищённая ручка или CLI-команда, пишущая грант.
|
||||
|
||||
**⚠ Открытый вопрос владельцу №1 (продуктовый, не технический): платить из России нечем.** Paddle
|
||||
собственной политикой блокирует покупателей в России и Беларуси; у западных PSP compliant-пути нет.
|
||||
Для продукта, чей целевой язык — русский, это не деталь выбора вендора, а вопрос рынка и способа
|
||||
оплаты. Решать до того, как строить П-7.
|
||||
**Схема (строить с П-7):** `credit_ledger` (append-only, знаковые целые микро-доллары, типы
|
||||
`grant|hold|hold_release|settlement|adjustment`; `UNIQUE(source, source_id)` — ключ идемпотентности;
|
||||
`purchase` добавится, если появится продажа), `reservations` (одна открытая на `engine_run_id`),
|
||||
`account_balances` (кэш в ТОЙ ЖЕ транзакции, что вставка в леджер, + тест-инвариант
|
||||
`balance == SUM(ledger)`). Правки строк не существует: ошибка чинится новой записью. Только целые
|
||||
микро-доллары; на шве расчёта округляем ВВЕРХ (леджер движка — нижняя граница).
|
||||
|
||||
**Платёжный провайдер — НЕ выбираем сейчас** (пользователей ноль). Когда дойдёт: только
|
||||
merchant-of-record, шорт-лист **Paddle vs Stripe Managed Payments** — ⚠ поправка скептика: у Stripe
|
||||
с февраля 2026 есть собственный MoR-продукт (Stripe — зарегистрированный продавец, налоги в 80+
|
||||
странах), что снимает прежний аргумент «Paddle или сам плати VAT OSS»; Lemon Squeezy как независимый
|
||||
игрок мёртв (куплен Stripe в 2024). Покупка проектируется как ОДНА запись леджера с id события PSP
|
||||
в качестве ключа идемпотентности — тогда выбор вендора остаётся дешёвым.
|
||||
|
||||
**Хвосты, которые нельзя забыть** (скептик): чарджбэк приходит после того, как токены потрачены ⇒
|
||||
леджер обязан переживать отрицательный баланс и иметь политику для прогонов в полёте · MoR продаёт
|
||||
в валюте покупателя, а леджер — микро-доллары ⇒ либо фиксированные долларовые паки, либо правило FX
|
||||
на момент покупки · движок отдаёт `committed_usd` как float64, а леджер целочисленный ⇒ правило
|
||||
округления на шве расчёта назвать явно (леджер движка = НИЖНЯЯ граница, значит округляем вверх).
|
||||
|
||||
**⚠ Открытый вопрос владельцу №2: источника денег ВО ВРЕМЯ попытки не существует.** Движок держит
|
||||
эксклюзивный лок (`status --json` недоступен), его stderr-INFO с ценами парсить запрещено доктриной,
|
||||
словарь событий денег не несёт. Варианты: **(A)** версионированное денежное событие в словаре строки
|
||||
103 — свежесть до стадии, но трогает движок и отменяет действующую доктрину «поток цифр не несёт»;
|
||||
**(B)** консервативные пер-книжные потолки, расчёт на границе попытки — ноль правок движка,
|
||||
пользователь не может перерасходовать сверх суммы открытых холдов, цена — пере-резервация;
|
||||
**(C)** нарезка попыток. **Рекомендация оркестратора: (B) сейчас, (A) — отдельным решением, если
|
||||
замер покажет, что пере-резервация душит фри-тир.** Строить П-7 можно на (B) без ожидания ответа.
|
||||
**Резервация — РЕШЕНО (вариант B, оркестратор 05.08; вопрос владельцу снят как переусложнённый):**
|
||||
в той же транзакции, что допускает задачу в очередь, ДО спавна `tmctl` ставим холд и передаём движку
|
||||
пер-книжный потолок ≤ остатка баланса. Дальше жёсткий стоп исполняет САМ движок, у которого этот
|
||||
механизм уже есть, — поэтому перерасход физически невозможен, даже если платформа во время прогона
|
||||
не знает ни цифры. Единственное видимое следствие: индикатор остатка обновляется на границах
|
||||
попытки, а не непрерывно. Денежное событие в потоке движка (вариант A) не строим — оно трогает
|
||||
движок ради обновления индикатора; вернуться, только если замер покажет, что грубость холда душит
|
||||
фри-тир.
|
||||
|
||||
## 3. Стандарты и стек: что взять, что не брать
|
||||
|
||||
|
|
|
|||
|
|
@ -19,19 +19,15 @@
|
|||
|
||||
## Открытые вопросы к владельцу/оркестратору
|
||||
|
||||
**⚠ ВЛАДЕЛЬЦУ, добавлено приёмкой 05.08 (разбор — `PLATFORM_DIRECTION.md`):**
|
||||
0а. **Платить из России нечем.** Paddle своей политикой блокирует покупателей из РФ и Беларуси,
|
||||
compliant-пути у западных PSP нет. Для продукта с русским целевым языком это вопрос рынка и
|
||||
способа оплаты, а не выбора вендора — решать ДО стройки П-7.
|
||||
0б. **Источник денег во время попытки** (движок держит лок, stderr-INFO парсить запрещено, поток
|
||||
цифр не несёт): (A) версионированное денежное событие в словаре строки 103 — трогает движок и
|
||||
отменяет действующую доктрину · (B) консервативные потолки + расчёт на границе попытки — ноль
|
||||
правок движка · (C) нарезка попыток. **Рекомендация: (B) сейчас**; строить П-7 можно, не дожидаясь.
|
||||
0в. **Размер и форма фри-тира** (грант в тот же леджер — механика выбрана; число — за владельцем).
|
||||
**Решения владельца 05.08 (закрыли всё, что висело по деньгам):** оплаты нет и в бете не будет —
|
||||
пробные аккаунты на фри-тире, ключи предоплачены владельцем · модель лимита = БАЛАНС кредитов, а не
|
||||
окна с обнулением («не подписки, а покупка токенов как у OpenRouter») ⇒ `resets_at`/`usage_windows`
|
||||
в подписочной форме отменены, вопрос авто-резюме после сброса окон отпал вместе с окнами · фри-тир =
|
||||
грант в леджер из админки, дефолт $5, настраиваемый. ⚠ Мой вывод «покупателям из России платить
|
||||
нечем» СНЯТ как необоснованный: он был выведен из целевого языка перевода, а не установлен.
|
||||
Резервация решена оркестратором (вариант B — холд + пер-книжный потолок движку, жёсткий стоп исполняет
|
||||
движок). Разбор — `PLATFORM_DIRECTION.md` §2.
|
||||
|
||||
1. **⚠ ВЛАДЕЛЬЦУ (П-5).** При сбросе окна лимитов приостановленный (`paused`) перевод
|
||||
продолжается САМ или ждёт явного «Продолжить»? От ответа зависит, есть ли кнопка на экране и
|
||||
нужно ли уведомление «продолжили без вас». Технически дёшевы оба варианта.
|
||||
2. **Оркестратору (контракт).** Поток событий привязан к ПРОГОНУ (`/runs/{runId}/events`), а
|
||||
статусы `uploading`/`parsing` существуют ДО прогона, и библиотека охватывает книги без прогонов.
|
||||
Живого канала у них нет вовсе. Нужна либо строка в спеке «до старта прогона состояние
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue