Files
descrybe/docs/live-credits-test.md
T
greeneclipse 8580c996c3 Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
2026-08-09 22:47:43 +02:00

119 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Live credits test (Local Demo Co)
**Date:** 2026-08-04
**Tenant:** Local Demo Co (`ee246275-dec0-4446-9e83-58d0c16c258a`) via `demo@descrybe.local`
**Stack:** API `:8080`, web `:5174` (Vite proxy), worker + Green Chat LLM, Postgres `:5433`
**Proof rule:** Live wallet deltas only. **No `seed-demo` / AssignPlan reset used as proof.**
## Verdict
**PASS.** SEO AI, campaign AI, and `enhance_only` each debited **2** credits (formula-aligned).
`/api/billing/credits`, `/api/billing/usage?range=30d`, `/api/auth/me`, open `billing_cycles.credits_used`, and `credit_balances` all agreed after the run.
Billing page HTTP **200**; UI APIs (same session via `:5174` proxy) matched the DB.
Enterprise remaining **label** stays “Unlimited”; numeric **used / total** reflect the wallet.
Wallet was **not** restored to 1M — burn was small (28 used of 1,000,000).
## Recorded balances
| Checkpoint | total | used | remaining | open cycle used |
|------------|------:|-----:|----------:|----------------:|
| Before this run | 1,000,000 | 22 | 999,978 | 22 |
| After SEO + campaign + enhance | 1,000,000 | 28 | 999,972 | 28 |
| **Delta (this run)** | — | **+6** | **6** | **+6** |
Pre-existing `used=22` came from earlier live AI activity in the same open cycle (not from seed).
## Cost table (active)
| feature_name | cost_per_unit |
|--------------|--------------:|
| `seo_meta_ai` | 1 |
| `campaign_copy` | 1 |
| `product_processing` | 1 |
| `openai_token_k` | 1 |
**Debit formula** (`billing.ConsumeCredits` / `EstimateDebit`):
`debit = cost(feature) + ceil(tokens/1000) * cost(openai_token_k)` (minimum 1 when charging).
With base=1 and tokens in (1..1000], expected debit = **2**.
## Operations
| Step | Endpoint | Result | Wallet debit | Notes |
|------|----------|--------|-------------:|-------|
| SEO AI | `POST /api/seo/apply` `mode=ai` product `d2c309ed-…` (Sample Gadget) | 200 | **2** | `credits_charged=2` matched Δused; title filled |
| Campaign AI | `POST /api/campaigns``…/{id}/generate` `mode=ai` | 201/200 | **2** | Campaign `6c135dd1-…`; subject “Upgrade your home essentials” |
| Enhance | `POST /api/processing/jobs` `enhance_only` raw `fa4d70c7-…` | 202→completed | **2** | Job `6a4f09fc-…`; steps `normalize`+`ai_enhance` done |
| **Sum** | | | **6** | Equals SEO+campaign+enhance |
## Billing UI / API consistency
Same browser-origin session (`http://127.0.0.1:5174`, cookies `descrybe_session` + `descrybe_csrf`):
| Surface | used | remaining | plan |
|---------|-----:|----------:|------|
| DB `credit_balances` | 28 | 999972 | Enterprise |
| `GET /api/billing/credits` | 28 | 999972 | Enterprise |
| `GET /api/billing/usage?range=30d` | 28 | 999972 | (wallet fields) |
| `GET /api/auth/me` → credits | 28 | 999972 | Enterprise |
| Open `billing_cycles` | 28 | — | — |
| `GET /billing` | HTTP 200 | — | — |
UI note: `formatCreditsRemaining` shows **Unlimited** for Enterprise; the “used of total” line stays numeric and matched the API.
## Checks (all PASS)
- SEO debit == `credits_charged` (2)
- Campaign debit ≥ 1 (2)
- Enhance debit ≥ 1 (2)
- Total == sum of three (6)
- Credits API == DB
- Usage API == DB
- `/auth/me` == DB
- Plan Enterprise; active company Local Demo Co
- Open cycle `credits_used` == wallet `used_credits`
Artifact: `artifacts/live-credits-summary.json` (`seeded: false`).
## Restore policy
Restore Enterprise **1,000,000 / 0** only if the demo wallet is depleted enough to block QA (e.g. near empty or wrong plan).
After this run: **28 used / 999,972 remaining****no restore**.
If restore is ever required for ops (not as debit proof):
```sql
-- operational reset only — not a substitute for live debit proof
UPDATE credit_balances
SET total_credits = 1000000, used_credits = 0, updated_at = now()
WHERE company_id = 'ee246275-dec0-4446-9e83-58d0c16c258a';
```
Prefer `AssignPlan`/admin billing over raw SQL when resetting plan windows; still do **not** treat that reset as evidence that debits work.
## Reproduce (PowerShell sketch)
```powershell
# Session against web origin so Billing UI cookies apply
$web = "http://127.0.0.1:5174"
$jar = "artifacts/live-credits-run-cookies.txt"
# GET /api/auth/me → CSRF; POST /api/auth/login; POST /api/auth/select-company
# Record GET /api/billing/credits + DB credit_balances
# POST /api/seo/apply {"product_id":"d2c309ed-fa99-4785-aa72-4f7d180f1f85","mode":"ai"}
# POST /api/campaigns {"name":"…","template_key":"spring","use_default_prompt":true}
# POST /api/campaigns/{id}/generate {"mode":"ai"}
# POST /api/processing/jobs {"raw_product_ids":["fa4d70c7-938a-405e-ada7-f7341eb64b53"],"processing_type":"enhance_only"}
# Poll job; re-read credits / usage / me / DB; assert deltas
```
Use raw JSON bodies (avoid PowerShell `ConvertTo-Json` boolean/`True` quirks on create).
## Related
- [billing-credits-audit.md](billing-credits-audit.md) — prior grant/debit/UI fixes
- [ai-full-smoke.md](ai-full-smoke.md) — Green Chat feature smoke
- [demo-user.md](demo-user.md) — credentials / Enterprise pack
- [free-tier.md](free-tier.md) — Free = 0 AI credits