Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
5.0 KiB
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== walletused_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):
-- 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)
# 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 — prior grant/debit/UI fixes
- ai-full-smoke.md — Green Chat feature smoke
- demo-user.md — credentials / Enterprise pack
- free-tier.md — Free = 0 AI credits