{
 "note": "Per-phase tunables (ADR-019). Round 4: every test phase is the live game times multipliers (live = all ×1). The server loads one ruleset at boot (env ZOEN_RULESET=alpha|beta|live); game code reads multipliers, never phase checks.",
 "active": "alpha",
 "rulesets": [
  {
   "id": "alpha",
   "label": "Alpha (closed, key only)",
   "targetHoursTo40": 2,
   "access": "one_time_key",
   "characterSlots": 3,
   "wipeAtEnd": true,
   "grants": {
    "gold": 0,
    "zoe": 0,
    "stash": [
     {
      "item": "field_report",
      "count": 99
     }
    ],
    "companion": "quest_L4",
    "mount": "quest_L10"
   },
   "respec": "standard (cost × 0)",
   "notes": [
    "Alpha is the live game with bigger multipliers: revert every multiplier to 1 and nothing else changes.",
    "Drop chance × dropRate (capped at 100%), stack sizes × dropQuantity, gold drops × gold, respec cost × respecCost.",
    "Testers who need everything at once (orbs, bases, levels, bosses) use the GM room, not the alpha ruleset.",
    "Quests still carry most XP so the story is seen in under 2 hours."
   ],
   "multipliers": {
    "xp": {
     "quest": 140,
     "kill": 70,
     "other": 70
    },
    "dropRate": 10,
    "dropQuantity": 10,
    "gold": 10,
    "respecCost": 0,
    "dropChanceCap": 1
   },
   "hoursTo40AtMultipliers": 1.61,
   "features": {
    "webActivityFeed": "free",
    "gmRoom": "gm and qa roles"
   }
  },
  {
   "id": "beta",
   "label": "Beta (open, wiped at launch)",
   "targetHoursTo40": 87.5,
   "access": "open_signup",
   "characterSlots": 3,
   "wipeAtEnd": true,
   "grants": {
    "gold": 0,
    "zoe": 2000,
    "stash": [
     {
      "item": "field_report",
      "count": 99
     }
    ],
    "companion": "quest_L4",
    "mount": "quest_L10"
   },
   "respec": "standard",
   "multipliers": {
    "xp": {
     "quest": 2,
     "kill": 2,
     "other": 2
    },
    "dropRate": 1.5,
    "dropQuantity": 1,
    "gold": 1,
    "respecCost": 1,
    "dropChanceCap": 1
   },
   "hoursTo40AtMultipliers": 87.5,
   "features": {
    "webActivityFeed": "premium",
    "gmRoom": "gm and qa roles"
   }
  },
  {
   "id": "live",
   "label": "Live",
   "targetHoursTo40": 175,
   "access": "open_signup",
   "characterSlots": 3,
   "wipeAtEnd": false,
   "grants": {
    "gold": 0,
    "zoe": 0,
    "stash": [],
    "companion": "quest_L4",
    "mount": "quest_L10"
   },
   "respec": "standard",
   "dailyXpSoftCap": {
    "effectiveHours": 18,
    "windowH": 24,
    "multiplierAfter": 0.5
   },
   "multipliers": {
    "xp": {
     "quest": 1,
     "kill": 1,
     "other": 1
    },
    "dropRate": 1,
    "dropQuantity": 1,
    "gold": 1,
    "respecCost": 1,
    "dropChanceCap": 1
   },
   "hoursTo40AtMultipliers": 175,
   "features": {
    "webActivityFeed": "premium",
    "gmRoom": "gm role only"
   }
  }
 ],
 "accessKeys": {
  "format": "ZOEN-XXXX-XXXX-XXXX (Crockford base32, 60 random bits from a CSPRNG)",
  "storage": "Only HMAC-SHA-256(key, server pepper) is stored; the plaintext is shown once to the owner at mint time.",
  "states": [
   "issued",
   "redeemed",
   "revoked",
   "expired"
  ],
  "redeem": "POST /v1/access/redeem { key, email, password } → one transaction: UPDATE keys SET state=redeemed, account_id=… WHERE hash=$1 AND state=issued AND expires_at>now() RETURNING id. 0 rows → 410 Gone (\"key already used or invalid\"). Creates the account with the active ruleset grants.",
  "bindsTo": "the account created by the redeem call (never reusable, never transferable)",
  "rateLimit": "5 redeem attempts per IP per 10 min; 20 failed attempts lock the IP for 24 h",
  "mint": "Owner-only CLI on the server host: `zoen-admin keys mint --count 10 --phase alpha --expires 2026-12-31` → prints keys + writes keys-<date>.csv to the owner’s machine. Agents never mint keys or create accounts.",
  "revoke": "`zoen-admin keys revoke <key-id>`; a redeemed account can be suspended separately.",
  "audit": "Every mint, redeem and revoke is logged with key id (never the key), time, IP hash."
 },
 "multiplierRules": [
  "xp.quest / xp.kill / xp.other multiply XP from those sources.",
  "dropRate multiplies every drop chance (items, materials, orbs, shards, gems, quest drops) and is capped at dropChanceCap (100%).",
  "dropQuantity multiplies stack sizes of every stackable drop (materials, orbs, shards, gold piles, consumables); non-stackables are unaffected.",
  "gold multiplies gold drops and quest gold (not vendor prices).",
  "respecCost multiplies Atlas/Codex respec gold costs.",
  "Rarity weights, affix tiers, refinement odds and boss reward caps are never multiplied (they keep the live balance)."
 ]
}
