# Mock Profile Data

Use this exact data in your mockup. Embed it inline as a `<script>` block. Do **not** change names, scores, badge sets, writings, or extension lists — every mockup must show the same content so designs can be compared apples-to-apples.

The score history is generated by a small deterministic function so the file stays readable. Paste the script verbatim — every agent will get the same numbers.

```html
<script>
  // ─── CANONICAL OPERATIVE ────────────────────────────────────────────────
  const PROFILE = {
    username: "swamplord_42",
    name: "Mira Vance",
    bio: "Building automation for the moss-bog. CLI > GUI. The swamp remembers everything.",
    website: "https://miravance.dev",
    email: "mira@miravance.dev",      // visible — showEmail = true
    memberSince: "2023-08-14",         // ~2.7 years on the platform
    firstSeen: "2023-08-14T18:22:01Z",
    lastSeen:  "2026-04-29T22:11:44Z",

    tier: 12,                          // out of 15
    tierName: "SWAMP MARSHAL",
    canonicalScore: 384210,
    nextTierName: "SWAMP LORD",
    nextTierThreshold: 500000,
    signInStreak: 47,
    longestStreak: 112,
    totalEvents: 28741,
    activeDays: 612,

    extensionCount: 7,

    linkedAccounts: [
      { providerId: "github",  providerUsername: "miravance",  providerProfileUrl: "https://github.com/miravance" },
      { providerId: "discord", providerUsername: "swamplord",  providerProfileUrl: null }
    ],

    collectives: [
      { slug: "moss-bog-co",    name: "Moss-Bog Co",    role: "owner",  memberCount: 4 },
      { slug: "telemetry-ops",  name: "Telemetry Ops",  role: "admin",  memberCount: 11 },
      { slug: "swamp-club",     name: "Swamp Club",     role: "member", memberCount: 1248 }
    ],

    pendingInvites: [
      { invitationId: "inv-x91", orgSlug: "field-recon", orgName: "Field Recon", role: "member" }
    ],

    apiKeyCount: 3
  };

  // ─── BADGES (ordered by awardedAt asc) ───────────────────────────────────
  const BADGES = [
    { badgeId: "founder",         name: "Founder",         description: "Joined before public launch.",        visual: "founder",   tierName: null,        tierLevel: null, awardedAt: "2023-08-14" },
    { badgeId: "first-pull",      name: "First Pull",      description: "Someone pulled your extension.",      visual: "pull",      tierName: null,        tierLevel: null, awardedAt: "2023-09-02" },
    { badgeId: "streak-3",        name: "Streak Keeper",   description: "Signed in 7 days in a row.",          visual: "streak",    tierName: "BRONZE",    tierLevel: 1,    awardedAt: "2023-09-12" },
    { badgeId: "streak-2",        name: "Streak Keeper",   description: "Signed in 30 days in a row.",         visual: "streak",    tierName: "SILVER",    tierLevel: 2,    awardedAt: "2023-10-15" },
    { badgeId: "extension-3",     name: "Extension Maker", description: "Published 3 extensions.",             visual: "extension", tierName: "BRONZE",    tierLevel: 1,    awardedAt: "2024-01-08" },
    { badgeId: "writer-1",        name: "Field Writer",    description: "First feed post approved.",           visual: "writer",    tierName: null,        tierLevel: null, awardedAt: "2024-02-19" },
    { badgeId: "streak-1",        name: "Streak Keeper",   description: "Signed in 100 days in a row.",        visual: "streak",    tierName: "GOLD",      tierLevel: 3,    awardedAt: "2024-04-22" },
    { badgeId: "pulls-1k",        name: "Distributor",     description: "Extensions pulled 1k+ times.",        visual: "pulls",     tierName: "BRONZE",    tierLevel: 1,    awardedAt: "2024-07-30" },
    { badgeId: "marshal",         name: "Tier Reached",    description: "Reached SWAMP MARSHAL.",              visual: "tier",      tierName: null,        tierLevel: null, awardedAt: "2025-09-04" },
    { badgeId: "pulls-2k",        name: "Distributor",     description: "Extensions pulled 10k+ times.",       visual: "pulls",     tierName: "SILVER",    tierLevel: 2,    awardedAt: "2025-11-12" },
    { badgeId: "writer-2",        name: "Field Writer",    description: "10 feed posts approved.",             visual: "writer",    tierName: "BRONZE",    tierLevel: 1,    awardedAt: "2026-01-07" }
  ];

  // ─── EXTENSIONS PUBLISHED ────────────────────────────────────────────────
  const EXTENSIONS = [
    { name: "moss-pulse",      version: "2.4.1", pulls: 8412, score: 92, grade: "A", updated: "2026-04-21" },
    { name: "lite-pulse-22",   version: "1.1.0", pulls: 4127, score: 88, grade: "A", updated: "2026-03-10" },
    { name: "fen-relay",       version: "0.9.3", pulls: 2061, score: 81, grade: "B", updated: "2026-02-14" },
    { name: "cypress-ledger",  version: "3.0.0", pulls: 1208, score: 86, grade: "A", updated: "2026-01-29" },
    { name: "bog-watcher",     version: "1.0.4", pulls:  742, score: 74, grade: "B", updated: "2025-12-02" },
    { name: "marsh-archive",   version: "0.4.0", pulls:  311, score: 69, grade: "C", updated: "2025-10-18" },
    { name: "swamp-syslog",    version: "0.2.1", pulls:   48, score: 62, grade: "C", updated: "2025-08-30" }
  ]; // total pulls = 16909

  // ─── WRITINGS (feed posts) ───────────────────────────────────────────────
  const WRITINGS = [
    { id: "p_31a", title: "Why I run my agent against my home-lab inventory every Sunday",   urlHost: "miravance.dev",  createdAtIso: "2026-04-22T10:14:00Z", verdict: "approved", commentCount: 14 },
    { id: "p_31b", title: "moss-pulse hit 8k pulls — what worked, what I'd cut",              urlHost: "miravance.dev",  createdAtIso: "2026-04-08T09:00:00Z", verdict: "approved", commentCount:  6 },
    { id: "p_31c", title: "A field guide to writing extension manifests that don't lie",      urlHost: "swamp.club",     createdAtIso: "2026-03-19T14:42:00Z", verdict: "approved", commentCount: 22 },
    { id: "p_31d", title: "Three years of CLI telemetry: every tool I actually use, ranked",  urlHost: "miravance.dev",  createdAtIso: "2026-02-27T08:30:00Z", verdict: "approved", commentCount: 11 },
    { id: "p_31e", title: "Draft: Why streaks beat scores",                                    urlHost: "miravance.dev",  createdAtIso: "2026-04-29T22:00:00Z", verdict: "pending",  commentCount:  0 },
    { id: "p_31f", title: "On vault rotation cadence",                                         urlHost: "miravance.dev",  createdAtIso: "2026-01-11T19:11:00Z", verdict: "rejected", commentCount:  0 }
  ];

  // ─── COHORT (population aggregates — for percentile framing if you want it)
  const COHORT = {
    populationSize: 1248,
    medianScore: 4200,
    p90Score: 78000,
    p99Score: 410000,
    medianStreak: 3,
    medianActiveDays: 22,
    rank: 14   // out of 1248. Top 1.1%.
  };

  // ─── DAILY SCORE HISTORY (deterministic, seeded) ─────────────────────────
  // 1100 daily snapshots ending on 2026-04-29.
  // Use this to draw heatmaps, sparklines, area charts, etc.
  // The shape of the series intentionally has:
  //   - a slow ramp during first 6 months (2023 H2)
  //   - a flatter plateau (early 2024)
  //   - a steep climb starting Q3 2024 (publishing extensions)
  //   - a shallow dip around day 700 (sabbatical)
  //   - sustained high cadence for the last ~150 days (current streak)
  function buildHistory() {
    function lcg(seed) { let s = seed >>> 0; return () => (s = (s * 1664525 + 1013904223) >>> 0) / 4294967296; }
    const rng = lcg(20260429);
    const days = 1100;
    const end = new Date("2026-04-29T00:00:00Z");
    const snapshots = [];
    let cumulative = 0;
    for (let i = 0; i < days; i++) {
      const d = new Date(end); d.setUTCDate(end.getUTCDate() - (days - 1 - i));
      const phase =
        i < 180   ? 0.25 + (i / 180) * 0.55                       // ramp
      : i < 360   ? 0.55 + Math.sin((i - 180) / 30) * 0.10        // plateau
      : i < 700   ? 0.65 + ((i - 360) / 340) * 1.20               // climb
      : i < 760   ? 1.85 - ((i - 700) / 60) * 0.90                // dip
      : i < 950   ? 0.95 + ((i - 760) / 190) * 0.75               // recover
      :              1.70 + Math.sin((i - 950) / 11) * 0.20;      // current high cadence

      const dow = d.getUTCDay();
      const weekend = (dow === 0 || dow === 6) ? 0.55 : 1.0;
      const noisy = rng();
      const inactive = noisy < 0.18 && i < 760;                   // ~18% inactive days early on
      const baseDelta = inactive ? 0 : Math.round(80 * phase * weekend * (0.55 + noisy * 0.9));

      // event mix — ratios shift over time as the operative explores more types
      const cliShare      = 0.55 - Math.min(0.30, i / 1100 * 0.30);
      const modelShare    = 0.05 + Math.min(0.25, i / 1100 * 0.25);
      const workflowShare = 0.05 + Math.min(0.20, i / 1100 * 0.20);
      const vaultShare    = 0.04;
      const dataShare     = 0.06;
      const repoShare     = 0.03;
      const extensionShare = i > 360 ? 0.07 : 0.01;
      const pageviewShare = 0.10;
      const evTotal = inactive ? 0 : Math.round(8 + baseDelta / 10 + noisy * 6);
      const ev = inactive ? null : {
        cli:        { total: Math.round(evTotal * cliShare) },
        model:      { total: Math.round(evTotal * modelShare) },
        workflow:   { total: Math.round(evTotal * workflowShare) },
        vault:      { total: Math.round(evTotal * vaultShare) },
        data:       { total: Math.round(evTotal * dataShare) },
        repo:       { total: Math.round(evTotal * repoShare) },
        extension:  { total: Math.round(evTotal * extensionShare) },
        page_view:  { total: Math.round(evTotal * pageviewShare) }
      };

      cumulative += baseDelta;
      snapshots.push({
        date: d.toISOString().slice(0, 10),
        dailyScore: baseDelta,
        totalScore: cumulative,
        totalEvents: evTotal,
        eventCounts: ev
      });
    }
    return snapshots;
  }
  const HISTORY = buildHistory(); // 1100 entries
</script>
```

## Notes for designers

- `HISTORY[i].dailyScore` is the score gained on that day (use this for heatmap intensity, sparkline of daily activity, etc.).
- `HISTORY[i].totalScore` is the cumulative score at end-of-day — use this for "score over time" trajectory charts. The final entry's totalScore equals roughly `PROFILE.canonicalScore` (within rounding).
- `HISTORY[i].eventCounts` has the per-day type mix. For sparser views, sum across a window.
- The shape is intentional — the slow start, the plateau, the climb, the dip, the recovery. A good chart should make the story visible.
- For percentile framing, `COHORT.rank = 14` of 1248 ⇒ top 1.1%. Don't lean on this unless the design calls for it.
- Tier 12 of 15. Next tier "SWAMP LORD" at 500k. Current 384,210 ⇒ ~77% to next tier. This is a great progression element if you want one.
- Don't fabricate fields beyond what's in the data block. Don't invent additional badges, extensions, writings, or collectives.
