PROD ADMIN VIEW · READ-ONLY · WRITES STILL ON LOCAL
Resume this draft in a fresh Claude Code session
Owner: quangholio. Two ways to pick this up:
OPTION A — Bootstrap prompt (works for any operator, no slash command needed)
You are operating as the SiXiS Project Onboarding orchestrator brain (Claude) for a NON-TOMMY operator (no local SiXiS install — all substrate writes go through HTTP endpoints on dashboard.sixis.ai).
A user has initiated a new SiXiS project via the dashboard at https://dashboard.sixis.ai/new-project. They have provided this brain dump:
---
# Sweats v1 — Card 3 (Stripe GC Purchase) Bootstrap
**Predecessor draft:** 2953e8c5-85df-442f-bec3-30bceca97762 (Card 2 — GC Wallet & Ledger, shipped 2026-05-15)
**Bootstrap prompt:** `/sixis-pickup <THIS_DRAFT_ID>` then `Pick up this project and move to Card 3`
---
## What you start with (Card 2 is done, on prod, stamped)
Card 2 closeout state on `sweats.poker`:
- Migrations `0003_ledger_card2.sql` + `0004_ledger_card2_reviewer_fixes.sql` applied to live Supabase project `vaqevyigkgfbjivwofgr`.
- `ledger` schema with double-entry primitive `ledger.post_transaction(p_user_id, p_transaction_type, p_legs jsonb, p_idempotency_key, p_initiated_by, p_metadata, p_require_age_verified)` is THE only ledger writer.
- Cached `balance_cached` (BIGINT minor units; 1 GC = 100), advisory-lock concurrency, text-namespaced idempotency_keys, strict `age_verified` gate inside the RPC.
- 11/11 acceptance tests pass via `bash scripts/verify-card-2.sh`.
- Routes live: `/wallet` (auth-gated), `/api/admin/ledger/grant` (LEDGER_ADMIN_TOKEN-gated; currently 500s in prod until env var added).
- Gemini reviewer final-stamp: STAMP (cycle 879ca7b7).
Read these first, in order:
1. `docs/cards/CARD_3_HANDOFF.md` — Card 3 scope, gates, council protocol carry-forward
2. `docs/cards/CARD_2_SPEC.md` — narrative + decisions register
3. `docs/cards/CARD_2_MANIFEST.md` — pure inventory + verification commands
4. Run `bash scripts/verify-card-2.sh` FIRST — must be 11 PASS / 0 FAIL before starting Card 3.
---
## Card 3 scope (per locked SPEC.md)
**Stripe GC purchase** at the locked rate: **$1 = 10 GC** (= 1000 minor units / $1).
- Add `purchase_settled` + `purchase_refunded` transaction_types to the `ledger.transactions` CHECK.
- New `/api/stripe/webhook` handler validates Stripe signature, calls `ledger.post_transaction` with `idempotency_key = 'stripe:<event_id>'`. The Card 2 idempotency table accepts this directly — no schema change required.
- Legs: credit user `available` (+amount_minor), debit `platform_float` (-amount_minor). Float runs negative as we sell GC; that's the point.
- Add Card 3a (pre-launch GC sale on the existing landing page): founding-member bonus tiers + referral GC. Stripe Checkout for the purchase; webhook into the ledger.
## Gates Card 3 must clear before going live
1. **Card 1a (admin audit log)** is co-requisite — Stripe webhook must emit `audit_events` per ledger write. Stopgap: write to `ledger.audit` inline if Card 1a hasn't shipped.
2. **Sweepstakes attorney signoff (Gate A)** — must sign off on $1 = 10 GC + sweepstakes structure for target jurisdictions BEFORE webhook goes live in prod.
3. **CSRF tokens on POST routes** — deferred from Card 1, MUST land before Stripe webhook goes public.
4. **`LEDGER_ADMIN_TOKEN` Vercel env var** added (carry-forward from Card 2) — same pattern Card 3 needs for `STRIPE_WEBHOOK_SECRET`.
## Council convergence carry-forward (DO NOT relitigate)
- Single `post_transaction` primitive is THE only ledger writer. Card 3 adds a thin `ledger.stripe_purchase_complete(p_event_id, p_user_id, p_amount_minor)` wrapper that calls `post_transaction` — do NOT introduce a parallel RPC.
- Text idempotency keys with namespace prefix. Use `'stripe:' || event_id` directly.
- Age-verified gate is enforced inside the RPC. Stripe webhook firing for an unverified user → `unverified_identity`; webhook handler swallows, responds 200 to Stripe (don't trigger their retry storm for a compliance failure), logs a critical audit row so the operator follows up.
- GRANT EXECUTE on `post_transaction` is `service_role` only. Card 3 webhook handler is server-side with service-role client — no grant change.
## Protocol for Card 3 (carried from Card 2 closeout)
1. **Fire council cross-poll EARLY** — at architectural decision points. Specifically: webhook signature verification (Stripe lib vs manual), Stripe at-least-once delivery + your retries, dispute/refund event flow, failed-card audit trail, CSRF/API auth for the webhook endpoint specifically.
2. **Per-brain relay matrix:** DeepSeek (API; remember to source DEEPSEEK_API_KEY from ~/.zshrc because bash does NOT auto-source zsh), GPT (ChatGPT desktop app, `sweats.poker` project folder), Claude.ai (Chrome MCP on **Desktop PC Chrome**, `Sweats.Poker` project folder), Gemini (judge + reviewer, NOT voter).
3. **At Card 3 closeout:** `CARD_3_SPEC.md` + `CARD_3_MANIFEST.md` + `scripts/verify-card-3.sh` (webhook signature, replay, refund symmetry, age-verified-blocked path). MANDATORY: Gemini reviewer final-stamp pass before commit. Then `CARD_4_HANDOFF.md` for the next pickup.
## Don't-repeat gotchas
- DEEPSEEK_API_KEY isn't in bash's environment — pass inline or source `~/.zshrc` explicitly.
- The `ledger` schema is NOT exposed to PostgREST. Use `get_my_ledger_summary()` SECURITY DEFINER from the client; service-role admin client can use `.schema("ledger")`.
- Cycle `879ca7b7` is in local SQLite but NOT in Supabase events FK. Capture brain responses as `/tmp/*` files until substrate sync is fixed.
- Vercel CLI authed as wrong account (`tommysixis-2777`). Env-var changes via dashboard through Chrome MCP.
- Repo-local git author is `Sweats <valuebet.app@gmail.com>`. Don't override.
---
## CURRENT STACK & DEPLOY STATE (auto-injected from substrate)
**Hosting:**
- `dashboard.sixis.ai` → Vercel static export (`ui/`)
- `dashboard.sixis.ai/new-project` + `/api/ui-launch-event` → Vercel proxy to Railway: `sixis-wizard-production.up.railway.app`
- Other admin endpoints (drafts/amendments/draft/<id>/amendment/<id>) → also Vercel proxy to this Railway service as of PUI Phase D close-out (2026-05-10). Honor-system admin gate via ?owner= URL param. Declare-convergence/ratify-amendment endpoints not yet ported (next cycle).
**Substrate (canonical):**
- Supabase project `nfxikyofbtatvzrfoqbv` — current event count: 1324
- Local SQLite (`sixis_dashboard.db`) is an archive after Phase B replay caught up (2026-05-07). Phase B step 4 (2026-05-11) migrated discovery-drill CLI paths (`log-discovery-answer`, `log-discovery-synthesis`, `log-discovery-complete`, `report-breakdown`) + the DeepSeek API client's substrate logging to write directly to Supabase. Remaining SQLite-writing CLI paths sync up via the post-invoke mirror.
- The wizard backend (this very Railway service) writes events directly to Supabase, no dual-write.
**Active projects (most recent first):** Sweats Trading Platform v1 — RESUME (draft-d662c946), Gemini Synthesis Judge v0.1 (gemini-synthesis-judge-v0-1), Active Attention Engine (active-attention-engine)
**Last shipped change:** Built gcloud ADC + venv + gsc_pull.py demand-brief tool; tested end-to-end; scheduled task updated to pull GSC before Batch 3.
**Council relay discipline — CORRECTED MATRIX (ratified by Tommy 2026-05-11T02:14, Universal Shell amendment in flight):**
- `cross-poll` defaults `--auto-relay ON`. The orchestrator (Claude Code session) drives all brains directly. API/CLI is the PRIMARY path for the two non-browser brains; browser control is FOR THE TWO REMAINING BROWSER-ONLY BRAINS ONLY:
- **DeepSeek (voter)** → API via `deepseek_api_v0_1/sixis/deepseek_client.py` (`call_deepseek`). Browser fallback at chat.deepseek.com (Expert/DeepThink mode) ONLY when the API client returns `ok=False` with `fallback=browser`.
- **Gemini (judge + reviewer)** → CLI/API via `gemini-synthesis-judge-v0-1/` (and `gemini-cli-judge-wrapper-v0-1/`). No browser path needed.
- **GPT (voter)** → ChatGPT desktop app via computer-use MCP. New chat created INSIDE the "SiXiS" project folder (per per-project chat-thread rule).
- **Claude.ai (voter)** → claude.ai via Claude-in-Chrome MCP. New chat created INSIDE the SiXiS project folder.
- Tommy is NOT a packet-routing relay node. Pipeline: prompt DeepSeek first via API (longest reasoning), kick off GPT + Claude.ai in browser windows while DeepSeek streams, capture all three responses in any order they arrive.
**Ratification cadence (extended convergence rule, ratified 2026-05-07):**
- Genuine multi-brain convergence at any tier (1/2/3) = automatic ratification — orchestrator proceeds without explicit Tommy ask.
- "Doubt is the cross-poll trigger" — when orchestrator has uncertainty, fire a cross-poll, don't decide unilaterally and don't ask Tommy.
- Sovereign-only matters (red-line risks, irreversible data destruction, money movement, account creation) still always escalate.
**Discoveries fold into scope (rule established 2026-05-07):** anything surfaced during this drill that's adjacent and relevant folds INTO the project's scope by default — don't punt to followups unless folding shifts the tier.
Wizard IDs (use these in the curl POSTs below — DO NOT change them):
- draft_id: 8b51649a-f117-490a-b412-15025310f1a2
- cycle_id: 37245c60-914e-443b-bede-66a36fe09099
- owner: ask the user which operator they're acting as (e.g. "quangholio") and use that value verbatim — DO NOT default to "tommy"
## Your job
Per FORCED_RULE_PO_01 (Conversational Discovery Drill), drill the user ONE QUESTION AT A TIME.
The internal checklist below is YOUR scaffolding — NOT an interrogation script for the user. Pick the most upstream open question, ask it, listen, let the answer pivot/collapse/deepen the queue.
Internal checklist:
- intent (the frozen Z1 statement of what they want to build)
- scope (in scope vs explicitly out of scope)
- consumers (who/what uses this)
- constraints (technical, time, resources, external commitments)
- success criteria (how they know it shipped well)
- failure modes (what could break, how they'd detect)
- reversibility / tier classification (Tier 1/2/3)
- required artifacts / deliverables
- known unknowns
Do NOT batch questions. Do NOT pre-load 5+ at once. Per FORCED_RULE_PO_01 this is a hard rule from the project's own Cycle Zero.
## Substrate logging (HTTP, no local CLI required)
After EACH user answer, log it to substrate via curl:
```
curl -sS -X POST https://dashboard.sixis.ai/api/log-discovery-answer \
-H "Content-Type: application/json" \
-d '{"draft_id": "8b51649a-f117-490a-b412-15025310f1a2", "cycle_id": "37245c60-914e-443b-bede-66a36fe09099", "question": "<the question you asked>", "answer": "<their answer>", "owner": "<operator>"}'
```
When you reach pollable sufficiency (the council can disagree productively without first asking what the project is), summarize the sharpened intent and ask the user to confirm. Then log the synthesis:
```
curl -sS -X POST https://dashboard.sixis.ai/api/log-discovery-synthesis \
-H "Content-Type: application/json" \
-d '{"draft_id": "8b51649a-f117-490a-b412-15025310f1a2", "cycle_id": "37245c60-914e-443b-bede-66a36fe09099", "synthesis_text": "<your sharpened-intent summary>", "owner": "<operator>"}'
```
After the user confirms the synthesis, mark discovery complete:
```
curl -sS -X POST https://dashboard.sixis.ai/api/log-discovery-complete \
-H "Content-Type: application/json" \
-d '{"draft_id": "8b51649a-f117-490a-b412-15025310f1a2", "cycle_id": "37245c60-914e-443b-bede-66a36fe09099", "owner": "<operator>"}'
```
Then propose firing the council cross-poll. (Council cross-poll endpoints are not yet HTTP-exposed; for now, the user will need to surface to Tommy/admin to fire R1+R2. This is a known gap — see draft f8b196a0 next phase.)
## Error handling
If anything crashes, the user reports a wizard issue, or you encounter a malformed/unworkable state mid-drill, log a breakdown:
```
curl -sS -X POST https://dashboard.sixis.ai/api/report-breakdown \
-H "Content-Type: application/json" \
-d '{"draft_id": "8b51649a-f117-490a-b412-15025310f1a2", "cycle_id": "37245c60-914e-443b-bede-66a36fe09099", "description": "<what went wrong>", "severity": "blocking", "owner": "<operator>"}'
```
The user can also report breakdowns from the dashboard "⚠ Report friction" button (bottom-right corner of any wizard page).
## Verifying writes landed
Each curl returns JSON like `{"ok": true, "event_id": "..."}` on success or `{"error": "..."}` on failure. ALWAYS check the response. If a write fails, surface the error to the user immediately and DO NOT proceed to the next question — the substrate must reflect every Q&A for the council to deliberate from.
You can verify substrate state any time by fetching:
```
curl -sS https://dashboard.sixis.ai/draft/8b51649a-f117-490a-b412-15025310f1a2?owner=<operator>
```
Returns the live event timeline rendered as HTML; grep for "discovery_answer_logged" / "discovery_synthesis_logged" / "wizard_step_completed" to confirm.
Paste into any fresh Claude Code chat — Claude runs the discovery drill on the brain dump.
OPTION B — Slash-command shortcut (Tommy's setup only — needs ~/.claude/commands/sixis-pickup.md installed)
Original input from /new-project. Stored as raw evidence per FORCED_RULE_PO_02; never edited in place.
# Sweats v1 — Card 3 (Stripe GC Purchase) Bootstrap
**Predecessor draft:** 2953e8c5-85df-442f-bec3-30bceca97762 (Card 2 — GC Wallet & Ledger, shipped 2026-05-15)
**Bootstrap prompt:** `/sixis-pickup <THIS_DRAFT_ID>` then `Pick up this project and move to Card 3`
---
## What you start with (Card 2 is done, on prod, stamped)
Card 2 closeout state on `sweats.poker`:
- Migrations `0003_ledger_card2.sql` + `0004_ledger_card2_reviewer_fixes.sql` applied to live Supabase project `vaqevyigkgfbjivwofgr`.
- `ledger` schema with double-entry primitive `ledger.post_transaction(p_user_id, p_transaction_type, p_legs jsonb, p_idempotency_key, p_initiated_by, p_metadata, p_require_age_verified)` is THE only ledger writer.
- Cached `balance_cached` (BIGINT minor units; 1 GC = 100), advisory-lock concurrency, text-namespaced idempotency_keys, strict `age_verified` gate inside the RPC.
- 11/11 acceptance tests pass via `bash scripts/verify-card-2.sh`.
- Routes live: `/wallet` (auth-gated), `/api/admin/ledger/grant` (LEDGER_ADMIN_TOKEN-gated; currently 500s in prod until env var added).
- Gemini reviewer final-stamp: STAMP (cycle 879ca7b7).
Read these first, in order:
1. `docs/cards/CARD_3_HANDOFF.md` — Card 3 scope, gates, council protocol carry-forward
2. `docs/cards/CARD_2_SPEC.md` — narrative + decisions register
3. `docs/cards/CARD_2_MANIFEST.md` — pure inventory + verification commands
4. Run `bash scripts/verify-card-2.sh` FIRST — must be 11 PASS / 0 FAIL before starting Card 3.
---
## Card 3 scope (per locked SPEC.md)
**Stripe GC purchase** at the locked rate: **$1 = 10 GC** (= 1000 minor units / $1).
- Add `purchase_settled` + `purchase_refunded` transaction_types to the `ledger.transactions` CHECK.
- New `/api/stripe/webhook` handler validates Stripe signature, calls `ledger.post_transaction` with `idempotency_key = 'stripe:<event_id>'`. The Card 2 idempotency table accepts this directly — no schema change required.
- Legs: credit user `available` (+amount_minor), debit `platform_float` (-amount_minor). Float runs negative as we sell GC; that's the point.
- Add Card 3a (pre-launch GC sale on the existing landing page): founding-member bonus tiers + referral GC. Stripe Checkout for the purchase; webhook into the ledger.
## Gates Card 3 must clear before going live
1. **Card 1a (admin audit log)** is co-requisite — Stripe webhook must emit `audit_events` per ledger write. Stopgap: write to `ledger.audit` inline if Card 1a hasn't shipped.
2. **Sweepstakes attorney signoff (Gate A)** — must sign off on $1 = 10 GC + sweepstakes structure for target jurisdictions BEFORE webhook goes live in prod.
3. **CSRF tokens on POST routes** — deferred from Card 1, MUST land before Stripe webhook goes public.
4. **`LEDGER_ADMIN_TOKEN` Vercel env var** added (carry-forward from Card 2) — same pattern Card 3 needs for `STRIPE_WEBHOOK_SECRET`.
## Council convergence carry-forward (DO NOT relitigate)
- Single `post_transaction` primitive is THE only ledger writer. Card 3 adds a thin `ledger.stripe_purchase_complete(p_event_id, p_user_id, p_amount_minor)` wrapper that calls `post_transaction` — do NOT introduce a parallel RPC.
- Text idempotency keys with namespace prefix. Use `'stripe:' || event_id` directly.
- Age-verified gate is enforced inside the RPC. Stripe webhook firing for an unverified user → `unverified_identity`; webhook handler swallows, responds 200 to Stripe (don't trigger their retry storm for a compliance failure), logs a critical audit row so the operator follows up.
- GRANT EXECUTE on `post_transaction` is `service_role` only. Card 3 webhook handler is server-side with service-role client — no grant change.
## Protocol for Card 3 (carried from Card 2 closeout)
1. **Fire council cross-poll EARLY** — at architectural decision points. Specifically: webhook signature verification (Stripe lib vs manual), Stripe at-least-once delivery + your retries, dispute/refund event flow, failed-card audit trail, CSRF/API auth for the webhook endpoint specifically.
2. **Per-brain relay matrix:** DeepSeek (API; remember to source DEEPSEEK_API_KEY from ~/.zshrc because bash does NOT auto-source zsh), GPT (ChatGPT desktop app, `sweats.poker` project folder), Claude.ai (Chrome MCP on **Desktop PC Chrome**, `Sweats.Poker` project folder), Gemini (judge + reviewer, NOT voter).
3. **At Card 3 closeout:** `CARD_3_SPEC.md` + `CARD_3_MANIFEST.md` + `scripts/verify-card-3.sh` (webhook signature, replay, refund symmetry, age-verified-blocked path). MANDATORY: Gemini reviewer final-stamp pass before commit. Then `CARD_4_HANDOFF.md` for the next pickup.
## Don't-repeat gotchas
- DEEPSEEK_API_KEY isn't in bash's environment — pass inline or source `~/.zshrc` explicitly.
- The `ledger` schema is NOT exposed to PostgREST. Use `get_my_ledger_summary()` SECURITY DEFINER from the client; service-role admin client can use `.schema("ledger")`.
- Cycle `879ca7b7` is in local SQLite but NOT in Supabase events FK. Capture brain responses as `/tmp/*` files until substrate sync is fixed.
- Vercel CLI authed as wrong account (`tommysixis-2777`). Env-var changes via dashboard through Chrome MCP.
- Repo-local git author is `Sweats <valuebet.app@gmail.com>`. Don't override.
Event timeline (5)
Every event tagged with this draft_id, in chronological order.