{
  "$comment": "Upgrade cards for partial_live → live. Gates align with docs/agent/API_GAP_REGISTRY.md. Run: node scripts/partial-live-upgrade-smoke.mjs",
  "version": 1,
  "phases": {
    "0": "baseline_observability",
    "1": "payments",
    "2": "funding",
    "3": "defi_marketplace"
  },
  "gaps": [
    {
      "gap_id": "GAP_X402_V1",
      "phase": 1,
      "pillar": "wallet",
      "owner": "payments",
      "tools": ["x402_payment_prepare", "x402_payment_execute"],
      "edge_functions": ["x402-payment-prepare", "x402-payment-execute"],
      "env_secrets": ["WALLET_GATEWAY_URL", "WALLET_GATEWAY_API_KEY"],
      "eval_cases": ["a2a_x402_payment_prepare", "a2a_x402_mandate_blocked"],
      "live_gates": {
        "contract": "prepare+execute routes reachable; structured 4xx on invalid challenge; gateway configured",
        "ops": "WALLET_GATEWAY_* set on Edge; payment_attempts + wallet_activity_events write path verified",
        "e2e": "staging x402 prepare→execute with user_confirmed or active mandate; transfer_status terminal"
      },
      "rollback": "Revert manifest gap_status; redeploy Edge with partialLiveFundsDisclosure"
    },
    {
      "gap_id": "GAP_PAYMENT_MANDATE_V1",
      "phase": 1,
      "pillar": "wallet",
      "owner": "payments",
      "tools": ["payment_mandate_create", "payment_mandate_status", "payment_mandate_revoke"],
      "edge_functions": ["payment-mandate-create", "payment-mandate-status", "payment-mandate-revoke"],
      "env_secrets": ["PAYMENT_MANDATE_ENABLED"],
      "eval_cases": ["a2a_payment_mandate_create", "a2a_x402_mandate_blocked"],
      "live_gates": {
        "contract": "create/status/revoke routes reachable; daily cap RPC bump_mandate_daily_spend",
        "ops": "payment_mandates table + migrations applied",
        "e2e": "create mandate → x402 execute without per-payment confirm within limits → revoke"
      },
      "rollback": "Set PAYMENT_MANDATE_ENABLED=false; keep gap_id in responses"
    },
    {
      "gap_id": "GAP_PAYMENT_INTENT_V1",
      "phase": 1,
      "pillar": "wallet",
      "owner": "payments",
      "tools": ["payment_intent_status", "create_onramp_url"],
      "edge_functions": ["payment-intent-status", "create-onramp-url", "moonpay-webhook"],
      "env_secrets": ["MOONPAY_PUBLISHABLE_KEY"],
      "eval_cases": ["a2a_payment_intent"],
      "live_gates": {
        "contract": "unknown intent id → 404 + gap_id (not gateway NOT_FOUND)",
        "ops": "moonpay-webhook deployed; payment_intents migration",
        "e2e": "create_onramp_url returns intent id → webhook updates status → payment_intent_status terminal"
      },
      "rollback": "Keep partial_live until MoonPay webhook闭环 verified"
    },
    {
      "gap_id": "GAP_BRIDGE_V1",
      "phase": 2,
      "pillar": "wallet",
      "owner": "wallet",
      "tools": ["token_bridge_quote", "token_bridge_execute", "wallet_bridge_job_sync", "wallet_outgoing_activity"],
      "edge_functions": ["bridge-quote", "bridge-execute", "bridge-job-sync", "wallet-outgoing-activity"],
      "env_secrets": ["WALLET_GATEWAY_URL", "WALLET_GATEWAY_API_KEY", "SUPABASE_SERVICE_ROLE_KEY"],
      "eval_cases": ["goal_bridge_quote", "goal_bridge_execute"],
      "live_gates": {
        "contract": "quote 2xx/4xx LiFi path; execute stale quote 400; job-sync unknown job 404 job_not_found",
        "ops": "Gateway lifiBridge convertQuoteToRoute; DB writeback OR bridge-job-sync",
        "e2e": "staging small bridge execute → outgoing activity job_id completed|failed (not pending forever)"
      },
      "rollback": "Document partial_live; do not claim cross-chain complete"
    },
    {
      "gap_id": "GAP_ONRAMP_V1",
      "phase": 2,
      "pillar": "wallet",
      "owner": "wallet",
      "tools": ["create_onramp_url"],
      "edge_functions": ["create-onramp-url", "create-onramp-hosted-action", "moonpay-webhook"],
      "env_secrets": ["MOONPAY_PUBLISHABLE_KEY", "MOONPAY_SECRET_KEY", "MOONPAY_WEBHOOK_SECRET"],
      "eval_cases": ["goal_onramp_moonpay"],
      "live_gates": {
        "contract": "create-onramp-url 200 URL or 503 not_configured; hosted-action 400 without token",
        "ops": "MoonPay keys + webhook URL in production",
        "e2e": "iframe checkout completes → wallet_incoming_activity row from webhook"
      },
      "rollback": "503 not_configured → create_deposit_link fallback"
    },
    {
      "gap_id": "GAP_DEPOSIT_STATUS_V1",
      "phase": 2,
      "pillar": "wallet",
      "owner": "wallet",
      "tools": ["wallet_deposit_activity", "wallet_deposit_confirm"],
      "edge_functions": ["wallet-deposit-activity", "wallet-deposit-confirm"],
      "env_secrets": ["DEPOSIT_CONFIRM_TEST_MODE"],
      "eval_cases": ["goal_deposit_incoming"],
      "live_gates": {
        "contract": "GET deposit-activity 200; POST confirm with tx_hash matches wallet_binding",
        "ops": "wallet_incoming_activity table + triggers",
        "e2e": "user tx_hash confirm OR MoonPay webhook → items in wallet_deposit_activity (no gap_id when items present)"
      },
      "live_boundary_note": "Full chain indexer without tx_hash remains future_backend; live = confirm + webhook paths reliable",
      "rollback": "Empty list may still return gap_id"
    },
    {
      "gap_id": "GAP_WALLET_ACTIVITY_V1",
      "phase": 2,
      "pillar": "wallet",
      "owner": "wallet",
      "tools": ["wallet_activity_list"],
      "edge_functions": ["wallet-activity-list"],
      "env_secrets": [],
      "eval_cases": ["a2a_wallet_activity"],
      "live_gates": {
        "contract": "GET wallet-activity-list 200",
        "ops": "wallet_activity_events + triggers from incoming/outgoing/transfer/swap",
        "e2e": "after transfer/swap/bridge/deposit, same id appears in activity list"
      },
      "live_boundary_note": "Not full on-chain explorer coverage",
      "rollback": "Empty list may return gap_id"
    },
    {
      "gap_id": "GAP_TRANSFER_NOTIFY_V1",
      "phase": 2,
      "pillar": "wallet",
      "owner": "wallet",
      "tools": ["transfer_notify"],
      "edge_functions": ["transfer-notify-register", "transfer-notify-tick"],
      "env_secrets": ["DEPOSIT_NOTIFY_CRON_SECRET", "SUPABASE_SERVICE_ROLE_KEY"],
      "eval_cases": [],
      "live_gates": {
        "contract": "register 2xx; tick without cron → 401; tick with cron → 200",
        "ops": "transfer-notify-tick deployed; cron scheduled in production",
        "e2e": "subscription notified_at set after chain terminal; webhook_url POST if configured"
      },
      "rollback": "Users poll transfer_status"
    },
    {
      "gap_id": "GAP_MARKETPLACE_ORDER_V1",
      "phase": 3,
      "pillar": "wallet",
      "owner": "commerce",
      "tools": ["marketplace_order"],
      "edge_functions": ["marketplace-order"],
      "env_secrets": ["WALLET_GATEWAY_URL", "WALLET_GATEWAY_API_KEY"],
      "eval_cases": ["a2a_marketplace_order"],
      "live_gates": {
        "contract": "unknown order get → 404 + gap_id",
        "ops": "marketplace_orders table",
        "e2e": "create order custodial transfer to seller_address + activity row; status terminal"
      },
      "live_boundary_note": "MVP custodial transfer — not arbitrary external checkout",
      "rollback": "Keep gap_id on responses until seller catalog defined"
    },
    {
      "gap_id": "GAP_DEFI_AUTOMATION_V1",
      "phase": 3,
      "pillar": "site_binding",
      "owner": "defi",
      "tools": [
        "platform_automation_enroll",
        "platform_automation_status",
        "platform_readiness",
        "defi_markets",
        "defi_preflight",
        "defi_trade",
        "defi_orders",
        "defi_order_status",
        "defi_positions",
        "defi_portfolio",
        "user_defi_automation_settings"
      ],
      "edge_functions": [
        "platform-automation-enroll",
        "platform-automation-status",
        "platform-readiness",
        "defi-markets",
        "defi-preflight",
        "defi-trade",
        "defi-orders",
        "defi-order-status",
        "defi-positions",
        "defi-portfolio",
        "user-defi-automation-settings"
      ],
      "env_secrets": ["CUSTODIAL_DEFI_AUTOMATION_ENABLED", "DEFI_ENABLED_PLATFORMS", "WALLET_GATEWAY_URL"],
      "eval_cases": ["goal_defi_trade_route_b", "goal_defi_orders_status", "goal_defi_portfolio_smoke"],
      "live_gates": {
        "contract": "defi-markets/preflight/trade reachable; enroll returns url or expected 403",
        "ops": "/automation-settings + /act enrollment documented; DEFI_ENABLED_PLATFORMS set",
        "e2e": "enrolled user: defi_trade → defi_order_status terminal on each enabled platform"
      },
      "rollback": "Disable platform in DEFI_ENABLED_PLATFORMS"
    },
    {
      "gap_id": "GAP_DEFI_POLY_V1",
      "phase": 3,
      "pillar": "site_binding",
      "owner": "defi",
      "parent_gap": "GAP_DEFI_AUTOMATION_V1",
      "tools": ["polymarket_place_order"],
      "edge_functions": ["polymarket-place-order"],
      "env_secrets": ["CUSTODIAL_DEFI_AUTOMATION_ENABLED"],
      "eval_cases": ["goal_defi_enroll_polymarket"],
      "live_gates": {
        "contract": "polymarket-place-order route reachable",
        "ops": "polymarket in DEFI_ENABLED_PLATFORMS; enrollment + vault",
        "e2e": "enroll → polymarket_place_order → order status"
      },
      "rollback": "Keep partial_live in platform skills"
    },
    {
      "gap_id": "GAP_DEFI_GTRADE_V1",
      "phase": 3,
      "pillar": "site_binding",
      "owner": "defi",
      "parent_gap": "GAP_DEFI_AUTOMATION_V1",
      "tools": ["defi_markets", "defi_preflight", "defi_trade"],
      "edge_functions": ["defi-markets", "defi-preflight", "defi-trade"],
      "env_secrets": ["DEFI_ENABLED_PLATFORMS"],
      "eval_cases": ["goal_defi_gtrade_smoke", "goal_defi_gtrade_polygon_smoke"],
      "live_gates": {
        "contract": "canonical trio on arbitrum + polygon",
        "ops": "gtrade in DEFI_ENABLED_PLATFORMS; gateway gtrade_arb_v1 / gtrade_pol_v1",
        "e2e": "staging+prod live trade smoke on arbitrum and polygon"
      },
      "rollback": "Prefer defi_trade; deprecate gtrade_open_trade alias"
    },
    {
      "gap_id": "GAP_DEFI_OSTIUM_V1",
      "phase": 3,
      "pillar": "site_binding",
      "owner": "defi",
      "parent_gap": "GAP_DEFI_AUTOMATION_V1",
      "tools": ["defi_markets", "defi_preflight", "defi_trade"],
      "edge_functions": ["defi-markets", "defi-preflight", "defi-trade"],
      "env_secrets": ["DEFI_ENABLED_PLATFORMS"],
      "eval_cases": ["goal_defi_ostium_enroll_smoke", "goal_defi_ostium_trade_route"],
      "live_gates": {
        "contract": "defi-markets ostium catalog; preflight valid for enrolled user",
        "ops": "ostium in DEFI_ENABLED_PLATFORMS; gateway ostium_arb_v1",
        "e2e": "enroll approve_usdc → defi_trade place → order terminal"
      },
      "rollback": "Keep partial_live until ostium smokes pass"
    },
    {
      "gap_id": "GAP_DEFI_HYPERLIQUID_V1",
      "phase": 3,
      "pillar": "site_binding",
      "owner": "defi",
      "parent_gap": "GAP_DEFI_AUTOMATION_V1",
      "tools": ["defi_markets", "defi_preflight", "defi_trade", "hyperliquid_deposit"],
      "edge_functions": ["defi-markets", "defi-preflight", "defi-trade", "hyperliquid-deposit"],
      "env_secrets": ["DEFI_ENABLED_PLATFORMS"],
      "eval_cases": ["goal_defi_hyperliquid_enroll_smoke", "goal_defi_hyperliquid_place_smoke"],
      "live_gates": {
        "contract": "HL markets + approveAgent enrollment path",
        "ops": "hyperliquid in DEFI_ENABLED_PLATFORMS; gateway hyperliquid_user_signed_v1",
        "e2e": "enroll → defi_trade → defi_order_status terminal; positions via defi_positions"
      },
      "rollback": "Keep partial_live until HL live trade smoke passes"
    }
  ]
}
