Skip to main content

Overview

Every successful skill execution triggers two parallel async chains, both dispatched non-blocking via ctx.waitUntil. Credits are only deducted on success — failures and rate-limit blocks never charge the user.

Chain A: Credit Deduction

deductCredit()
  1. Read KV profile:{uid}  — preserve existing tier + username
  2. Write new balance to KV profile:{uid}
  3. Refresh In-Memory cache (60s TTL)
  4. POST Vercel Webhook (syncToSupabase)
       { hash, newBalance, skillName, amount, request_id, display_name }
The Vercel Webhook (VERCEL_WEBHOOK_URL) is the bridge to uniskill-web’s Supabase instance, writing the transaction into the persistent ledger.

Chain B: Telemetry (Dual Write)

1. recordSkillCall → Supabase RPC

Captures structured per-call statistics in tri-state format:
type ExecutionTxStatus = {
  status_code: number;
  execution_status: 'SUCCESS' | 'FAILED' | 'SKIPPED';
  error_message: string | null;
  latency_ms: number;
  metadata: any;  // debug trace array
};
RPC payload sent to record_skill_usage:
FieldDescription
p_user_uidUUID-validated caller UID (fallback: OFFICIAL_UUID)
p_skill_nameNormalized skill identifier
p_source_skill_uidUUID-validated skill UUID
p_costCredits charged
p_status_codeHTTP status code
p_execution_statusSUCCESS / FAILED / SKIPPED
p_latency_msEnd-to-end request duration
p_metadataDebug trace + original skill/user identifiers
p_display_nameHuman-readable skill name snapshot
p_tagsSkill tag array

2. saveInvocationLog → Supabase REST

Raw payload audit written directly to the invocations table:
{
  "skill_uid": "uuid (or OFFICIAL_UUID fallback)",
  "user_uid": "uuid (or OFFICIAL_UUID fallback)",
  "status": "success | error",
  "input_payload": { "...params", "_meta": { "original_skill": "...", "original_user": "..." } },
  "output_payload": { "...result" },
  "duration_ms": 342
}

Layered Cache Architecture

Request
  → In-Memory Cache (60s TTL)    L0 — ~0ms
      ↓ miss
  → Cloudflare KV                L1 — ~1ms
      ↓ miss
  → Supabase DB                  L2 — ~50-200ms
      ↓ write-back
  → KV + Memory Cache            (self-healing)

UUID Safety

Both telemetry chains validate all UUID fields with a strict regex before writing. Any non-UUID value (e.g. skill name strings, "anonymous") falls back to:
OFFICIAL_UUID = '00000000-0000-0000-0000-000000000001'
This prevents foreign key violations while preserving an audit trail of the actual identifier in p_metadata.