CHAOS /DOCS/REGISTRY

THE REGISTRY

The registry

This site. It issues tickets, signs claims, moves ownership, computes value, answers check for anyone. The app can be read by anything on your PC so it's not a security boundary, the registry is. That's why rarity gets derived here and the file is only a receipt.

Pages

checkDrop a .chaos: valid or not, what it is, what the registry says about this copy. No sign in.
claimUpload a rolled file, get the signed one back. The app does this for you anyways.
vaultYour seeds, states, values, the bank, list / delist, download the current file.
marketListed seeds, search, sort, acquire. Money isn't wired yet so acquire moves ownership at the listed value on paper.
/seed/<hex>One seed's public page.

Value

Rarity is the seed's. Value is the market's: a floor per tier times family and native mode, plus an age bonus, minus a supply discount. Every number is config the registry owns.

CHAOS/src/lib/server/value.tsts
export function valueCents(v: ValueInputs): number {
  const age = 1 + Math.min(config.ageBonusMax, (v.ageDays ?? 0) / 365);
  const supply = 1 / (1 + config.supplyDiscount * v.sameTierClaimed);
  const floor = config.floorCents[v.tier] ?? 1, fam = config.familyMult[v.family] ?? 1, mode = config.modeMult[v.mode] ?? 1;
  return Math.max(1, Math.round(floor * fam * mode * age * supply));
}

Odds

Common60%
Uncommon25%
Rare10%
Epic4%
Legendary0.9%
Mythic0.1%

Of every claimable roll, one a week per account.

What gets refused

Every body goes through one validator before any logic runs: size caps, exact hex for seeds, base64 of exactly 512 bytes for files, bounded ints, closed lists. Bad input = a 400 with the reason.

CHAOS/src/lib/server/input.tsts
export function bytesOf(v: unknown, what: string, exact?: number, max?: number): Uint8Array {
  if (typeof v !== "string" || v.length > MAX_PREVIEW_B64 || !/^[A-Za-z0-9+/]*={0,2}$/.test(v)) throw new Bad(`${what} must be base64`);
  let bin: string; try { bin = atob(v); } catch { throw new Bad(`${what} must be base64`); }
  if (exact !== undefined && bin.length !== exact) throw new Bad(`${what} must be ${exact} bytes`);
  if (max !== undefined && bin.length > max) throw new Bad(`${what} is too large`);
  return Uint8Array.from(bin, (c) => c.charCodeAt(0));
}

Paths nobody honest asks for answer a fake "win" and flag the address for 30 days. A flagged address can still read but gets no ticket, claim, listing, acquisition or sign in.

CHAOS/src/lib/server/honeypot.tsts
export const TRAPS = ["/api/admin", "/api/admin/", "/api/tickets", "/api/ticket/free", "/api/debug", "/api/keys", "/api/internal", "/.env", "/wp-login.php", "/admin", "/backup.zip"];
export const TRAP_PREFIXES = ["/api/admin/", "/api/internal/", "/wp-", "/.git"];
export const FLAG_DAYS = 30;
export function isTrap(pathname: string) { return TRAPS.includes(pathname) || TRAP_PREFIXES.some((p) => pathname.startsWith(p)); }
export function clientIp(request: Request) { return request.headers.get("cf-connecting-ip") ?? request.headers.get("x-forwarded-for")?.split(",")[0].trim() ?? "unknown"; }
// what a trap answers: looks like a win, means nothing. random so two bots cannot compare notes

What gets stored

Your Google subject id, email and display name, your seeds, the signed bytes of each, the preview PNG, transfers, your allowance, flagged addresses. No passwords anywhere. The app's only network calls go to the registry you configured.