{
  "shipped": "1",
  "source": "repo/claimyour.gold",
  "org": "org/claimyour-gold",
  "generated": "2026-10-17T10:49:30.912Z",
  "entries": [
    {
      "id": "ship/claimyour.gold/6b0dd1a39932",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-17T17:49:12+07:00",
      "kind": "feature",
      "title": "Merge pull request #130 from FlashyLabs/claude/friendly-faraday-he0xvh",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-10-17",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Roadmap loop: wire the Matrix link flow, drop a dead cap, correct the ledger's stale write-path count",
      "refs": {
        "commit": "6b0dd1a3993222b9bead7ada247ca5b9ad7bf599",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/130"
      },
      "digest": "5dd675838f9415634502da0a28a2ed4afa11a06d80b02469fa805c9239601d28"
    },
    {
      "id": "ship/claimyour.gold/5d400662ae19",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-17T15:50:25+07:00",
      "kind": "feature",
      "title": "Merge pull request #129 from FlashyLabs/claude/friendly-faraday-he0xvh",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-10-17",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Roadmap loop: one gold format + machine surfaces live",
      "refs": {
        "commit": "5d400662ae19b7c2776aff15340fd07e370f4dad",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/129"
      },
      "digest": "e4ee17e91337df7c15d779acad433be3904e81fb463b1bfc5e8ad0033320e3d1"
    },
    {
      "id": "ship/claimyour.gold/f1e7cfe38f74",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-17T14:39:59+07:00",
      "kind": "other",
      "title": "WGI-3b: LIFE non-custodial wallet behind the custody adapter (agent half) (#124)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-17",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* WGI-3b: wire the LIFE non-custodial wallet behind the custody adapter\n\nThe agent half of WGI-3b. src/lib/rails/custody/lifeWallet.ts adapts the\nuser-controlled LIFE / Flashy Finance wallet onto the WGI-3a CustodyProvider\ncontract without re-implementing it: a narrow LifeWalletHandle port with\nexactly two capabilities — addressFor and signCall (sign, never broadcast,\nnever export) — so there is no code path from this module to a private key,\nbecause the port defines none. LifeExternalSigner maps that handle onto the\nExternalSigner port and lifeCustodyProvider() returns an ExternalCustodyProvider\nover it (or one that refuses to sign when no handle is wired, never a\nplatform-key fallback). As with WGI-2a's wdkWalletPlane, the concrete LIFE/WDK\nclient is bound at the wiring edge, not guessed in the adapter.\n\ntests/lib/rails/custody/lifeWallet.test.ts proves conformance to the\nCustodyProvider contract and that the non-custodial invariant is structural\n(the handle's whole surface is enumerated; a key accessor or broadcast would\nhave to be added and would fail the test).\n\nWGI-3b is a `both` item: the person's half is the key-handling security review\nin docs/wdk-gold-integration/life-wallet-security-review.md, done before the\npath reaches a real user. The roadmap item is therefore in-progress, not done;\na mainnet offering stays owner-gated under WGI-5.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Fix type check: cast the wallet handle through unknown before Record\n\nThe structural-surface test cast `wallet as Record<string, unknown>` directly,\nwhich tsc rejects (insufficient type overlap). Route it through `unknown`\nfirst, as TS asks. Test behaviour is unchanged.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "f1e7cfe38f74b14039d5d8e8c6057292d35ff56f",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/124"
      },
      "digest": "2913e117dbb4f2cce94c36570163d2ebf697d624ecd1071ecc0536f66c3a8b4d"
    },
    {
      "id": "ship/claimyour.gold/2174f1c9396c",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-17T12:47:57+07:00",
      "kind": "feature",
      "title": "Merge pull request #128 from FlashyLabs/claude/friendly-faraday-he0xvh",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-10-17",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Harden pass 2: shield cap, atomic B2B debit, fulfil flip, rate-limits, notify guards",
      "refs": {
        "commit": "2174f1c9396ca4d328c448bf37523e44aa91256c",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/128"
      },
      "digest": "b6ed0026df1d9e998a5784bdd22f525cb1598e99eef4421c98dcfc2ce22a00ad"
    },
    {
      "id": "ship/claimyour.gold/7bb432d7f4d3",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-17T12:09:44+07:00",
      "kind": "feature",
      "title": "Merge pull request #127: Harden the competitive layer (settlement idempotency + isRealTelegramId sweep)",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-10-17",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Harden the competitive layer: settlement idempotency + the isRealTelegramId sweep",
      "refs": {
        "commit": "7bb432d7f4d32c779b993a2a82a785ed09c5bedb",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/127"
      },
      "digest": "c9b58f72a94e4226ac24b39bee63373af4ed7d0d1d88a117a09663b741832644"
    },
    {
      "id": "ship/claimyour.gold/e90b50937df1",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-16T08:17:34+07:00",
      "kind": "other",
      "title": "vendor: re-vendor drifted emitter copies from current flashyos canon (#111)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-16",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The vendored copies here had drifted from their source in flashyos. A stale\ncopy does not fail; it disagrees silently about whichever field changed.\nestate-revendor replaced each drifted vendor-*.mjs with current canon. Re-\nemitting the fragments is a separate step the repo's own workflow runs.\\n\\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\\nClaude-Session: https://claude.ai/code/session_01BjzD1kWqueq1ArT1m4mZsy\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "e90b50937df1bc049592a51cc4ec7297242267e5",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/111"
      },
      "digest": "7d98e4908a40084e0142d26a36b788a4a2870eee6aba94627198681188689de8"
    },
    {
      "id": "ship/claimyour.gold/85a0f474c820",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-16T03:43:38+07:00",
      "kind": "feature",
      "title": "Merge pull request #126: Matrix launch roadmap (email fallback, channel-guard sweep, machine-readable surfaces)",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-10-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Matrix launch roadmap: email fallback, retention channel-guard sweep, machine-readable launch surfaces",
      "refs": {
        "commit": "85a0f474c82049a12fbcbb37274ff7f53d5cd58f",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/126"
      },
      "digest": "7598e62beaf5dba2dafde730f2d440020a8be19cdd20b0a04719b8aa8f3dc402"
    },
    {
      "id": "ship/claimyour.gold/f60b8798d0ae",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-16T02:40:02+07:00",
      "kind": "feature",
      "title": "Merge pull request #125: Matrix launch roadmap (welcome bonus, identity badges, story cards, channel guards)",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-10-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Matrix launch roadmap: welcome bonus, identity badges, story cards, channel guards",
      "refs": {
        "commit": "f60b8798d0ae2f209f7c77789960feb9c30e12bb",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/125"
      },
      "digest": "c14c0cc125541202dbc4eb80d8cce4e0924932066f752d494ec57ca7f0886764"
    },
    {
      "id": "ship/claimyour.gold/21a0fe040129",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-15T16:41:40+07:00",
      "kind": "other",
      "title": "First-session UX, Matrix front door, and the component-reachability orphan queue (#123)",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-10-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Three weeks of first-session UX work merged back to main:\n- Onboarding: one consolidated checklist, guided welcome wizard, reachable glossary\n- Matrix as a first-class front door, wired into durable acquisition analytics; referral rate-limit re-keyed to (ip, referralCode)\n- New component-reachability CI gate (mirrors check:job-wiring); orphan queue worked 79 -> 58 (2 dead clusters deleted, 9 retention/virality components wired into real pages, 9 ui primitives documented as exempt)\n- 10 new component test files; docs/onboarding.md §1-9 + CLAUDE.md updated",
      "refs": {
        "commit": "21a0fe04012978933510fe650469ed46c4e8bc0a",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/123"
      },
      "digest": "d2c0d79c27ef0c2270feb47033949bbd70179201cc27f928504308658601c5af"
    },
    {
      "id": "ship/claimyour.gold/b32f35eddd13",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-15T16:35:43+07:00",
      "kind": "feature",
      "title": "Merge pull request #121 from FlashyLabs/claude/dreamy-bell-2e5nq3",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-10-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Web 4 rollout: sitter / llms.txt / footer hub, merged with main",
      "refs": {
        "commit": "b32f35eddd13e8cd0d4909a062ae6b7167228a02",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/121"
      },
      "digest": "bd12607c673f3f6c140ea9937fdd7d1b99e11bf1e1e0e26118a6be2f48d43282"
    },
    {
      "id": "ship/claimyour.gold/a21f590d789e",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-15T16:00:37+07:00",
      "kind": "other",
      "title": "WGI-4b: ledger↔chain reconciliation (nightly) (#120)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* WGI-4b: ledger↔chain reconciliation (nightly)\n\nThe WDK rail's half of the nightly reconciliation. Every settled RailReceipt\n(WGI-2b) carries the on-chain amount and the id of the RAIL_DEPOSIT /\nRAIL_REDEEM ledger entry it produced; the two books must agree and no rail\nledger entry may exist without a receipt behind it. A missing entry, an amount\nmismatch, or an orphan entry is drift — a P0, logged with a sample, never\naveraged. A receipt whose entry cannot be read is unread and voids the verdict.\nInert without FLASHY_RAILS_URL.\n\nwdkChainReconciliationService reconciles the receipts the plane already\nreported against the ledger — the chain record as this property holds it;\nregistered as the nightly wdk-chain-reconciliation job beside FG-1. The live\nΣ(on-chain balance) comparison via a registered wallet plane is the\nplane/owner-gated extension.\n\nRoadmap WGI-4b done; README § reconciliation. Every agent-owned WDK item is now\ndone — only WGI-0c (money migration), WGI-3b (LIFE port) and WGI-5 (go-live)\nremain, all person/owner.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Type RAIL_ENTRY_TYPES as the Prisma enum, not string[]\n\nThe goldLedger `in` filter wants GoldLedgerEntryType[].\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Roadmap vacuity guard: allow a finished agent track\n\nCompleting WGI-4b leaves no agent item 'not-started', which is a finished\nplan, not a vacuous one. The guard now requires an agent track to exist and,\nif any agent item is open, it be actionable — but accepts every agent item\nbeing done.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "a21f590d789e911c587987aaabb82222ebde4bfb",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/120"
      },
      "digest": "7e6a7dbac99870ee8ac3c2b42a899e9c260bd212f042a45246c725365ec8eeca"
    },
    {
      "id": "ship/claimyour.gold/96ff6252decd",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-15T15:34:55+07:00",
      "kind": "other",
      "title": "Tests: track the 800,000+ Season 1 floor the source already shipped (#122)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Commit 73648aa set SEASON1.users -> '800,000+' / usersRaw -> 800_000 (the\noperator's canonical figure) but left three tests pinned to the old 549,000 /\n600,000, so main's Tests step has been red and every PR merging against main\nfails there too. This syncs the tests to the shipped source, as invariants\nrather than fresh literals:\n\n- season1.test.ts: assert users is the formatted usersRaw plus the \"+\" floor\n  marker, and that usersLabel is present.\n- platformStatsService.test.ts: raise the live-count mock above the 800,000\n  floor so the case still proves pass-through, not flooring (the floor case is\n  its own test).\n- foundation.test.ts: assert the homepage description contains SEASON1.users,\n  so the figure lives in one place and the test cannot lag again.\n\nNo source change; the lingering '549K' short-form copy in several src pages is\nleft for a separate copy pass.\n\n\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "96ff6252decda26802d8ccfc79f610d2d8b5105f",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/122"
      },
      "digest": "eb4d954c8490b27f9fe7da914b21f8f0ff01edca7d07dfbc4fb44fadb16cb845"
    },
    {
      "id": "ship/claimyour.gold/5d85e0f7712b",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-15T14:59:13Z",
      "kind": "feature",
      "title": "claimyour.gold: surface the machine surfaces in the footer",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The handshake has advertised this site's machine surfaces to a program since\nlaunch; nothing a person reads named them. The band renders only on the\nclaimyour.gold host — on the /academy mount these root paths belong to the\nacademy surface.\n\n- src/lib/machineSurfaces.ts: MACHINE_SURFACES, the one list (llms.txt,\n  claimyourgold.json, sitemap.xml, the handshake, the charter, frontdoor,\n  delivery).\n- src/components/chrome/global-footer.tsx: a machine-surfaces band, gated off\n  the academy mount.\n- tests/machine-surfaces.test.ts: every listed path is really served here\n  (a route handler or a public file), so a path that 404s fails the suite.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "5d85e0f7712b7b92f9c5958b15253b5f83dcffef"
      },
      "digest": "747b31a98bd9aa1777fd6c41f620b8c72f1b00bea89cda2dc8e681c83e4ee7bf"
    },
    {
      "id": "ship/claimyour.gold/05f85aff7eda",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-15T09:26:34Z",
      "kind": "feature",
      "title": "Add the provenance bar (estate chrome) to claimyour.gold",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The human half of the estate chrome: one line at the top of every page —\n\"A Gord Holdings company on the FlashyOS mesh\" — linking the direct parent,\nthe network and the roadmap. Rendered from the canon/1 fact mesh.provenance\nlocked from flashyos.com; this property fills the {parent} slot with its own\ndirect parent (the mesh does not assert who the parent is).\n\nRead from the lock directly, the self-contained way terms.ts already reads\nvocabulary.terms — this property does not install @flashyos/canon.\n\n- canon.lock.json: lock mesh.provenance from flashyos.com (rev 1)\n- src/lib/lineage.ts: lock reader, PARENT, lineSegments\n- src/components/ProvenanceBar.tsx: the dark strip, this property's accent\n- src/app/layout.tsx: render it first in the page column, above the banner\n- tests/lineage.test.ts: pin the lock to the authority + the shape, and\n  assert the rendered bar hands out all three links\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "05f85aff7edaceafd0b97f5872576ddf859b164e"
      },
      "digest": "051d5055bd31336dd9eeeba27bbc4f1ca3f1a04aeb542422bcc14c8e9a4e1d29"
    },
    {
      "id": "ship/claimyour.gold/73648aa5470f",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-15T07:31:31Z",
      "kind": "other",
      "title": "Season 1: 800,000+ eligible to claim Flashy Gold (audit 1.2)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Applies the operator's audience correction that flashy.academy already\ncarried (549,000 S1 players -> 800,000+ Gold hunters eligible to claim) so\nthe estate shows one figure everywhere. SEASON1.users -> '800,000+' with\nusersLabel; copy reframed from \"participants/users\" to \"Gold hunters eligible\nto claim\"; fixed the templates that appended a literal \"+\" (would have\nrendered \"800,000++\"). 68,700 qualified unchanged.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "73648aa5470f43020135c091249bdcad618d48d1"
      },
      "digest": "5ec3cb597e103447606f73c59ad7a665559a7b62b0abc7541d3dfd98b907c384"
    },
    {
      "id": "ship/claimyour.gold/78c6606e94a2",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T20:11:00+07:00",
      "kind": "other",
      "title": "WGI-4a: rail receipts as offline-verifiable claims (#117)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* WGI-4a: rail receipts as offline-verifiable claims\n\nEvery rail movement that reaches a terminal state is sealed as a small\nEd25519-signed claim a holder keeps and verifies OFFLINE against this\nproperty's published public key — no network, no trust in CYG. The shape is\npurpose-built for a gold movement (direction, chain, receiptId, amountMinor,\noutcome, holder, idempotency key, settledAt), not the cross-org invoice\nreceipt.\n\n- src/lib/rails/receiptClaim.ts signs and verifies (canonical form: signed\n  fields only, sorted, no whitespace; node:crypto only).\n- prismaRailReceiptStore seals a receipt the moment it turns terminal and\n  stores the claim on the RailReceipt row (new claim Json? field);\n  listRailReceipts carries it and the wallet read serves the public key under\n  onchain.receiptPublicKey. Inert without RAIL_RECEIPT_SIGNING_KEY — receipts\n  persist unsigned.\n- scripts/verify-rail-receipt.mjs verifies offline, dependency-free; a test\n  signs with the library and verifies with that script as a subprocess so the\n  signer and the offline verifier cannot drift.\n\nREADME § proving a movement; roadmap WGI-4a done.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Cast test env fixture through unknown (ProcessEnv requires NODE_ENV)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Carry the claim field in the existing listRailReceipts assertion\n\nThe view now returns claim (null when unsigned); the pre-existing exact-equality\ntest did not expect it.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "78c6606e94a2694329b094d02f134690f9476e35",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/117"
      },
      "digest": "a823537a81032ca5af60fc150f7937a86169b4a5811fd08b69f5bcd4dad75bab"
    },
    {
      "id": "ship/claimyour.gold/75fabde2bdd9",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T19:13:56+07:00",
      "kind": "other",
      "title": "WGI-3a: custody abstraction (custodial + non-custodial) (#115)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A redeem pays out on-chain; custody answers who holds the signing key.\nCustodyProvider (mode, supportsChain, address, sign) carries each movement's\nchain id and hardcodes none — the testnet guard is shared with the rail, so\nnothing custody signs can reach a mainnet before WGI-5.\n\n- SignerCustodyProvider (custodial) signs through an injected PlatformSigner\n  port, so @flashyos/signer (key from Secret Manager) is wired at the edge and\n  the logic is unit-testable. Testnet only.\n- ExternalCustodyProvider (non-custodial) delegates to an ExternalSigner the\n  user controls (LIFE, WGI-3b). The platform holds no key and the interface\n  exposes no platform-key accessor; built without an external signer it refuses\n  to sign rather than falling back. That absence is the security property.\n\nTests assert a signature echoes its chain and mode, the testnet guard fires\nbefore any signer is touched, and the non-custodial path never reaches for a\nplatform key. README § custody; roadmap WGI-3a done.\n\n\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "75fabde2bdd90e7858e03471880bdc04ee415462",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/115"
      },
      "digest": "6a75d076df28cc4d9c4b179d0d50653c7ec6829990915b4b7bcea86bf353cb50"
    },
    {
      "id": "ship/claimyour.gold/63034817c9ae",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T19:08:43+07:00",
      "kind": "other",
      "title": "WGI-1c: signed service auth, flag-gated beside the static key (#118)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* WGI-1c: signed service auth, flag-gated beside the static key\n\nThe static x-internal-key authenticates a service but has no freshness and no\nper-request binding. This adds an HMAC-SHA256 request signature a caller\nholding the shared secret presents instead:\n\n- serviceAuthSignature.ts signs/verifies over method+path+timestamp+nonce\n  (constant-time, a freshness window), node:crypto only.\n- requireInternalService accepts a valid signature beside the static key,\n  flag-gated by INTERNAL_SERVICE_SIGNING: off (default, static only — today's\n  behaviour byte-for-byte), accept (signature OR static key), require (only a\n  signature; the static key is refused). With no signing secret the mode falls\n  back to off, so a misconfigured require never locks every caller out.\n\nDefault off, so the shared gate's behaviour is unchanged until an owner\nprovisions the secret and flips the flag; serviceAuth.test.ts (the default\npath) is untouched. Roadmap WGI-1c done.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Cast test env fixtures through unknown (ProcessEnv requires NODE_ENV)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "63034817c9ae52153a1c6a3cedefa19b0c6e27e5",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/118"
      },
      "digest": "787a2264888f9d03759777c552d6babae4d4fc74fcfd01f3484792a5ccc3b62f"
    },
    {
      "id": "ship/claimyour.gold/3ae11aac600b",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T18:29:13+07:00",
      "kind": "other",
      "title": "WGI-1b: internal wallet routes + contract tests (#114)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* WGI-1b: the four internal wallet routes, driven against wallet.v1\n\nThe contract named four operations but only credit existed. This builds the\nthree missing internal routes beside it and makes the contract real and tested:\n\n- debit (conditional decrement; INSUFFICIENT_BALANCE becomes a 409, refused\n  and nothing posted, distinct from a 422/400 validation error), balance (the\n  authoritative figure in minor units), transactions (a cursor-paged page of\n  the customer's ledger entries, amounts in minor units).\n- credit is aligned to the contract's MovementResult: it now accepts\n  amountMinor (preferred) or the deprecated decimal amount, and answers\n  newBalanceMinor + entryId (newBalance kept for pre-contract callers).\n- One money boundary, internalWalletAmounts, so all four never drift on the\n  minor-unit representation; the read side is internalWalletService.\n- tests/api/internal-wallet-contract.test.ts drives every handler and asserts\n  each response conforms to the wallet.v1 schema it declares.\n\nThe YAML was reconciled to the server it describes rather than left as\nfiction: requireInternalService returns 403 (not the declared 401), the house\nerror envelope { success, error: { message, httpStatus, code } } replaces the\nflat Error, and validation is 400 (parseBody's convention). The structural\ncontract test's auth assertion moves 401 → 403 to match.\n\nRoadmap: WGI-1b done; WGI-2b corrected to done (its integration run shipped as\nWGI-2c in #112).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Keep the wallet money boundary prisma-free so route tests can import it\n\ninternalWalletAmounts imported toMinor/toMajor from @/ledger/postEntry, which\nconstructs a PrismaClient at module load. That pulled prisma into every\ninternal wallet route and into the existing credit route test (which mocks\n@prisma/client but not prisma), failing it with 'PrismaClient is not a\nconstructor'. The conversions",
      "refs": {
        "commit": "3ae11aac600bc68954f761a9e920d3e589eb8d2f",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/114"
      },
      "digest": "105a1e68fd00c99d31f09f4efdaeb0075cbedca009d15a328bca1e371822b4bc"
    },
    {
      "id": "ship/claimyour.gold/d35101e05329",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T18:24:57+07:00",
      "kind": "infra",
      "title": "Bump @flashyos/agent 0.16 → 0.21 (#116)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "CYG tracked the mesh SDK five minors behind the plane it ships. The bump is\nAPI-compatible for CYG's only surface, AgentReporter: the config fields it\nconstructs with (orgId, agentToken, agentName, baseUrl) and the methods it\ncalls (setTask, taskStart, taskComplete, error, idle) are all present in 0.21,\nand 0.21's only transitive dependency (@flashyos/aao ^0.4.0) is unchanged, so\nthe lockfile moves one entry and nothing else.\n\n\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "d35101e053293aea4f40a2ba05031d7d32da2953",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/116"
      },
      "digest": "fe0c073fa6ada06e3ce5d861315e23c3a2cc94e2cf067a74b612df206f3128d8"
    },
    {
      "id": "ship/claimyour.gold/19e7a32bfce7",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T13:02:17+07:00",
      "kind": "other",
      "title": "Wallet: full transaction list with Flashy Network explorer links (#113)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Every movement on the holder's gold ledger — not just redemptions — newest\nfirst, each with a link to its public record on flashynetwork.com's explorer,\nthe line a stranger can verify.\n\n- `customerLedgerService.listCustomerLedger` reads the holder's own\n  `gold_ledger` rows (scoped by customerId, never another holder's), signed\n  major amounts, a stable `${createdAtMillis}:${publicId}` cursor, and the\n  explorer URL per entry.\n- `explorerUrl(publicId)` is `https://www.flashynetwork.com/explorer/<publicId>/`\n  — the verified host (the 308 to www) and path shape; a live entry returns\n  200. Every `gold_ledger` row carries a unique uuid `publicId`, which is the\n  key flashynetwork.com serves the anonymised public projection under.\n- `GET /api/v1/customer/ledger` (portal session), `WalletTransactions` on\n  `/portal/wallet` listing each movement with amount, label, date and an\n  Explorer link, paginated by \"Show more\". The existing redemption list is\n  retitled \"Recent redemptions\" so the two are not confused.\n\nThe explorer shows an entry's type, amount, source and hash chain, never an\nidentity, so a holder linking their own line reveals nothing it does not\nalready publish.\n\n\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "19e7a32bfce77184c624c539e6c111482645338c",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/113"
      },
      "digest": "87e48aa13432f11d21d8c6933e981fb4c8a12963a74fdf478e072772b80ed42c"
    },
    {
      "id": "ship/claimyour.gold/bb57c45e0bdc",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T12:33:15+07:00",
      "kind": "other",
      "title": "WGI-2c: round-trip integration test (#112)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Wires GoldRailPort, the real postEntry-backed ledger client, the real receipt\nstore and the poller against a mock wallet plane and two in-memory backends\nthat honour the real contracts: postEntry's idempotency and signed amounts,\nand the receipt model's uniqueness and forward-only onchain state.\n\nProves the four things the roadmap names — deposit→credit→balance,\nredeem→debit→payout, idempotency on replay, and conservation (Σ of the signed\nledger entries the rail wrote equals the final balance; every settled receipt\njoins exactly one entry) — plus that a PENDING deposit and a REVERTED payout\nmove no gold and the poller credits only once the plane confirms.\n\n\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "bb57c45e0bdcd68005986fdfcdf585aeb009484e",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/112"
      },
      "digest": "97876956da504d5ffa13c63d4f72bad1e29770cc91ab3172c682743f6bb44f6b"
    },
    {
      "id": "ship/claimyour.gold/9a1679d526f5",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T12:21:42Z",
      "kind": "infra",
      "title": "Drop \"real Flashy Gold\" from copy; extend the brand lint (audit 1.5)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The estate rule bans \"real gold\"; the near-miss \"real Flashy Gold\" sat on the\nhero and ~20 other user-facing surfaces, nudging the bullion association the\nledger copy disclaims. The asset is Flashy Gold, full stop — \"real\" removed\nthroughout, two anaphora lines reworded. The planner and evaluator brand lint\nnow reject \"real Flashy Gold\" too, and tests/content/no-real-gold.test.ts\nscans the rendered copy (allowing only the \"not real gold\" disclaimer).\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "9a1679d526f5802178306c2bcb05a3d73a21cd19"
      },
      "digest": "25024e516c34f3bce20b34ebf10bf9edaed85c31043f59c244f4dca8231dd0af"
    },
    {
      "id": "ship/claimyour.gold/85b22ed1239e",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T12:05:37+07:00",
      "kind": "other",
      "title": "WGI-2b: receipts persisted and double-entered (#110)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* WGI-2b: receipts persisted and double-entered\n\nEvery movement the wallet plane reports to the gold rail is a row in\n`rail_receipts`, written by the rail itself through a RailReceiptStore port\nbefore any gold moves and marked settled only when a ledger entry was written\nagainst it. `onchain` only moves forward (PENDING → CONFIRMED | REVERTED); a\nplane contradicting a terminal state is recorded and logged at error level,\nnever applied. An escalation or a refusal touched no chain and records no\nreceipt.\n\nThe ledger side is the wallet.v1 credit/debit slice over postEntry — entry\ntypes RAIL_DEPOSIT and RAIL_REDEEM, idempotent on the rail's key, so a\nretried confirmation credits once and the two books join on the key.\n\nThe poller is `wdk-receipt-confirmation` in the job registry, every five\nminutes: every PENDING deposit goes back through rail.deposit, which re-asks\nthe plane and credits on CONFIRMED. It reports rail-off or no-plane by name\nuntil WDK_GOLD_RAIL=on and a plane whose chain-shaped pieces were confirmed\nagainst the SDK is registered.\n\nThe Flashy Financial wallet read carries the holder's receipts. Roadmap:\nWGI-2a measured done (#104), WGI-2b in progress with the integration run\ndeferred to 2c.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Type the receipt spy as the port it stands in for\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Poller: count a reverted deposit as reverted, not still pending\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n---------\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "85b22ed1239ec8142513cb877d143a1c16fe0ce0",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/110"
      },
      "digest": "b38553c0754f453021660e068344be56852a75ee6f53983a556b167e116ef697"
    },
    {
      "id": "ship/claimyour.gold/d53c265ef112",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T11:06:56+07:00",
      "kind": "other",
      "title": "WGI-4b: nightly ledger↔rail reconciliation (#109)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "FG-1 swears Σ(entries) = Σ(balances) over the local ledger. A cut-over\nholder's Gold is on Flashy Rails and outside that sum. This is the other\nhalf, in the job registry at the same hour so the two as-of times agree:\nfor every holder this property has asked the rail to carry (one outbox row\nor more — the population is named, not assumed), ask the rail to prove the\nholder's sealed chain settles to their balance, and read the outbox for\nintents that never arrived.\n\nUnread is never zero: a holder the rail did not answer for is counted by\nname and the run is UNREAD, not PASS. Drift is a FAIL at error level with a\nsample. A `failed` outbox row is a FAIL — an intent the local ledger\ncommitted that the rail never received. `blocked` and `awaiting-consent`\nare parked by design and reported, with the oldest parked debit's age.\n\nInert without FLASHY_RAILS_URL. `AWAITING_CONSENT` moves to a module with\nno queue import so a reader of the outbox can name the status without\nopening Redis; the queue re-exports it.\n\n\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "d53c265ef112b5faac30ab77f101ae5ea121a314",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/109"
      },
      "digest": "610d7b9ae6e0992951dd90bfcf8787ea33e89b6291e62d18b1f42f066664f939"
    },
    {
      "id": "ship/claimyour.gold/708a4e5827b2",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T11:06:28+07:00",
      "kind": "other",
      "title": "The dashboard wallet is the Flashy Financial wallet (#108)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* The dashboard wallet is the Flashy Financial wallet\n\nOne rule for which Gold figure a surface shows. `balanceForDisplay` serves the\nwallet column for an unmigrated holder and Flashy Rails' settled figure for a\nmigrated one (fail-safe to the frozen column, logged), and every surface that\nshows a balance reads through it: the portal header, the dashboard, the\nwallet, the redeem page, the portfolio API, the Telegram mini app, the hunter\nspotlight and the client API. A migrated holder's figure is the rail's\neverywhere; there is no second number to disagree with it.\n\nThe wallet page carries the Flashy Financial panel: whether this property is\non the rail and the rail answers, whether THIS holder's Gold is there yet,\nand every debit parked `awaiting-consent` with \"Approve in Flashy ID\".\nApproval never happens here. `/api/v1/customer/finance/consent/start` sends\nthe holder to flashyID's `/rail/consent` with the rail-served draft, this\nproperty's registered callback and an HMAC-signed state naming this holder\nand this row (ten minutes, no `_`, so it fits flashyID's parseState);\n`/api/v1/customer/finance/consent/callback` verifies the state against the\nsession, exchanges the one-time code with the service credential on the back\nchannel, checks the holder, and settles the row through railConsentService.\nEvery refusal is one word on the wallet page with the rail's own code.\n\nInert without FLASHY_RAILS_URL: the panel renders nothing and `isMigrated` is\na synchronous false. Without FLASHYID_ISSUER / FLASHYID_RAIL_MINT_SECRET the\npanel lists the parked debits and says approval is not available yet, and the\nstart route answers 503 rather than inventing a flow.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* Type the test env fixtures as ProcessEnv rather than casting\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n",
      "refs": {
        "commit": "708a4e5827b224a0cb983a862677c67a99011a1f",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/108"
      },
      "digest": "1e852b33aea871e86f5707789bcb015f4b3832b698c01c0c94d1955e2cb4ca89"
    },
    {
      "id": "ship/claimyour.gold/49298a6fc0ac",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T09:53:19+07:00",
      "kind": "other",
      "title": "Rail debits through the consent gate, migrated reads from the rail, a bounded rail client (#107)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Central-rail migration, cutover plan steps 2–4, flag-gated on FLASHY_RAILS_URL and inert for every holder without a MIGRATION entry. A redeem is drafted on the rail and parked awaiting-consent; railConsentService executes it against the holder's flashyID-signed consent and re-enqueues the drain; two routes under /api/v1/finance/rail/consents carry the list and the token. getBalance reads the rail's settled balance for a migrated holder, fail-safe to the frozen cache. Every rail request carries a timeout (RAIL_TIMEOUT 504). Transfers and reversals still park as blocked. CI green on c380bfe (Lint + type check + tests, CodeQL, gitleaks, Lighthouse). The one open seam is flashyID's consent interaction, named in docs/rail-cutover-plan.md.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c",
      "refs": {
        "commit": "49298a6fc0ac929a16c435fbfd89fe9ccda911de",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/107"
      },
      "digest": "5892b982e50daa4a89cb28d4c1ed76e4a3fe58571e24217c4f40e46f5af167bd"
    },
    {
      "id": "ship/claimyour.gold/11b7ab15a811",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-14T09:34:35+07:00",
      "kind": "other",
      "title": "WDK gold rail (WGI-2a): governed, flag-gated, testnet-only (#104)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-14",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The on-chain value path for Flashy Finance into CYG's gold ledger, as a caller of the wallet.v1 seam: deposit (a CONFIRMED settlement → a gold credit) and redeem (a gold debit ← an executed, CONFIRMED payout) through the FlashyOS wallet plane. Off by default (WDK_GOLD_RAIL=on), testnet-only before a verdict is asked, money follows the chain (ESCALATE/DENY move nothing; a REVERTED payout debits nothing; idempotent on the receipt id). CI green on 185fd94: Lint + type check + tests, CodeQL, gitleaks, Lighthouse. The Vercel commit status fails on main's own merge commits before this change and is not this PR's.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c",
      "refs": {
        "commit": "11b7ab15a811cc69fadd356f8eafae8a12f22024",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/104"
      },
      "digest": "62318795ac6aeb77bc132636699bcbeb5e37711dfaa215898eeb1f709be4af8a"
    },
    {
      "id": "ship/claimyour.gold/0abca6665b6d",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-06T06:53:41Z",
      "kind": "feature",
      "title": "Merge claude/live-hq-org-display-njs2qo: link the FlashyOS live network at /live-network",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-10-06",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01VgrPGGUFKMq9zXBHnfcTgs",
      "refs": {
        "commit": "0abca6665b6d554cb335f14de10a3df37708047e"
      },
      "digest": "30ef7d624ac4532ff3505dadda28856e808f0e64b693b7686c5d3c1adf645dd1"
    },
    {
      "id": "ship/claimyour.gold/59facc69cbf5",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T20:37:50+03:00",
      "kind": "feature",
      "title": "Add Vercel Web Analytics (<Analytics/> component) (#105)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "@vercel/analytics ^2.0.1 + <Analytics/> in the root layout (Next.js App Router). Enable Web Analytics in the Vercel project for data to flow.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c",
      "refs": {
        "commit": "59facc69cbf5c11ee78dd8da6fa40374ac2ceb7d",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/105"
      },
      "digest": "37ac3c50d9c42c5d8ddbfe2cebcee02d559bc52e85eec472a41d03064f8eaa8e"
    },
    {
      "id": "ship/claimyour.gold/96d97ad21e80",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T18:42:19Z",
      "kind": "other",
      "title": "Delivery: the emitter's push does not run the laptop hook",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "With dependencies installed, the husky pre-push hook typechecked the whole\napp inside the workflow and ran out of memory, so the observed record (both\nLearn guides now distributed) was never committed. CI typechecks every push\nalready; the hook is for a developer's machine.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "96d97ad21e80fc4dfc552a98fb3cfe5066333898"
      },
      "digest": "2c505e3b4ae645dae388acbf4feaf23ad0f6ca5361bda63c02499d1ee7daa775"
    },
    {
      "id": "ship/claimyour.gold/073cc9ca72ad",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T18:24:59Z",
      "kind": "other",
      "title": "Delivery: install before the Test step",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The workflow ran this repository's delivery test with nothing installed,\nso npx fetched a test runner the project never pinned and died loading\nthe config — red on every run, for a reason that was never the record.\nOne install step, with the lockfile cached, the way ci.yml already does.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "073cc9ca72ad538ba99dec9238516d5f4ca2b48d"
      },
      "digest": "ec32a1bcdd596a10b65dc89a83d84bcf36f2cfa21939d62b0cdb16cd342fa423"
    },
    {
      "id": "ship/claimyour.gold/beb8d846137f",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T17:46:18Z",
      "kind": "infra",
      "title": "Link Developers and the estate's open-source door from the footer",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "flashyos.com owns the open-source listing (decided 2026-10-04); every other\nproperty says \"Open source\" and links the owner rather than restating the\nlist. The door is locked as the canon/1 fact `open.door` in canon.lock.json\nand read through src/lib/openDoor.ts, the same pattern as the term map. It\nsits in the footer's Resources column beside a new \"Developers\" row —\n/developers existed and nothing linked it. An `external` footer row renders\nas a plain anchor and never goes through crossHref(), which would otherwise\nprefix it with claimyour.gold on flashy.academy.\n\ntests/components/chrome-nav.test.ts holds the lock, the helper, both rows on\nboth hosts, and that nothing under src/ types the door's URL.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "beb8d846137fb90bb2bff3239f2e8af864649198"
      },
      "digest": "c398a3cbc7926ef7fc7f9afaa2177617afad04e8205fab0d84d704d942371399"
    },
    {
      "id": "ship/claimyour.gold/54f1921c36be",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T16:36:00+03:00",
      "kind": "other",
      "title": "WDK–Gold integration: machine-readable roadmap + wallet.v1 contract (#103)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* docs(wdk-gold): the machine-readable roadmap for completing the WDK/Flashy Finance integration\n\nCompleting and hardening the FlashyOS WDK wallet-plane integration into CYG's\ngold ledger, planned as a machine-readable file rather than prose.\n\n- docs/wdk-gold-integration/roadmap.json — 6 phases, 15 items, each with owner\n  (agent/person/both), status, deliverables, tests, docs, risk, dependencies,\n  and a testnet_only flag. The on-chain rail (@flashyos/wdk) becomes a *caller*\n  of CYG's existing dormant seam (POST /api/v1/internal/wallet/credit →\n  creditWalletWithLedger), never a second ledger: governed by authorize() →\n  SpendAuthorization → the signer that re-derives every call → a verifiable\n  receipt. Blockchain-agnostic, custodial OR non-custodial.\n- Ordered so the ledger is made trustworthy BEFORE any value moves: WGI-0\n  fences the write path and proves the books balance (the Float→minor-units\n  money migration stays owner-gated); WGI-1 makes the wallet API a versioned\n  contract; WGI-2 connects the rail (flag-gated, testnet-only); WGI-3 adds the\n  custodial/non-custodial custody abstraction (the LIFE wallet plugs in here);\n  WGI-4 proves it (verifiable receipts + ledger↔chain reconciliation); WGI-5\n  (mainnet, KYC/AML, production flag) is named owner-gated.\n- schema.json shapes it; README.md navigates it; tests/docs/wdk-gold-roadmap.test.ts\n  guards the invariants (dependencies resolve, money steps stay a person's, the\n  rail never admits a mainnet) so a careless edit fails CI, not production.\n\nNo code path changed and nothing is promoted to production; this is the plan.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01CLZMfnkGGUXXzv9VA1td1c\n\n* docs(wdk-gold): correct the roadmap to measured reality + add the wallet.v1 contract\n\nMeasuring CYG before building changed the plan — and that is the finding:\nPhase 0 is already DONE here, better than a shallow read assumed. Recorded so\nthe roadmap stops claim",
      "refs": {
        "commit": "54f1921c36be124f49738b847331d0360c4632da",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/103"
      },
      "digest": "cb3e01e2ca91d6f193f15383177ab6245212c8a801f394b139b50a9f094c8f90"
    },
    {
      "id": "ship/claimyour.gold/552b9a828ab4",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T13:09:16Z",
      "kind": "other",
      "title": "Branch mesh sync: check out the module the re-vendored script requires",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The sync has failed on every scheduled run since the re-vendor with\n\"Cannot find module './flashyos-role-mesh.cjs'\" (run 37202857602): the\nworkflow's sparse checkout named only scripts/flashyos-branch-mesh-sync.mjs,\nand the re-vendored script requires scripts/flashyos-role-mesh.cjs and\nreads flashyos.roles.json. The checkout now lists all three, as\nflashy-academy's copy of the same workflow already does.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "552b9a828ab4b69947df24c4f57504a9b30e74c3"
      },
      "digest": "5537affda0543e491ae5f9e5eb1c254c75517c3a7cefac0622b070bf9f8ae53e"
    },
    {
      "id": "ship/claimyour.gold/3b2f132acad7",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T08:25:52Z",
      "kind": "other",
      "title": "Term-map test: one argument to expect, as jest takes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "CI's type check refused the two-argument form vitest allows; the\nfailure message now rides on the asserted value.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "3b2f132acad71e2e9ab0ad7c428de758e129321e"
      },
      "digest": "f61abec3243c6646c9e1d20e239f49a05b6ceace15647331872709c616621042"
    },
    {
      "id": "ship/claimyour.gold/92e157f4a6a1",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T07:50:51Z",
      "kind": "other",
      "title": "Cite the owner of the two estate terms this property says",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The estate's term map has one owner per term, and a property that says a\nterm links the owner's canonical page with the agreed anchor text rather\nthan restating the definition. /llms.txt and /claimyourgold.json say\n\"Agentic Autonomous Organization\" and \"AAO stack\"; both now link\nflashyos.com's canonical pages, rendered from canon.lock.json through\nsrc/lib/terms.ts so no route types a URL, with gda.group's answer page\nkept as the companion thesis. tests/content/term-map.test.ts holds it.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "92e157f4a6a1d96fa98d9070cea3b2619e25b5b6"
      },
      "digest": "ce7037f57c62654f45fb75a4123733f92d701381d308eea01e0fc3e67719de49"
    },
    {
      "id": "ship/claimyour.gold/8c94a7f0ed69",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T07:06:10Z",
      "kind": "other",
      "title": "devlog/1: re-emit the fragments on the rebased head",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Deterministic regeneration after rebasing onto two upstream emitter commits —\nthe served shiplog and devlog fragments now reflect the current tree,\nincluding the adoption commit itself as a devlog entry.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "8c94a7f0ed69431ecededabdbfe0ad6319c9e488"
      },
      "digest": "b888d4995b2c6bdd5e9ff78a069f92c930654d552f0a91e85a1f771fdfc83d4b"
    },
    {
      "id": "ship/claimyour.gold/a02e44f709bd",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T07:05:04+00:00",
      "kind": "feature",
      "title": "devlog/1: adopt it, re-vendored to current canon",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The devlog/1 adoption was built earlier but never committed — it sat in the\nworking tree while claimyour.gold/.well-known/devlog.fragment.json 404'd. This\nships it: serveDevlog in .shiplog/config.json, DEVLOG.md and the fragment\nderived by the current vendor-shiplog.mjs (re-vendored byte-identical to\nflashyos canon, which carries the machine-attribution fix this copy predated),\nserved at /.well-known/devlog.fragment.json. tests/devlog-fragment.test.ts\n15/15 green; tsc clean but for the one documented phantom mongodb-types error.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "a02e44f709bd13457a9b8833a2c8c0d16fc13c05"
      },
      "digest": "ba948e9a774c136878caada3e30c33f9950c2e651e0fe55769624585f56aec2f"
    },
    {
      "id": "ship/claimyour.gold/718859fbba8d",
      "repo": "repo/claimyour.gold",
      "at": "2026-10-04T00:03:53Z",
      "kind": "other",
      "title": "Badge: verified on the FlashyOS network",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The cross-product trust badge's accessible text said \"Verified on\nFlashyOS\". FlashyOS is the agentic network, as flashyos.com now says in\none sentence, and the badge is the one place this product names it to a\nstranger, so it names the network. The test pins the new text.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "718859fbba8db04ff1ce21065101387209e5ca83"
      },
      "digest": "b31cfe89248f120993aba1973ea41d76e1a2731420bb33bbf35f3fdf9762da90"
    },
    {
      "id": "ship/claimyour.gold/50e2b58073fc",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-22T16:25:20-04:00",
      "kind": "feature",
      "title": "Merge pull request #100 from FlashyLabs/claude/jolly-noether-oh1ev6",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "licence: put the AGPL text first so scanners detect it",
      "refs": {
        "commit": "50e2b58073fcc597fe663f35075b3f6c2c55a27d",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/100"
      },
      "digest": "9a1febc2da3357c93bf08f273bbd1225f1d7339118a5656a501db091f93c9dbb"
    },
    {
      "id": "ship/claimyour.gold/445f65c25045",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-22T15:04:33+00:00",
      "kind": "other",
      "title": "vendor-bolt.mjs: re-vendor from flashyos (multi-property emitter)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-10-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Byte-identical replacement of the drifted copy. .bolt/bolt.html and\n.bolt/bolt.js are unchanged — this property declares exactly one config, so\nthe newer multi-property loop produces the same output as before.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "445f65c2504564fe8d1ff537cc4e9b1322961f6a"
      },
      "digest": "a1189abcfa4faf801f5ac8bd8e65eb96314c6df707c7a4c9c387dde6056a4d1d"
    },
    {
      "id": "ship/claimyour.gold/cf399d293ef5",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-22T13:30:33Z",
      "kind": "feature",
      "title": "delivery/1: adopt the standard, tracking two Academy guides",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-22",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Files two deliverables through the ladder -- \"How to Claim Your Flashy Gold\nRewards\" and \"Flashy Gold Rewards: The Air Miles for the Web3 Generation\" --\nso a merged Academy guide has something checking it actually became\nfetchable, listed, and discoverable rather than only declared shipped.\n\nRedemption fulfillment (the /fulfil and /fulfill routes) was the first\ncandidate and is deliberately not what got wired: the format's last four\nrungs are settled by fetching a real public URL, and a redemption is a\nprivate, per-hunter transaction with no such URL. CLAUDE.md records that\nreasoning.\n\nWires the standard emitter, its CI workflow (observe on every push and\nevery six hours, fails on a regression or an unshipped live page), and\nformat tests -- driving the ESM vendor script as a subprocess, the way\ntests/hunt.test.ts already does for vendor-bolt.mjs, since ts-jest's\nCommonJS transpilation cannot import() an .mjs file directly.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "cf399d293ef57088fa485cf49a99a2828e13f9a2"
      },
      "digest": "a776bd126d2162ae184f01b796bc3dfc780b685a160a09190b6420ffde4dc255"
    },
    {
      "id": "ship/claimyour.gold/221c71078034",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-22T13:13:02Z",
      "kind": "docs",
      "title": "document the Mesh Concierge integration",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-22",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "/concierge.js and /concierge are already served, vendored byte-identical\nfrom Magician's canon. Record where and how, matching the doc note\npattern gda-group uses for the same integration.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "221c71078034b584e6c00b19c5a32a2f0b130bea"
      },
      "digest": "87794624d6b7d86a14c6699baa6b94850e0a72310b49be0b23af08220b184141"
    },
    {
      "id": "ship/claimyour.gold/4f94499c1288",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-21T15:57:30-04:00",
      "kind": "feature",
      "title": "Merge pull request #99 from FlashyLabs/dependabot/github_actions/actions-add0da0037",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-21",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "build(deps): bump the actions group across 1 directory with 7 updates",
      "refs": {
        "commit": "4f94499c1288c60d9c2fc96b2bb0477aedcea62d",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/99"
      },
      "digest": "580256340f6dace5b53e762c4512a17d9acd49655260eebea4753b6ebd716beb"
    },
    {
      "id": "ship/claimyour.gold/5599f1f85b44",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-21T15:21:40-04:00",
      "kind": "feature",
      "title": "Merge pull request #95 from FlashyLabs/claude/laughing-pasteur-lvg40h",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-21",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "codeql: keep the findings; never upload what a private repository cannot land",
      "refs": {
        "commit": "5599f1f85b4493096e44a04e4d5419ec6b700717",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/95"
      },
      "digest": "9eb46c317e1d3fbde6f16d554aac553a177f138ed4b653014b2198e8af342841"
    },
    {
      "id": "ship/claimyour.gold/767e07f1d26e",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-21T10:11:16-04:00",
      "kind": "feature",
      "title": "Merge pull request #98 from FlashyLabs/claude/inspiring-mendel-34uy2u",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-21",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "favicon: make the Claim Your Gold wordmark fill the tile, and bust the cache",
      "refs": {
        "commit": "767e07f1d26e07ed501607638c6da967e8921bc5",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/98"
      },
      "digest": "897fb92e9b369aa2cd459932001859d5fc69372ae6d73fc7809b70fc41b61ede"
    },
    {
      "id": "ship/claimyour.gold/120f1e0ed7a4",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-21T08:56:05-04:00",
      "kind": "feature",
      "title": "Merge pull request #97 from FlashyLabs/claude/code-estate-audit-wfm6ha",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-21",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "favicon: Claim Your Gold wordmark instead of the gold coin",
      "refs": {
        "commit": "120f1e0ed7a4398b25c745af77148cf3f0d2be1e",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/97"
      },
      "digest": "b917e960104bf62de1ea1b287e0860c0b20750cc028711f554eeaa95ad81075a"
    },
    {
      "id": "ship/claimyour.gold/2e75d3e440f8",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-19T03:01:52Z",
      "kind": "other",
      "title": "streak: stack shields across the unified pool, wire up both marketplace buys",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-21",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "claimDailyStreak() protected at most one missed day per claim and drew only\nfrom the free Customer.streakShields int. Two paid systems that write\nStreakShield rows -- buyStreakShield() (POST /api/portal/streak-shield/buy)\nand purchaseShield() (POST /api/v1/portal/streak-shield) -- charged real\nFlashy Gold for a shield that claimDailyStreak never looked at, so a customer\ncould hold three paid shields, miss two days, and still reset to day 1.\n\nclaimDailyStreak now draws from one pool: the streakShields int plus every\nactive StreakShield row, regardless of which endpoint sold it. A gap of N\nmissed days costs exactly N units, spending the int counter first and then\nrows soonest-to-expire first; if the pool is short, nothing is consumed and\nthe streak resets, so a partial charge never happens. Marking a row consumed\ngoes through one new shared helper (streakShieldService.markShieldConsumed)\nthat consumeShield(), applyShield() and this claim all call, replacing two\nindependent implementations of the same write.\n\nPre-existing unconsumed, unexpired StreakShield rows from either endpoint\nbecome usable automatically -- no migration needed.\n\nAdds shield-stacking coverage to tests/services/streakService.test.ts\n(consecutive claim, single-day gap from the int pool, multi-day gap spanning\nboth pools, and insufficient-pool with zero consumption) and updates\ndocs/streak-consequence-review.md to describe the unified, stacking pool.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "2e75d3e440f8ac6019e77089b1516c8bdbaa7e11"
      },
      "digest": "b5498aaba8bbbfdd0e468806f15df00c91078355000974a1c24814feea5a4ef7"
    },
    {
      "id": "ship/claimyour.gold/449ca5053b02",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-15T15:36:21Z",
      "kind": "feature",
      "title": "ledger: add the manual invariant trigger the force option always promised",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "runInvariantJob has carried a `force` option since it was written, documented\nas \"used by the manual trigger and by tests; never by the schedule\" — but\nnothing in the repository was ever that trigger. The reconciliation runs once a\nday during the 04:xx UTC hour, so a fix that lands on main and promotes to\nproduction then waits a full day before the verdict it exists to change is\nre-evaluated. A day between a fix and its verdict is a gate nobody can pass\nquickly, and it is exactly what would make \"green by tomorrow morning\" a\npromise this repository could not keep.\n\n`npm run invariant:run-now` (scripts/run-invariant-now.ts) is the trigger. It\ncalls the same runInvariantJob the schedule calls, with force: true, and writes\none run record to ledger_invariant_runs exactly as the nightly does — the public\nAPI and every page reading the verdict pick it up on their next request. It\ncomputes nothing the schedule would not and cannot make the verdict pass; it\nonly asks the question again, now. Exit code is the verdict (0 PASS, 1 FAIL or\ndid-not-run) so a shell can act on it, and it prints the same partition the API\npublishes plus any live breaks still failing the run. It needs DATABASE_URL, so\nit is run by whoever holds that, not by a workflow. Unlike scars:classify it is\nNOT read-only: it writes the run row.\n\nmain() is exported behind an argv guard so the test can exercise it without a\ndatabase. tests/scripts/run-invariant-now.test.ts pins the two properties that\nmake it safe to hand to an operator: it forces past the hour and once-per-day\ngates (a trigger that silently did nothing outside 04:xx would read exactly\nlike a passing run), and a run that did not happen exits 1, never 0.\n\ndocs/chain-breaks.md gains a \"Re-running the invariant on demand\" section.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "449ca5053b02c7626a88efde3f0632c8830f54f7"
      },
      "digest": "7e4ff824f0fb646097d6848be8baaa14e91f1855dd26f00f9460441af95e7e0e"
    },
    {
      "id": "ship/claimyour.gold/05a1fc3439b5",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-15T15:30:49-04:00",
      "kind": "other",
      "title": "Concierge: modal redesign re-vendor (#92)",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Concierge: modal redesign re-vendor",
      "refs": {
        "commit": "05a1fc3439b513e50bde72c05be297aa280898f7",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/92"
      },
      "digest": "9226853747262f5d1d97efe1313ee4ae5232f5bf60395a4266690f28c75d151b"
    },
    {
      "id": "ship/claimyour.gold/027d46cbcde8",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-15T11:05:07Z",
      "kind": "other",
      "title": "ledger: report-level tests + doc index for the signature scar",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Round out the H08 signature-forgiveness change with the coverage the\nper-customer test cannot give and the reachability the docs owed.\n\nTests — the invariant verdict reads the AGGREGATED report, not the per-customer\nresult, so prove the accumulate wiring end to end through reconcileAllBalances\nwith the REAL continuityScars module (not mocked): a reactivation-keyed break on\nan undeclared id is folded into report.chainBreaksScar and lifted out of\nreport.chainBreaksAfterWatermark when the customer reconciles; it stays in the\nfailing count when the customer drifts; and a reactivation scar is forgiven\nwhile an ordinary live break beside it still fails — the exact discrimination\nthe mechanism exists for.\n\nDocs — chain-breaks.md \"Where to look\" now points at src/ledger/continuityScars.ts\nand every test that pins the two-part gate, so the mechanism is reachable from\nthe reference rather than only from the diff.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "027d46cbcde847539a490e19770d436f85866204"
      },
      "digest": "58e98c60416ed32e8121ce20f1cf929ddb45d04a78ac456a21f5475c3ac220ec"
    },
    {
      "id": "ship/claimyour.gold/1b001b7e4d2b",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-15T10:59:15Z",
      "kind": "other",
      "title": "ledger: forgive the H08 reactivation orphan by signature, not enumeration",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The first post-promotion run flipped the 16 declared scars into chainBreaksScar\ncorrectly, but was still FAIL on 2 NEW after-watermark breaks (2026-09-14 ~10:00\nUTC, gaps 25 and 263.25) — the same H08 reactivation fingerprint. The cause is\nstructural: the reactivation code is fixed (no new orphan is created), but each\nhunter over-credited before the migration surfaces one continuity break the\nfirst time the migrated comeback credit next writes their entry, and those\nhunters return over weeks. Enumerating each is a commit-and-promote per night.\n\nForgive the H08 orphan by CAUSE instead. A live break is a scar — and forgiven\nonly when its customer reconciles exactly that run — if EITHER its entryPublicId\nis in DECLARED_CONTINUITY_SCARS (the closed historical set: the transposition\npair, the migration-window writes) OR the breaking entry's own idempotency key\nbegins `reactivation-credit:` (isReactivationScarBreak), the key\nreactivationService writes the migrated H08 comeback credit under. This is the\nsame recognise-by-write-key mechanism isDeliberateBreak uses for the 2026-08-17\nratifications, not a fragile time/gap heuristic.\n\nThe signature only says WHICH breaks the runtime value-gate may clear; it never\nclears one alone. Post-migration a reactivation credit journals every write, so\nit cannot create an orphan — a reactivation-credit break on an exactly-\nreconciling customer is by construction an old orphan being absorbed. A\nreactivation break on a drifted customer is NOT forgiven and fails the run,\nidentical to the enumerated path. comeback-milestone: (a journalled reward) is\nnot matched.\n\n- continuityScars.ts: REACTIVATION_SCAR_KEY_PREFIXES + isReactivationScarBreak,\n  with the rationale for signature-over-enumeration and the value guarantee.\n- ledgerReconciliationService: capture signatureScar from the breaking entry's\n  key in the walk; forgive on (declared || signature) under the same exact-\n  reconcile gate; chainBreaksScar bucket unchanged.\n- continuityScarRecon",
      "refs": {
        "commit": "1b001b7e4d2b8ca2d7fba829ba66713dd2eeef8b"
      },
      "digest": "4af03464dcd165961fc5fdecde1887890d21751577bd34d4b97f9bbcfbc88e5c"
    },
    {
      "id": "ship/claimyour.gold/3c4c12036f74",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-15T09:56:25-04:00",
      "kind": "infra",
      "title": "make flashy-app depend on the GatewayZ secret grant (#94)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-09-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Deploy prod #610 failed at terraform apply: the routine lane applies with\n-target= on the Cloud Run resources only, so the accessor grant from #93\nwas never applied and the new revision could not mount the secret.\nmodule.cloud_run_web now names the grant in depends_on; -target pulls in\ndependencies, so it applies first on both lanes. docs/provider-seam.md\nrecords the failure and what confirms the cutover.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HAQBuRxQyLbrVwVApDJu9n",
      "refs": {
        "commit": "3c4c12036f74b260e22d4e296e631b74901c4dde",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/94"
      },
      "digest": "2d7c417bd93a2ffd767ef76952e8c9f2ba8a2ce2c1d6a4e8de6edb99378fe361"
    },
    {
      "id": "ship/claimyour.gold/94dfddb8e479",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-15T09:03:12-04:00",
      "kind": "infra",
      "title": "route the live /ops inference through GatewayZ (flashy-app) (#93)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-09-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Set LLM_PROVIDER=gatewayz on flashy-app and map FLASHYOS_GATEWAYZ_API_KEY to the GATEWAYZ_API_KEY env the seam reads, with a runtime-SA accessor grant. Anthropic stays the breaker fallback; only src/lib/os capability calls read this seam. Rollback is one line.\n\nCo-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HAQBuRxQyLbrVwVApDJu9n",
      "refs": {
        "commit": "94dfddb8e4791367aea8e5bf7eb5e6c4ab1e3e47",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/93"
      },
      "digest": "cfec48a4ad2bc1b68b440fa953495810f30ab44d002c8e7f8f64d18e6612a031"
    },
    {
      "id": "ship/claimyour.gold/b895e3e3b02d",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-15T00:39:14Z",
      "kind": "fix",
      "title": "ledger: fix continuity-scar test to jest's one-arg expect",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The register-shape assertions used expect(value, message) — the vitest\ntwo-arg form. jest's expect takes exactly one argument, so tsc failed the\nbuild with TS2554 (Expected 1 arguments, but got 2) on four lines, which\nblocked promotion and kept the invariant on FAIL. Drop the message args;\nthe loop context and the value under test already identify a failure, and\na short comment on each carries what the message said.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "b895e3e3b02dc02c26f456df18a059024e1d45d5"
      },
      "digest": "5585f60e25894e12ac3abd2c0bcd17b023a81000e92f66956aa1d19a2db0d918"
    },
    {
      "id": "ship/claimyour.gold/4be817185e3a",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-15T00:25:59Z",
      "kind": "feature",
      "title": "ledger: declare the 16 continuity scars, with register guards and docs",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-15",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "4be817185e3a45640fafde42ee7b831df251fc38"
      },
      "digest": "9006f4b4d9ba1ec517cfb70efae3f1ff4703cc0b8aec53198232476fac2ed911"
    },
    {
      "id": "ship/claimyour.gold/7fe6755dd5eb",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-13T13:21:43Z",
      "kind": "other",
      "title": "ledger: enumerated, value-verified continuity-scar exemption",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-13",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Resolves the post-watermark continuity breaks the invariant fails on, without\nmoving any bar. Diagnosis: the dominant cause is the pre-migration H08\nreactivation \"comeback credit\" (a bare wallet.updateMany(+25) with no ledger\nentry, daily at 10:00 UTC). The code is already migrated to postEntry; the\norphaned wallet inflations it left behind surface as one-time +25 breaks when\nan affected hunter next earns. Gold is all present (drift 0, all hash chains\nverify) — the discontinuity is a value-neutral linkage scar, unrepairable by\nany append-only op.\n\nThe mechanism (src/ledger/continuityScars.ts) forgives such a break only under\na TWO-PART gate: (1) its entryPublicId is in an enumerated DECLARED list (names\neach entry, never widens a threshold), AND (2) at reconciliation time its\ncustomer reconciles exactly — re-checked every run, so a named customer who\ndrifts stops being forgiven and the run fails. A declaration can forgive a\nprovably value-neutral discontinuity and nothing else.\n\n- reconcileCustomer reclassifies declared scars on exactly-reconciling\n  customers into a new chainBreaksScar bucket, out of chainBreaksAfter/Undated;\n  verdictFrom excludes it from FAIL exactly as it does chainBreaksDeliberate.\n- chainBreaksScar wired through the report, persisted run, and public API.\n- scripts/classify-continuity-scars.ts (npm run scars:classify): READ-ONLY,\n  proposes a DeclaredScar only when it can prove value-neutrality AND match a\n  known silent-write signature; everything else it lists STILL RED. The\n  registry starts EMPTY — the invariant stays honest until a human runs the\n  script against prod and commits the reviewed output.\n- Tests pin both halves of the gate (forgiven when reconciling, NOT forgiven\n  when drifting or undeclared) plus registry hygiene (reason >= 40 chars).\n- docs/chain-breaks.md documents the resolution.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "7fe6755dd5ebb7219c0839615af23d2dc7e1bfc0"
      },
      "digest": "291db081cf80019625821cf39a78623871dbe63bf601eb20796bf40734aba063"
    },
    {
      "id": "ship/claimyour.gold/bee43d05530f",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-13T00:55:58Z",
      "kind": "feature",
      "title": "public ledger API: expose the live continuity breaks, anonymised",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-13",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The invariant fails solely on 14 breaks recorded on/after the watermark, while\nthe totals tie out, all 903 customers reconcile and all 526 hash chains verify.\nBut latestInvariantRun() exposed only the flat chainBreaks (290, dominated by\nthe historical scar) — so the 14 that actually decide the verdict were visible\nnowhere but a direct read of ledger_invariant_runs.\n\nPublish the breakdown: chainBreaksAfterWatermark / Undated / Deliberate, the\nwatermark, and liveBreakSample — the 14 themselves, oldest first. The stored\nsample names the customer each break belongs to; toPublicBreaks() strips that\nby construction (it names every field it copies and customerId is not one), and\nthe privacy-line test now seeds a customer id into the sample and asserts it\nnever appears in any returned shape. Partition fields stay nullable end to end:\na run that predates the split renders null, never a zero that would certify a\nclean live chain on evidence that does not exist.\n\nDiagnosis-only: the reconciliation still writes nothing. docs/chain-breaks.md\nrecords the two candidate root causes (a cutover seam vs a genuine\ndiscontinuity) and why the continuity check must not be touched until the\nexposed sample says which — a fix that silenced one would silence both.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U",
      "refs": {
        "commit": "bee43d05530fc1dcac15788a09b9f92d8b5dafe3"
      },
      "digest": "2fc4fc59e41080282b09854be4b40120077019628672dc27beac0f8e5b628f99"
    },
    {
      "id": "ship/claimyour.gold/0513092ce847",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-12T11:16:21-04:00",
      "kind": "feature",
      "title": "Merge pull request #90 from FlashyLabs/claude/code-estate-audit-wfm6ha",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-13",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Re-vendor check-directory.mjs from canon",
      "refs": {
        "commit": "0513092ce8475a9851fefe75ff9491c176cf4915",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/90"
      },
      "digest": "ef6a6e46d52b4c5dec854515f9467f0245b155901bf53bed714033cc5723384c"
    },
    {
      "id": "ship/claimyour.gold/e647d8337964",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-08T14:20:11Z",
      "kind": "infra",
      "title": "Link the reference shelf: seventeen documents nothing pointed at",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-08",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "This repository held 68 documents that no page, test, workflow or file\nreferenced — more than any other in the estate, and 4,500 words of them\ndescribe how the thing actually works: the data flows, the index\nchoices, the Redis key shapes, the settlement paths, the provider seam,\nthe jobs nothing schedules.\n\nA document nobody links is one the next person rewrites from scratch,\nand this repository has 3,342 source files to rewrite it against.\n\nSeventeen are now on a shelf in the file an agent reads first. Thirty-nine\n`docs/sessions/*-prompt.md` are declared as an archive in\n`estate-findable`'s own register — retained history rather than routing,\nthe same distinction flashyos draws for its superseded design revisions.\n\n**The eleven dated documents are deliberately still unlinked.**\n`civilization-audit-2026-08-27.md` and its siblings carry a date because\nthat is what they are: a reading taken on a day. Listing them beside the\nreference shelf would present a July audit as current, which is the\nfailure this estate names as a verdict in prose reading as settled. They\nremain visible to the survey as an open decision — archive them under a\nprefix, or delete them — and that decision is not one a linking commit\nshould quietly make.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BjzD1kWqueq1ArT1m4mZsy",
      "refs": {
        "commit": "e647d83379644d2b4efd3b97c8f980c6cceecc76"
      },
      "digest": "4db67c69c9a86dd03b698e0fcbdc141dc7ef91221dfae1d410871a79f82e4902"
    },
    {
      "id": "ship/claimyour.gold/202ccae369b3",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-08T12:36:45Z",
      "kind": "other",
      "title": "Re-vendor check-directory.mjs: it never took dependsOn",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-08",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`@flashyos/directory` added the `dependsOn` edge type — the only edge a\nstranger can check without asking us, since a version range is verifiable\nfrom a registry — and the vendored checker in flashyos was updated with\nit. This copy was not, so it would reject a valid `dependsOn` edge as an\nunknown type while the canonical validator accepts it.\n\nThat is how a vendored copy fails: not by breaking, but by disagreeing,\nsilently, about exactly the field somebody has just changed. Seventeen\nrepositories carried the older copy and the estate's `Vendored emitter\ncurrent` dimension read 15 of 34.\n\nByte-identical to `packages/directory/vendor-check-directory.mjs`;\n`tools/vendored-directory.test.mjs` in flashyos compares every copy and\nfails on any difference.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BjzD1kWqueq1ArT1m4mZsy",
      "refs": {
        "commit": "202ccae369b374039cc018cc9799e326c8da54c4"
      },
      "digest": "c0082837899730ea2a9374d9fdabc2d78811bde88b25068e2bbe7e34aa493ae1"
    },
    {
      "id": "ship/claimyour.gold/f6301bcc5e34",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-08T12:12:41Z",
      "kind": "other",
      "title": "The index describes the shipping ref, not this laptop",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-08",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The first version generated from `git ls-files` — the working tree. On a\ncheckout six commits behind its remote that saw three documents where the\nref holds six, so it would have written an index naming half of them and\nreported the repository done. Across this machine 39 of 40 checkouts are\nbehind their remote, so almost every index written yesterday described a\ntree that ships nowhere.\n\nSay which tree you measured — this estate's first house rule, broken by\nthe tool written to make things findable, and the third tool here to\nbreak it. It reads `git ls-tree` and `git show` against the shipping ref\nnow, so a document committed on a laptop and pushed nowhere is\ndeliberately absent: a reader who follows a link to a file only one\nmachine has is a reader the index lied to.\n\nThe generator and the gate also disagreed about what a document IS —\n`SPEC.md` was an entry point to one and not the other — so the gate could\nask for an index in a repository the generator refused to write one for.\nThe population is imported now, one definition.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BjzD1kWqueq1ArT1m4mZsy",
      "refs": {
        "commit": "f6301bcc5e343a1965ec0977c52c325b0ab58cb5"
      },
      "digest": "5a15eb30a32ef5f3194e87dc3e79eaf772781bb97183c1f3cc115ce9e5055726"
    },
    {
      "id": "ship/claimyour.gold/4adbb1d08711",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-08T12:00:18Z",
      "kind": "other",
      "title": "An index of every document and every runnable, generated from the tree",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-08",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "This repository held documents that nothing pointed at and scripts that\nnothing named. `tools/estate-findable.mjs` in flashyos measured the\nestate at 9 of 25 repositories with reachable documents and 0 of 16 with\nany index at all — nobody had built a door, so nobody had one to add a\ndocument to.\n\nGenerated, never maintained. Every title is read from the document's own\nfirst heading, every date from its last commit, and every runnable's line\nfrom that file's own first comment. A document added here is in the index\non the next run whether anybody remembered it or not, which is the one\nproperty a hand-written index does not have.\n\nBeing listed is not being used. `estate-findable` excludes a generated\nindex from vouching for anything, so writing this moves `docsIndexed` and\nleaves `docsReachable` exactly where it was. Three states, not two:\nunlisted, listed-and-unused, and reached by work.\n\nRegenerate with `node tools/estate-doc-index.mjs --write` from a flashyos\ncheckout beside this one; `--check` runs in `npm run estate` there.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BjzD1kWqueq1ArT1m4mZsy",
      "refs": {
        "commit": "4adbb1d087115b660b50e90abded8cd7f4069217"
      },
      "digest": "11c5ad8b0764a83ed325dfeb41e3c4535bf6d4e11c70c86716d76f73f1895c4d"
    },
    {
      "id": "ship/claimyour.gold/1fee8335210d",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-08T08:41:45-04:00",
      "kind": "feature",
      "title": "Merge pull request #89 from FlashyLabs/claude/leaderboard-alltime-fix",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-08",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Fix the broken All-Time leaderboard (Mongo groupBy relation filter)",
      "refs": {
        "commit": "1fee8335210db672e6f20e8bca20e5a62f542458",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/89"
      },
      "digest": "a25df1696501818a0a89909ceb3267cf2dd7692012eff18f5a95bc66243a0b68"
    },
    {
      "id": "ship/claimyour.gold/d9e53b079986",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-07T15:59:37-04:00",
      "kind": "feature",
      "title": "Merge pull request #54 from FlashyLabs/claude/canonical-host-env",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-07",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Let the sitemap host resolve from either env var name",
      "refs": {
        "commit": "d9e53b079986113ae4b1c545f60e45897fde8fbc",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/54"
      },
      "digest": "7843a2dd5b71de1f98178946bb3e70e6dc0fe069ab1ed16f14013f36eb902217"
    },
    {
      "id": "ship/claimyour.gold/72cef5c65950",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-07T15:10:40-04:00",
      "kind": "feature",
      "title": "Merge pull request #55 from FlashyLabs/claude/fix-broken-cross-links",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-07",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Fix two dead links on earning paths: /join?ref= and /portal/earn",
      "refs": {
        "commit": "72cef5c65950c84bef38257de9a0e1ed9a80593f",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/55"
      },
      "digest": "52548cd3d6c07bb31c5613ffb8aed573411ad3f798a842f256ca879360865bc4"
    },
    {
      "id": "ship/claimyour.gold/e8cc869b3660",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-07T15:05:14Z",
      "kind": "feature",
      "title": "Merge origin/main",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-07",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "e8cc869b366036b14ca7ab97c05580b827f463b0"
      },
      "digest": "f78f323a1f21a99a93dda0dc0646071e250bb322ea96610477bfd953d8293188"
    },
    {
      "id": "ship/claimyour.gold/80a0e0a8420f",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-07T15:04:18Z",
      "kind": "other",
      "title": "Re-vendor the branch-mesh scripts from canon",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-07",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A vendored file does not fail when it drifts — it disagrees, silently, about\nwhichever field somebody has just changed. These copies were behind flashyos's\n`scripts/`, and the drift check in that repository is what noticed.\n\nThe version that matters is the one that tells a plan cap apart from a broken\ngate: `classifyMintFailure` reads the status plus a marker, never the sentence,\nbecause a checker that greps product copy stops working the day somebody\nimproves it. A cap still fails the run — reporting nothing is reporting\nnothing, whatever the reason — and the log now says which of the two it was.\n\nKind: chore\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BjzD1kWqueq1ArT1m4mZsy",
      "refs": {
        "commit": "80a0e0a8420f39d49037aa6dd964e1cc50dcafb0"
      },
      "digest": "4a7e08fa6b91ec66990a0528139f0c624122d58bd25611b8448af3dd29bfe2cb"
    },
    {
      "id": "ship/claimyour.gold/1d469ba37f39",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-07T13:55:51-04:00",
      "kind": "feature",
      "title": "outbox worker (increment 2) — settle earns, park debits (#88)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-09-07",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* feat(rail): outbox worker (increment 2) — settle earns, park debits\n\nRoadmap #6, increment 2, on top of the merged increment-1 outbox. Flag-off\nand inert until the first cutover (no migrated holder ⇒ no outbox row ⇒\nnothing enqueued).\n\n- railOutboxWorker.ts — drainCustomerOutbox drains a holder's pending rows\n  oldest-first (per-holder FIFO), settles each EARN through the rail's\n  idempotency-keyed railReward (exactly-once: the rail dedups on the outbox\n  key), marks it settled. A rail error marks the row (attempts++, lastError)\n  and rethrows so BullMQ retries with backoff; settled rows are skipped on\n  retry, so FIFO holds. Fail-safe: inert when the rail is unconfigured.\n- DEBITS ARE PARKED, deliberately. A redeem/transfer settles only through the\n  rail's draft→execute consent gate, which needs a consent token bound to the\n  draft — mintable only by flashyID's human consent flow (not wired yet, and\n  the outbox carries no token). Such a row is marked `blocked` (never failed,\n  never guessed, never double) and the drain stops. Completing debit\n  settlement is the increment after the consent flow.\n- railOutboxQueue.ts / railOutboxScheduler.ts — Redis-guarded BullMQ queue\n  (one in-flight drain per holder via jobId) and a periodic sweep that\n  enqueues holders with pending rows (decoupled from postEntry's transaction).\n\nAlso (roadmap #2, CYG copy nit): the redeem OG alt-text said \"Redeem Center\nNow Live\" while the pages say \"coming soon\" — redemption is waitlist-stage,\nso the overclaiming alt-text is corrected to \"Redeem Center\".\n\nTests (tests/jobs/railOutboxWorker.test.ts): inert-when-unconfigured, earn\nsettles with the outbox key, FIFO stop + rethrow on rail error, debit parked\nblocked, and a malformed earn failed-not-looped. NOT validated locally\n(@flashylabs/ledger is a private GitHub Packages dep this environment can't\ninstall) — CI is the gate; flag-off keeps prod unaffected until a cutover.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>\nClaude-Ses",
      "refs": {
        "commit": "1d469ba37f39f8c6a5844cd5f7477a2eb76ee8b9",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/88"
      },
      "digest": "71c7de108bde2284da6e17a6f77a75b825ec0b8210afe72d867bc1a044769ef3"
    },
    {
      "id": "ship/claimyour.gold/e6b732202549",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-07T13:50:18Z",
      "kind": "docs",
      "title": "Move the house-rules marker below this repository own prose",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-07",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The opening marker sat ABOVE this repository sections rather than below them,\nso the region the estate sync owns had grown to contain prose that is this\nrepository own. Running the sync deleted it — caught in the diff and reverted,\nthen fixed here.\n\nFive lines move; no content changes. flashyos tools/estate-house-rules.mjs now\nrefuses this shape rather than replacing it, naming the sections it would have\nlost.\n\nKind: docs\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01DryqvxX93nEakD77pNANCt",
      "refs": {
        "commit": "e6b7322025492d97acaae0c41bf75b3b135b027d"
      },
      "digest": "8e5c3caf709f45c09c805614fac920cfce6c514fe593a1bdd9f92a7f8b8a08ad"
    },
    {
      "id": "ship/claimyour.gold/5b7d1377828d",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-07T12:39:23-04:00",
      "kind": "feature",
      "title": "Merge pull request #87 from FlashyLabs/claude/trust-routing-network-77xwmg",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-07",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Merge main, and carry the session's estate work to the shipping ref",
      "refs": {
        "commit": "5b7d1377828d9a74000881ba4e1a2c8a3085dafa",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/87"
      },
      "digest": "df0a7ef1fbcbe1884d0d6dec2ce456d9924c53e97db7994d5f6e5039c404ff7f"
    },
    {
      "id": "ship/claimyour.gold/807fedb1b2c7",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-07T12:32:43-04:00",
      "kind": "feature",
      "title": "Merge pull request #86 from FlashyLabs/claude/source-code-audit-b97g8c",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-07",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "feat(rail): outbox increment 1 — RailOutbox + migration gate + flag-off postEntry branch",
      "refs": {
        "commit": "807fedb1b2c70a57bf25626fa6e70e760d9d063b",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/86"
      },
      "digest": "55a97010312bc6c85a7f60996f56e8aefca738805d8129d2aee08fd515d19091"
    },
    {
      "id": "ship/claimyour.gold/d0f512432ad7",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-07T09:44:59-04:00",
      "kind": "feature",
      "title": "Merge pull request #85 from FlashyLabs/claude/source-code-audit-b97g8c",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-07",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "docs: rail-cutover plan (outbox design) — for review before implementation",
      "refs": {
        "commit": "d0f512432ad7a651354df5d0acadfaf37f6d7f26",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/85"
      },
      "digest": "69840aae4ca7620acf3061b4e1f2fc2e9d97c7a50393108ff2c24eb6044c31a0"
    },
    {
      "id": "ship/claimyour.gold/37f6c2008433",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-06T12:35:19-04:00",
      "kind": "fix",
      "title": "reconstruct ledger continuity from the hash chain, not createdAt (#84)",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-09-06",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "fix: reconstruct ledger continuity from the hash chain, not createdAt",
      "refs": {
        "commit": "37f6c200843382aa054d3c130d644b961382f8ad",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/84"
      },
      "digest": "ccf2185f88bd6464e1a0e0ef4fcf32e4553fdbc94d5567c5b2fb0d721359bb32"
    },
    {
      "id": "ship/claimyour.gold/71a50a51ae77",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-06T12:14:15+00:00",
      "kind": "fix",
      "title": "Hold the entries that publish another property's shard",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-06",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A `shipped/1` entry is served at this repository's public well-known surface,\nwhich any stranger can fetch. Nine entries across seven properties named other\nproperties' `bolt/1` shards — six of them titled \"This property hides <WORD>\" —\nso the estate's own public record was handing out the answers to its own hunt\nwhile every structural check reported the hunt healthy.\n\nFound by tools/bundle-reach.mjs in flashyos on its first run, which walks what\na deployed page can reach. The export-surface test that was meant to cover this\nclass reads a package's named exports, where the words are genuinely absent,\nand an export surface says nothing about what a bundler carries.\n\n`.shiplog/held.json` maps the sha to the reason. The entry stays in this\nrepository's own record, sealed and counted; only the published projection\nomits it. That is the mechanism built for an entry naming a rotated credential,\nused here for the second time.\n\nHolding is NOT remediation. The commit message is still in git history, and an\nentry is sealed once — re-deriving to remove it is the destructive operation\nthe house rules already warn about.\n\nKind: fix\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\n\nClaude-Session: https://claude.ai/code/session_01BjzD1kWqueq1ArT1m4mZsy",
      "refs": {
        "commit": "71a50a51ae777a5a31bbc8c6e9a5ac8b5e750ad4"
      },
      "digest": "5a62517c95bdf0db3a2969a58a6aae80e95140ff2e26a93e25ac7f4691a5396e"
    },
    {
      "id": "ship/claimyour.gold/11bd09f9900d",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-06T11:23:42+00:00",
      "kind": "fix",
      "title": "Land the component half of the egg fix, which the previous commit dropped",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-06",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The previous commit here carried .bolt/bolt.js and the re-vendored emitter and\nNOT the component that imports them, so its message described a fix half of\nwhich was not in it. The cause is worth writing down because it is silent: a\nsingle `git add -A a b c` with one pathspec that does not exist in this\nrepository fails the whole command and stages nothing, and the loop that ran\nit sent stderr to /dev/null. Every repository reported a clean push.\n\nThe component is the half that matters. It imports `.bolt/bolt.js` rather than\ncomputing a path to `.bolt/bolt.html` at request time — a computed path is\ninvisible to Next's output file tracing, so the file is not carried into the\ndeployed function, existsSync returns false, and the component returns null\nsilently. That is why Tier I of bolt/1 was unwinnable a week after it was\nsealed as a permanent puzzle.\n\ntests/hunt.test.ts is the invariant rather than the repair: import and never\nread, a module that exists and carries this property's shard, module and HTML\nthe same bytes, the layout actually rendering it, the emitter reproducing what\nis committed, and the vendored emitter byte-identical to canon. Every\nassertion strips comments before matching, because a test that greps a file\npunishes an explanation.\n\nKind: fix\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\n\nClaude-Session: https://claude.ai/code/session_01BjzD1kWqueq1ArT1m4mZsy",
      "refs": {
        "commit": "11bd09f9900dc7333f3ca95d80c4cf521c69a4eb"
      },
      "digest": "7e6154f2bcfee0e2dd058dcc2c822fb85c568ebc3aa076dbb2c68758d910fc3a"
    },
    {
      "id": "ship/claimyour.gold/0a764fd9be71",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-06T11:17:56+00:00",
      "kind": "fix",
      "title": "The egg is carried by the bundler, never read at runtime",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-06",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Tier I of bolt/1 was sealed on 2026-08-31 as a permanent puzzle and was\nunwinnable a week later. The correlation is by MECHANISM rather than by\nproperty: every property that bakes the snippet into committed HTML serves\nits shard, and every Next property that reads it at request time serves\nnothing — with the code on the shipping branch, the deploy current, and\nnothing anywhere red.\n\nA path computed from process.cwd() is invisible to Next's output file\ntracing, so the file is never carried into the deployed function, existsSync\nreturns false, and the component returns null. Silently, because the format\nmade absence silent on purpose so a checkout with no shard would still build.\nThat explanation is consistent with every data point available and is NOT\nproven — settling it needs a production build served by `next start`, or the\nVercel build log.\n\nSo this does not argue with the hypothesis; it removes the question.\nvendor-bolt.mjs now emits `.bolt/bolt.js` beside the HTML, and the component\nimports it. A static import is a dependency the bundler can see, and an\nabsent module is a build error rather than a page that quietly has no egg.\nAn entire failure class goes away rather than one property being patched with\nan outputFileTracingIncludes entry the next adopter has to rediscover.\n\nProved in flashyos rather than assumed: before this change the shard appeared\nin nothing the marketing build emitted; after it, in two server chunks.\n\nThis property had no test for its egg at all, which is why nothing said so.\nIt has one now, and it asserts the invariant rather than the repair: the\ncomponent imports and never reads, the module exists and carries this\nproperty's shard, the module and the HTML are the same bytes, the layout\nactually renders it, and the emitter run here reproduces what is committed.\nEvery assertion strips comments before matching, because a test that reads\nprose punishes an explanation — this estate's recorded mistake three times\nover, and made twice more while",
      "refs": {
        "commit": "0a764fd9be71f9b5e1a46344cab9bcb00222b230"
      },
      "digest": "e0bf9819a939e2e0ca7d9e20e9cb5c0a3c38a07b1afcce22a23ac4f0ff59f569"
    },
    {
      "id": "ship/claimyour.gold/8b515b005128",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-05T12:41:59+00:00",
      "kind": "docs",
      "title": "the hunt's size is not written down here",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-06",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "\"ten domains\" was true when the section was written and is not now — the\nestate register decides who plays, and a count in prose decays faster\nthan anything else recorded here. The sentence says what is durable\ninstead: every live property hides one word.\n\nKind: docs\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BjzD1kWqueq1ArT1m4mZsy",
      "refs": {
        "commit": "8b515b00512849e483dca71e9508aba101e53591"
      },
      "digest": "3434f58fed1cbbc773d108c099084bb4e6cc64213c4f72ddd989d68ddfe43862"
    },
    {
      "id": "ship/claimyour.gold/a844a08db1ba",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-04T19:23:51+00:00",
      "kind": "feature",
      "title": "Promote to production automatically — the click was the part that broke",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-06",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Kind: feature\n\n`promote-to-production.yml` opened a pull request and stopped, on the\nreasoning that shipping a live rewards product is a decision and only\n*remembering* should be automated. That was right about the decision and\nwrong about the cost.\n\nOpening a PR needs Settings → Actions → General → \"Allow GitHub Actions to\ncreate and approve pull requests\", which this repository does not have on. So\nthe default lane failed, and the lane that worked needed somebody to find a\nworkflow_dispatch input and tick a box. What that cost, measured: a partner\nlocked out of /partner/login stayed locked out while the fix sat on main,\ngreen, for hours. A gate nobody can pass only ever stops the right change.\n\nWHAT WAS REMOVED IS THE CLICK. THE GATE IS STRICTER THAN THE RULE IT REPLACED.\n\nThe old workflow raised its PR over \"the commit whose CI run triggered this\".\nThis finds the newest commit on main that carries a PASSING CI verdict and\npromotes exactly that. They are different commits most of the time — main's\nhead is usually an emitter's `[skip ci]` refresh with no verdict at all, so\nmerging the trigger's own sha would have shipped an unchecked commit roughly\nhalf the time. Anything newer than the green commit waits for the next run,\nand the run summary says how many were left behind.\n\nA red commit stops the walk: nothing past a failure is promotable.\n\nIt never calls `gh pr`, so it needs no repository setting — pushing wants\nonly `contents: write`. `open_pr_only: true` on a manual run restores the old\nbehaviour for a promotion somebody wants to read first; that lane still needs\nthe setting, which is why it is no longer the default.\n\nStill a merge commit, never a squash or a rebase: production carries 2,596\ncommits of its own history against main's 300 of a rewritten one, and\nsquashing would restart that divergence from a new base.\n\ntests/scripts/promote-to-production.test.ts pins all six properties. The\nclick was the visible half of the safety; the gate is the half that matte",
      "refs": {
        "commit": "a844a08db1ba4353e401b8688dbd371bf29a6c9f"
      },
      "digest": "385fe3647488d40aa44530da5cfedc873d7516c802e5eaa923370fd77c86f28f"
    },
    {
      "id": "ship/claimyour.gold/3019ee1ec97f",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-04T18:58:14Z",
      "kind": "fix",
      "title": "Restore the lockfile the previous commit stripped",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "To run the test suite here I temporarily removed the two @flashylabs\ndependencies from package.json — they live on GitHub Packages and this\nsandbox has no token, so `npm ci` cannot complete with them. I restored\npackage.json afterwards and checked it matched HEAD. I did not check\npackage-lock.json, and `git add -A` carried it into the commit with all\nseven references to those packages gone.\n\n`npm ci` installs from the lockfile, so CI would have built a tree\nwithout @flashylabs/ledger and @flashylabs/flashyid-sdk — which\nsrc/ledger/anchor.ts, src/lib/arenaGate.ts and the hunter-engagement\nroute all import. A red main, and it would have blocked the promotion\nthis very change is meant to reach production through.\n\nCaught by checking the commit's own file list rather than by the tests,\nwhich cannot see it: they were already failing on those two modules for\nexactly the same reason, so nothing in the suite could have gone from\ngreen to red to say so.\n\nThe lockfile is restored byte-for-byte from 1d044e83. Nothing else in\nthat commit is touched.\n\nKind: fix\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "3019ee1ec97f237497c5b7bbc0d8d943ffeab45f"
      },
      "digest": "b43bf6107637199bcf0ae28a704b00e935df992676f182cf44b1847d402539bb"
    },
    {
      "id": "ship/claimyour.gold/36c0beb200a3",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-04T18:57:43Z",
      "kind": "fix",
      "title": "Make the reset pages say what happened, instead of blanking",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two bugs found by testing the flow rather than the rules, and both are in\nthe CLIENT pages as much as the partner ones — the partner pages have\nthem because they were copied from the client ones.\n\napiError answers `{ success: false, error: { message, httpStatus, code } }`\nso `error` is an OBJECT. All four pages did `setError(d.error)` and then\nrendered `{error}`, and React refuses a plain object as a child. So an\nexpired link, a weak password, a rate limit — every error path — threw at\nrender instead of printing a sentence. The page a person only reaches\nbecause they are already locked out was the page that went blank when\nanything went wrong.\n\nThis was found by a test asserting the wrong response shape. Being wrong\nabout the shape is what surfaced it; a test written to match the code\nwould have agreed with the bug.\n\nAnd the reset pages checked length, lowercase and uppercase while\nstrongPasswordSchema also requires a digit and a symbol — with helper\ntext promising only the three. Somebody following the rule printed under\nthe field was rejected by the server for a rule the page never mentioned.\nThe client checks now mirror the schema exactly and the helper text says\nall four.\n\nFifteen route-level tests cover the layer a browser actually hits: a\nknown and an unknown address answer identically, a spent per-address\nbucket stays quiet rather than 429-ing (a 429 would confirm the address\nis worth retrying), the IP bucket does 429, every password rule comes\nback naming which rule, and an AppError passes through with its own\nstatus and code rather than as a 500.\n\nVerified by running the suite twice, once with these changes and once\nwithout: 254 failing suites either way, zero new. Every one of those is\n`Cannot find module '@flashylabs/*'` — the two GitHub Packages\ndependencies this sandbox cannot install. The partner service (14), the\npartner routes (15), the middleware (12) and the three client auth\nsuites all pass.\n\nKind: fix\n\nCo-Authored-By: Claude Opus 5 <noreply@anthr",
      "refs": {
        "commit": "36c0beb200a3c93187fc7889d459b1cbe7c46f39"
      },
      "digest": "e14284dc66efe150c013859340432cb8199b82855435383adee82d71af5a1444"
    },
    {
      "id": "ship/claimyour.gold/1d044e8319e8",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-04T18:21:21Z",
      "kind": "feature",
      "title": "Give partners a way back in, and make a reset token say which login it opens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "/partner/login had no reset link and no reset page. A partner who forgot\ntheir password had exactly one route back: an operator running\nPOST /api/v1/super/reset-partner-password by hand. Locked out at 9pm\nmeant emailing support and waiting until somebody read it.\nchangePartnerPassword was no help — it rotates a password you still know.\n\nThe flow is deliberately the same shape as the client one rather than a\nsecond design: one hour of validity, one use, bcrypt cost 12,\nsessionVersion incremented so every other session dies with the old\ncredential, and silence on an unknown address so the endpoint cannot be\nused to enumerate partners. A PENDING partner who completes it becomes\nACTIVE, which lets an operator's invite travel the same road rather than\nneeding its own. An INACTIVE partner is refused, and at the request stage\ntreated as absent — a working link for somebody whose access was\nwithdrawn ends at a login they cannot pass, and answering differently\nwould confirm the account exists.\n\nTWO THINGS THAT COULD NOT BE COPIED\n\nPasswordResetToken now carries `audience`. Nothing stops one person\nholding a client account and a partner account on the same address —\nrunning a venue and partnering with us is an ordinary combination — and\nresetClientPassword resolves an address by looking up a Client and then a\nClientUser. Reusing the token table without this field would mean a\npartner following their own reset link silently rotated their CLIENT\npassword and was told it worked, while the credential they were trying to\nchange stayed exactly as it was. Both reset functions now refuse the\nother's tokens.\n\nThe field is optional rather than defaulted. Tokens issued before it\nexisted have no value for it, and a required column would make them\nunreadable; `null` is read as CLIENT, which is what every one of them is,\nso links already sitting in inboxes keep working.\n\nAnd the email is its own function. sendPasswordResetEmail hardcodes\n/client/reset-password, so reusing it would have sen",
      "refs": {
        "commit": "1d044e8319e8b976b82698931143004878176bf2"
      },
      "digest": "091a32f99d9b63c4c446f58498d082be5a37438957a4ea70290f6b0f2a968198"
    },
    {
      "id": "ship/claimyour.gold/0f6b25ad10a8",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-04T18:01:56Z",
      "kind": "fix",
      "title": "Unlock the four pages you can only reach without a session",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Nolan reported the \"Forgot password?\" link on /client/login: the anchor\nrenders, the browser shows the right target in the status bar, and\nclicking it returns you to the login page. The link was never the\nproblem — the destination was.\n\n`isClientProtected` allowed exactly two paths, /client/login and\n/client/register, so every other page under /client was treated as\nrequiring a session. /client/forgot-password is the page that exists to\nhelp you when you cannot log in, and it required you to be logged in.\n\nThree more were broken the same way and nobody had tried them:\n\n  /client/reset-password  where the emailed link lands — so the reset\n                          flow was dead end to end, not only at its door.\n                          Even a partner who received the mail could not\n                          have used it.\n  /client/verify-2fa      login-form.tsx redirects here when a code is\n                          required, and there is no token yet by\n                          definition, so any client admin with 2FA on\n                          could not log in at all. A loop, not a 404.\n  /super/verify-2fa       the same shape on the super side.\n\nOpening these adds no exposure, and it is worth being precise about why\nrather than asserting it. Middleware could never have protected them:\neach is reached by somebody holding no token, which is the only state the\nguard can see, so the check was always a no-op that redirected. The real\nenforcement is where it has to be — authorize() in authOptions.ts throws\nTOTP_REQUIRED without a code and verifies it against the account secret,\nand the reset pages are gated by a single-use token in the URL that their\nown API route validates. The middleware was a lock on the outside of a\nfire exit.\n\nDeclared as one list rather than as inline negations, because the inline\nform is exactly what was outgrown: three pages were added over time and\nnobody thought to edit a boolean expression in another file. Matching is\non whole segments no",
      "refs": {
        "commit": "0f6b25ad10a8cd9ae24383a189e135a46b96b853"
      },
      "digest": "a842fa6ebf9ddb50112436dda23876a3fb2f2005c13ddd6449197e330ea1a6bd"
    },
    {
      "id": "ship/claimyour.gold/033c20c8c2b4",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-04T17:24:43Z",
      "kind": "other",
      "title": "Re-vendor the directory checker for dependsOn",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-04",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "directory/1 gained an edge type: one published artifact requiring\nanother to run. Not folded into `cites`, which the vocabulary has always\ndocumented as being for sources — a dependency is a hard requirement a\npackage manager enforces, and giving one edge type two meanings is the\nfailure this vocabulary has recorded twice already.\n\nThis copy is byte-identical to packages/directory/vendor-check-directory.mjs\nin flashyos. Changing the source there does nothing here until the copy\nis replaced, and a stale copy does not fail — it disagrees, silently,\nabout exactly the field somebody has just changed.\n\nKind: chore\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "033c20c8c2b4465abf5c3f2a378f658e6f5f059f"
      },
      "digest": "5aed66c70e33fd5f5bfbb3f397615715b3f1fbd1124c650c6b9a2ebc64b7e96d"
    },
    {
      "id": "ship/claimyour.gold/8cfae7b34e66",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-03T03:13:46Z",
      "kind": "docs",
      "title": "Correct a note describing a blocker that cleared",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-03",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "arenaGate.ts explains why this file names @flashylabs/flashyid-sdk when\nthe kernel's real identity is @flashyid/sdk — GitHub Packages only\naccepts a scope matching the repository owner, so the publish job renames\nit on the runner. That reasoning is still right and the paragraph stays.\n\nIts last clause was not. It read \"one line changes here the day\n@flashyid/sdk publishes to public npm — publish-sdk.yml, waiting only on\nNPM_TOKEN.\" Measured 2026-09-03: @flashyid/sdk@0.1.1 is on the public\nregistry, the same version this file installs through the mirror. The\nblocker cleared and nothing said so, because a comment describing a wait\nhas no way to notice the wait ended — it reads exactly the same on the\nday it becomes false, which is a worse failure than being wrong from the\nstart.\n\nThe migration itself is deliberately not folded in. Swapping the\nspecifier means a lockfile change, an .npmrc scope other dependencies\nhere still need, and a jest resolution path this file documents having\nbeen bitten by once — real work on a live rewards product, which does not\nbelong inside a comment correction.\n\nKind: docs\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "8cfae7b34e66a3c62c12155ca52aa84de15531de"
      },
      "digest": "f536e1801dc26444057afae186840cc361ff72132c3567d1e2edbd3c1840181c"
    },
    {
      "id": "ship/claimyour.gold/a0857c7116d1",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-02T16:22:11Z",
      "kind": "other",
      "title": "Re-vendor: the ship log learns ritual/1 before its first commit",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-02",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`vendor-shiplog.mjs` gained `ritual/1: observe the office` in\nBOOKKEEPING_SUBJECTS upstream, so every copy in this estate disagreed with\ncanon about whether that workflow's refresh commits are work. A stale\nvendored copy does not fail — it disagrees, silently, about exactly the\nfield somebody has just changed, and the last three entries on that list\nwere each added only after their commits had already sealed as work under\nagent/unattributed.\n\nReplaced by `node tools/estate-revendor.mjs --write` in flashyos, which\ncompares every copy byte-for-byte against the default branch rather than\nagainst whatever is checked out.\n\nKind: chore\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "a0857c7116d1537f0f64ba74c7740762f58d26a9"
      },
      "digest": "872cb97d3e10a6f23026809edcf3f10e46a492110ead4f3b45198e5fe6e8007d"
    },
    {
      "id": "ship/claimyour.gold/f0107da26853",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-02T16:13:31Z",
      "kind": "feature",
      "title": "deploy/1: declare where this repository is hosted",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-02",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Root directory, production branch, framework and registrar, in a file a\nmachine can check instead of in two settings panels nobody can read from a\ncheckout.\n\nThe estate spent an afternoon on 2026-09-02 answering \"which domains are\nhosted and what does each one still need\". Every fact it produced already\nexisted — in a Vercel panel, a GoDaddy zone, and somebody memory — and none\nof it was anywhere a check could reach. Fourteen estate domains were\nresolving to a parking page with finished sites committed behind them.\n\nThe checker is dependency-free and runs before an install. Two of its rules\nare ones nothing else here makes: a root directory that does not exist in\nthe tree is refused, because a hosting project pointed at a typo builds\nnothing and reports success; and a production branch is refused if it does\nnot exist on origin, or if it differs from the default with no written\nreason — an accidental divergence and a deliberate one look identical from\ninside a panel.\n\nIt carries no credentials, no account or project identifiers, and no DNS\nrecord values. The first because the value of this file is that the\nrepository can be handed to somebody else; the last because those belong to\nthe host and they move — Vercel went from 76.76.21.21 to 216.198.79.1, and a\ncopy of that in thirty repositories is thirty copies to update.\n\nEvery value here was measured, not remembered.\n\nKind: feature\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "f0107da26853f05c0cd685baca30d5cd6541f311"
      },
      "digest": "6e21fb889187d1561f97f0cf67c8fe1027fb12e3672d62b7185d7ac060f042ac"
    },
    {
      "id": "ship/claimyour.gold/3ee2259647af",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-02T12:35:31Z",
      "kind": "fix",
      "title": "Stop a list of API names from proposing to destroy production",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-02",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The production deploy has been blocked since 31 August by the\ndestructive-change gate. The gate was right, and it was also reporting\nabout a third of what the plan actually said.\n\n  BLOCKED: plan destroys/replaces stateful resource(s):\n    - google_redis_instance.flashy (delete+create)\n\nPlan: 2 to add, 3 to change, 18 to destroy. Alongside replacing the\nproduction Redis it proposed deleting five live credentials with their\nIAM bindings and versions — FLASHYID_COOKIE_KEYS, FLASHYID_MONGODB_URI,\nFLASHYID_REDIS_URL, FLASHYID_SIGNING_JWK, IDENTITY_MONGODB_URI_READONLY\n— and said nothing about them, because google_secret_manager_secret was\nnot in the gate's list of stateful types. Fixing the Redis diff alone\nwould have applied all eighteen deletions unremarked.\n\nTwo independent faults, neither of which looked like what it did.\n\nThe Redis replacement came from a list of API names. cloudscheduler was\nenabled on the project and in state but absent from local.apis, so every\nplan proposed removing it; that pending change on google_project_service\nmade Terraform defer module.networking's data source, which it\ndepends_on, to apply time; network_id became (known after apply);\nauthorized_network read as changed; and authorized_network forces\nreplacement. Every line of that plan was correct.\n\nThe secret deletions came from a bucket object. The secret name list is\nthe union of names declared in code and the keys of secrets.json in GCS,\nand those five were in Secret Manager and in state but not in the JSON.\nNothing records who removed them or when, which is the real finding: the\nname list for production credentials was living somewhere with no\nhistory and no review.\n\n  - cloudscheduler.googleapis.com goes back in local.apis, which is the\n    minimal fix and unblocks the deploy on its own;\n  - the networking module computes the network id from the project id\n    instead of reading it back. The value is byte-identical to what the\n    data source returned and it can never be unknown, s",
      "refs": {
        "commit": "3ee2259647af0c49047b78d6727f71abf89e3344"
      },
      "digest": "0c09e0440a838bdf41f54f5da36519d60b6e2d36941f51f73953089008d389f3"
    },
    {
      "id": "ship/claimyour.gold/250b9a0efb4c",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T23:32:49Z",
      "kind": "other",
      "title": "Two people, one partner account, two passwords",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-02",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Nolan and Derek are both at Matrix and both need the dashboard. Until now\na partner tenant was one Client row with one email and one password, so\nthe only way to give them both access was to hand them the same\ncredential — which neither of them could then change without locking the\nother out. That is the thing this removes.\n\nEveryone who needs access to a tenant now gets a ClientUser row: their\nown address, their own password, their own sessions. The Client row keeps\nthe tenant's original registered address; a member is invited by an owner\nfrom /client/settings, and the Password card that already existed serves\nboth, because the route reads the session to decide whose row to write\nand both paths share one rotate() so there is a single answer to what\nchanging a password verifies.\n\nsessionVersion is the load-bearing part. A JWT carries the version of the\nrow that minted it, so requireClientSession now checks a member's token\nagainst the member's row. Checking it against the tenant's counter fails\nin both directions at once: a member's password change would stop signing\nout their own other sessions, and the tenant changing theirs would sign\nout every member on the account. Both directions are pinned in\ntests/lib/clientSessionScope.test.ts, and both were confirmed by removing\nthe guard and watching them fail.\n\nAccepting an invite is the reset-password path, deliberately. An invite\ncarries a reset token to the same page, and setting the first password\nflips INVITED -> ACTIVE. One place in the product turns a token into a\npassword; a separate accept-invite endpoint would repeat every check here\nand drift from it. The invite link lives 7 days rather than an hour —\na reset answers something the recipient just did, an invite waits in an\ninbox over a weekend.\n\nNothing here ever sets or prints a password. Removing access disables the\nrow and bumps sessionVersion so a live session dies on its next request\nrather than at token expiry; a DISABLED member cannot sign in, cannot\nacc",
      "refs": {
        "commit": "250b9a0efb4cdbbd345b7cb039bb62e082595a07"
      },
      "digest": "fb0121f6655bed1571f5edf6acc908f58cd469edfbcc4d7cae0c063a9293e1c5"
    },
    {
      "id": "ship/claimyour.gold/62bff0b36fb9",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T23:17:18Z",
      "kind": "infra",
      "title": "Move a partner account without ever handling their password",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-02",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "An operator with database access can now do what /super/clients does —\nchange a partner tenant's sign-in address and send a reset link — from a\nshell, which matters while that screen is on main and production is not.\n\nReport-only unless --write. It lowercases and trims the new address,\nbecause login and the forgot-password lookup both match the stored\nstring, so an account stored as `Nolan@Matrix.fun` is one nobody can\nreset from `nolan@matrix.fun`. It refuses an address another account\nholds. It bumps sessionVersion, because an email change is an identity\nchange and the old address's sessions should end with it.\n\nIt never sets a password and never prints one; the partner receives a\nreset link and chooses their own. scripts/bootstrap.ts prints a\nhard-coded password to stdout, which puts a live credential in terminal\nhistory, CI logs and screenshots. This is the version that does not.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "62bff0b36fb905e902c25fe96daf0e0aac058b75"
      },
      "digest": "9168d3173fe1270db3383a1f57d8f062f4a411406794b9bbc710e365c72042e0"
    },
    {
      "id": "ship/claimyour.gold/d4259f368457",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T21:08:55Z",
      "kind": "feature",
      "title": "Tell the estate the moment this repository pushes a record",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "graph.yml in flashyos merges every property's fragment on a daily\nschedule, so without a dispatch a change here is invisible to the estate\nfor up to 24 hours — and \"the graph is a day behind\" is\nindistinguishable from \"this property has nothing new to say\".\n\nThe dispatch has been in the shiplog/backlog template since August and\nin no repository, because each vendored its workflow before the template\nhad it. This adds it, gated on the commit step having actually pushed: a\ndispatch per run rather than per change would turn one daily merge into\na merge per push across thirty repositories.\n\nThe commit step is replaced with one canonical form rather than patched,\nbecause the estate had two vintages of it — some repositories carry a\nfive-attempt push retry the template lacked, and re-emitting would have\ndeleted it. Both halves are here now.\n\nThe retry resolves the branch per run instead of resetting to a literal\norigin/main. Eleven repositories in this estate have an agent branch as\ntheir default, and there a rejected push would reset the checkout to a\ndifferent branch and push that over the deploy branch.\n\nUnset ESTATE_DISPATCH_TOKEN means a delay of up to 24 hours, never a\nloss — the daily merge is the floor, and the step says so loudly rather\nthan skipping green.\n\nKind: feature\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01FDosmV9fXV6oZ9NXe7PZ76",
      "refs": {
        "commit": "d4259f368457c04c0bb94fe321da65de795b99c5"
      },
      "digest": "0e61dd906f23808fdcb92f4fa7dfe49a93591c80321bf6ec81afc27ec4113aa2"
    },
    {
      "id": "ship/claimyour.gold/e22d23388256",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T19:20:36Z",
      "kind": "feature",
      "title": "Merge origin/main: regenerate the backlog fragment past a bookkeeping refresh",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Both sides are emitter output; the resolution is a fresh emit, not a pick.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NfXZ2PAsNCENGJupuCQrnH",
      "refs": {
        "commit": "e22d23388256966dac629c082d3f4b299dd72d3e"
      },
      "digest": "9d583393f2c5b544a5adbf0c771330fe68f1f2ab8ac216a84fe9353ac3993ce0"
    },
    {
      "id": "ship/claimyour.gold/7e0aeb1ee856",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T19:19:47Z",
      "kind": "feature",
      "title": "Serve the backlog projection at /.well-known/intent.json too",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "intent/1 is backlog/1's successor name and its readers accept the legacy\nversion key permanently, so the cost is one more entry in the serve list:\nthe emitter writes the same public projection to both paths from one emit,\nand no copy step exists to forget. Validated by the intentmesh checker as\nwell as the vendored one.\n\nKind: feat\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NfXZ2PAsNCENGJupuCQrnH",
      "refs": {
        "commit": "7e0aeb1ee8565d41168a2c6336048e56e72c251d"
      },
      "digest": "ff9788804223ac56a8048842f99f604ee22d4649eb8d84dfc65dc938867bff3a"
    },
    {
      "id": "ship/claimyour.gold/c7918acd551e",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T19:12:55Z",
      "kind": "feature",
      "title": "Activate: the Mesh Concierge on claimyour.gold",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Three of the Activation standard's four artifacts. `/concierge.js` is the\nbuilt bundle of @magician/concierge vendored byte-identical; the root\nlayout includes it once with this property's accent and the charter's own\nnamed human. `/concierge` carries the slot, and reads the portal session\nthe way `/contact` does — a door that tells somebody they are logged out\nwhen they are not is a small lie on the page asking them to trust us with\na sentence.\n\nThe page says what it is not, twice, because on a rewards property that\nis the part somebody misreads: it is not support, and it grants no Flashy\nGold. Anyone with a question about a hunt, a streak or a redemption is\nsent to /contact, which routes it to people who can actually answer.\n\n**This is the one property I could not compile or test here.** `npm ci`\nfails with a 401 against npm.pkg.github.com for `@flashylabs/ledger` —\nGitHub Packages needs a token this session does not have — so there is no\nnode_modules, no `tsc --noEmit` and no jest run behind this commit. What\nwas verified instead, and it is less: both changed .tsx files parse\nthrough esbuild; every assertion in the new jest test was executed\ndirectly in node and passes (the served bundle is byte-identical to\ncanon, makes no network call, keeps no storage; the include appears once;\nthe contact equals the charter's accountableTo; the accent is a\nmeasurable hex; the page carries the slot and promises no rewards); and\n`verifyPortalSessionToken` returns `displayName?: string` and\n`photoUrl?: string | null`, which is exactly what /contact already hands\nGlobalHeader.\n\nSay so rather than let a green-looking commit imply a run that did not\nhappen. CI on main is the first thing that actually typechecks this, and\nmain deploys to dev — the production promotion is a separate manual merge\nand should wait for that run.\n\nKind: feature\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "c7918acd551e542dc1b917a6f223bc94ed0e183e"
      },
      "digest": "ce5d15c3cc2936f205fb2751e25dc5b8a2ce38d30ffb7dcfb640c35a4b57818d"
    },
    {
      "id": "ship/claimyour.gold/f6f6d2696534",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T17:58:19Z",
      "kind": "other",
      "title": "Re-vendor shiplog: the filter learns directory/1, delivery/1 and intent/1",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Three formats gained a workflow that commits a refresh. Without this the\nfirst run of each seals as work under agent/unattributed, inflating the\ntwo numbers the record exists to make honest.\n\nA vendored change does nothing until the copy is replaced, and a stale\ncopy does not fail — it disagrees, silently, about exactly the field\nsomebody has just changed.\n\nKind: chore",
      "refs": {
        "commit": "f6f6d2696534b9011b9ba0bb63a525cfb60ffa5e"
      },
      "digest": "77e5969de6a7b160f3392ce5c409c1b7ea16acfd6a3c14e70a833d142df99ca6"
    },
    {
      "id": "ship/claimyour.gold/aac95e2d40ab",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T17:56:03Z",
      "kind": "feature",
      "title": "Take ten minor versions of the mesh SDK",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "This property pinned @flashyos/agent at ^0.6.0, and npm's caret on a 0.x\nversion pins the minor — that range is >=0.6.0 <0.7.0, not \"0.6 and\nlater\". The package is published at 0.16.1, so ten minor versions had\nshipped and this property had taken none of them, silently: an\nunsatisfiable-looking range does not fail, it just installs the newest\nversion that matches.\n\nThe delta is purely additive. Nothing removed, an identical constructor,\nand sixteen methods added: proposeInitiative, joinInitiative, offer,\ndeclareCapabilities, discover, discoverRoadmaps, publishRoadmapItem,\nengageRoadmap, resolveInitiative, broadcast, claimTask, completeTask,\ndecide, declareFromCharter, watch and work.\n\nThose are every call by which an initiative comes to exist or a want\ngets declared, which is why the network has three initiatives in total.\n\nVerified on a real build rather than by reading the changelog.\nflashyos/tools/estate-sdk-range.mjs is the gate that measures this across\nevery repository, and it now runs in `npm run estate`.\n\nKind: chore",
      "refs": {
        "commit": "aac95e2d40abf5f4c9a81ebb7ce23de1512a3b4a"
      },
      "digest": "78adc5468a1971d49211cfdc58fea0e861092b75909b57e221ab9e6334218395"
    },
    {
      "id": "ship/claimyour.gold/9101997314ff",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T17:41:50Z",
      "kind": "fix",
      "title": "Name this repository's mesh credentials after this repository's org",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The campaign worker reports under claimyour-gold and read its\ncredentials from FLASHYGOLD_ORG_ID and FLASHYGOLD_AGENT_TOKEN — named\nfor flashygoldams, what this product was called before the rename.\n\nThat name belongs to nobody now and reads as somebody else's.\nflashy.gold is a separate property with a separate mesh org\n(flashy-gold, org #11) whose credentials are FLASHY_GOLD_*. Someone\nsetting FLASHYGOLD_AGENT_TOKEN on the obvious Vercel project puts a live\ncredential on the wrong property, and neither side complains.\n\nReads CLAIMYOUR_GOLD_* now, falling back to the old name with a warning.\nThe fallback is deliberate: a rename has two halves and only the code\nhalf lands in a commit. ACTION REQUIRED — add CLAIMYOUR_GOLD_ORG_ID and\nCLAIMYOUR_GOLD_AGENT_TOKEN to this project's Vercel environment; the old\nnames keep working until then and log on every boot.\n\nWritten inline rather than importing meshEnv from @flashyos/agent,\nbecause this repository pins ^0.6.0 and the helper is in 0.16.1. The\nnaming rule is enforced from outside by tools/mesh-env.test.mjs in\nflashyos, which checks names and not which code reads them.\n\nAlso: NEXT_PUBLIC_FLASHYOS_ORG_SLUG defaulted to flashygoldams, and\n/api/v1/public/orgs/flashygoldams returns 404 today. The live org is\nclaimyour-gold. A badge whose slug does not resolve renders nothing and\nreports no error, so that default was wrong for as long as any\ndeployment relied on it.\n\nKind: fix",
      "refs": {
        "commit": "9101997314ff5a89a7aee6477c60baa9fc865d58"
      },
      "digest": "521da5d9a16e6b5c355686b98d5793092047e4b4ba3f60da83517ed2ffa952e9"
    },
    {
      "id": "ship/claimyour.gold/9da600fcbc7c",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T17:33:42Z",
      "kind": "feature",
      "title": "Let partners change their own password, and operators hand accounts over",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-02",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "An audit of the partner auth surface found three things missing, all of which\nhad the same consequence: a partner's password, once set, was effectively\npermanent.\n\n  1. There was NO authenticated change-password anywhere in the product. A\n     partner who wanted to rotate a credential they already knew had to\n     pretend to have lost it and go through the forgot-password email.\n     /client/settings now has a Password card. It requires the current\n     password — a session cookie alone must not replace a credential, or an\n     unattended laptop can lock the owner out — enforces the same strength\n     rule as registration and reset, and increments sessionVersion so every\n     other session that partner has open is signed out. Rate-limited on the\n     auth bucket, because it verifies a password.\n\n  2. There was NO way for an operator to change a partner's email or reset\n     their password. The route named reset-partner-password acts on the\n     Partner model, which is a different thing from the Client model behind\n     the partner dashboard — reaching for it does nothing to the account\n     someone is locked out of. /super/clients gains Change email and Send\n     reset link. Neither sets a password or reveals one: the partner receives\n     a link and chooses their own. The email change signs out sessions on the\n     old address and is audit-logged with the operator's name.\n\n  3. Forgot-password matched the stored email case-sensitively while nothing\n     normalised it on write, so an account created as Nolan@Matrix.fun could\n     never be reset from nolan@matrix.fun — the request found nothing and, by\n     design, said nothing. The lookup now tries the normalised form too, and\n     changeClientEmail stores lowercase.\n\ndocs/partner-accounts.md records how this works, that a tenant has exactly one\nlogin and what the options are when a partner names two people, and an honest\nlist of what is still weak — plaintext reset tokens, createClientByAdmin\nemailing a password, n",
      "refs": {
        "commit": "9da600fcbc7ccf9659dfbe84a241d6015092bc30"
      },
      "digest": "aee93aef4da6668b7b880fdda092ea28a850f5edeee17c533642faffc98f70f8"
    },
    {
      "id": "ship/claimyour.gold/1732bb3add72",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T14:53:44Z",
      "kind": "feature",
      "title": "Give this repository's directory fragment a machine that refreshes it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "shipped/1 and backlog/1 each ship a workflow with their adoption, so\nevery repository filing one has something re-running the emitter.\ndirectory/1 never did — sixteen repositories in this estate got the\nfragment and nothing else, and were still serving the bytes one\nhand-sweep produced on 2026-08-31.\n\nNothing was red, and nothing would have gone red. A fragment nobody\nre-emits does not decay for a year; it stops being true. A machine\nsurface added here never enters the graph, the asserted date freezes,\nand a change to the vendored emitter reaches a copy that never runs it.\n\nThe workflow is generated by workflow() in @flashyos/directory rather\nthan hand-written, gates on the default branch resolved per run, and\ncommits with [skip ci] because a refresh is a record of what already\nhappened.\n\nvendor-shiplog.mjs is re-vendored in the same commit: its bookkeeping\nfilter had never heard of \"directory/1: refresh the fragment\", so the\nfirst refresh would have sealed as work under agent/unattributed.\n\nKind: feature",
      "refs": {
        "commit": "1732bb3add722d9446514215f4779065836444dc"
      },
      "digest": "0d10d1a32c2c9e46a2d3f89a8354e3894a7de0863df9ed8a4bedfbacf1816bd2"
    },
    {
      "id": "ship/claimyour.gold/8580c1204808",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T14:33:31Z",
      "kind": "fix",
      "title": "Re-vendor check-directory.mjs: enforce what every edge type must carry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The vendored checker had hand-written blocks for three of the sixteen edge\ntypes and nothing for the other thirteen, so engaged without a basis,\ndelegatedTo without a scope and issued without a date all validated clean —\nin thirty identical copies that agreed with each other perfectly.\n\nIt reads a requires table now, mirroring EDGE_REQUIRES in\n@flashyos/directory, with one conditional: `declares` needs a role when it\nnames an agent and not when it names a machine surface. That split was\nmeasured, not decided — across the estate all 88 agent declarations carry a\nrole and none of the 43 surface declarations do.\n\nflashyos/tools/vendored-directory.test.mjs differentials this copy against\nthe package by verdict, and asserts every estate copy is byte-identical to\nit. This repository's fragment passes the stricter checker unchanged.\n\nKind: fix",
      "refs": {
        "commit": "8580c12048089734ed5a49810d781c7ee3f02c6f"
      },
      "digest": "f3f27cb56aa895ae7c80008af9e660ac583e9652044745f34adf4f35088a7640"
    },
    {
      "id": "ship/claimyour.gold/92fda353d526",
      "repo": "repo/claimyour.gold",
      "at": "2026-09-01T03:41:02Z",
      "kind": "docs",
      "title": "Document the shard, and deploy it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "This property's bolt/1 shard went in on a commit marked [vercel skip], so the\nsite never rebuilt and the egg is in git and not on the domain. That marker is\nright for the emitters — their refresh commits were 321 of the estate's 594 in\none day against a 100/day build limit — and wrong for a commit that changes\nwhat the site renders. Written down here so the next person does not repeat it.\n\nKind: docs",
      "refs": {
        "commit": "92fda353d52611f7c16f7dcecedd31b1372c2bea"
      },
      "digest": "f66b7ce37144bd0b4eaa23fdb5b348f3f90c3bbc884dcee50a4669065eb88431"
    },
    {
      "id": "ship/claimyour.gold/9ae4fc920908",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T20:53:54Z",
      "kind": "infra",
      "title": "Hold the attribution line: freeze what sealed, refuse what would seal next",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The bookkeeping-filter window let emitter refresh commits seal as shipped\nentries under agent/unattributed. The fixed vendor-shiplog.mjs is already\non this branch; this adds the test that makes the line hold — the sealed\nentries are frozen by id (sealed is final under append-only) and any new\nunattributed entry fails the suite.\n\nKind: test\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NfXZ2PAsNCENGJupuCQrnH",
      "refs": {
        "commit": "9ae4fc9209083716151600b8d0d7412350ae5f03"
      },
      "digest": "6824aaf103f01c39eea0517a69faee37cfcb65f24b4921041e2e1610cab53f9b"
    },
    {
      "id": "ship/claimyour.gold/72996636f544",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T19:38:19Z",
      "kind": "fix",
      "title": "Re-vendor the shiplog emitter: the bookkeeping filter learned its suffixes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The emitted refresh subjects grew \", and the checkpoint over it\" and\n\"[skip ci]\", and the exact-match anchor in the old copy missed both — so\nevery refresh commit sealed as a shipped entry under agent/unattributed.\ngda-group sealed six before the fix landed. Byte-identical with\npackages/shiplog/vendor-shiplog.mjs in flashyos as of its fix.\n\nKind: fix\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NfXZ2PAsNCENGJupuCQrnH",
      "refs": {
        "commit": "72996636f544222eb1ad63cfacaf22f7d9ec51e7"
      },
      "digest": "e67ec510dfd2c635939d7b353e18873737be069af0bab626f257840552da49d4"
    },
    {
      "id": "ship/claimyour.gold/871bd4bad819",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T19:29:46Z",
      "kind": "infra",
      "title": "backlog/1: refresh the fragment [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "871bd4bad8193872540130aa7bb9e63e16161ee7"
      },
      "digest": "ed71e6e89aed85a1fe808ab60ef2395b31a46fa38b26b4ab7e2ed7124817cd23"
    },
    {
      "id": "ship/claimyour.gold/032693538017",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T19:29:31Z",
      "kind": "fix",
      "title": "The auto_merge lane starts the deploy it promises",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A push made with the workflow's own GITHUB_TOKEN never fires on-push\nworkflows — GitHub's recursion guard — so the summary line 'Deploy prod fires\non this push' was false in exactly the lane whose job is shipping. Discovered\nlive: the 71-commit promotion merged into production at 16:34 and the branch\nsat undeployed until a person dispatched Deploy prod by hand an hour later. A\npromotion that quietly does not deploy is the original failure this workflow\nwas written to end, moved one step downstream.\n\nThe lane now dispatches deploy-prod.yml on production explicitly after the\npush, with the actions: write grant that requires and a comment saying why —\nso the next reader does not delete the 'redundant' dispatch and reintroduce\nthe gap.\n\nKind: fix\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ac/code/session_01NfXZ2PAsNCENGJupuCQrnH",
      "refs": {
        "commit": "032693538017cf89e272fde2ced2f443fff6ff6d"
      },
      "digest": "7f6d6be8cff7209f5d12c9ce33245d303c811e923f3f5073cd3b3e38cd3b8cdd"
    },
    {
      "id": "ship/claimyour.gold/c6656a8b1872",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:13:02Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "c6656a8b1872c9d8d9b93357fedea04d8fd9423b"
      },
      "digest": "aab20cc27c37c2db248f9c9e0c93972bc344b8312951234d9728dcf33f0f5dd5"
    },
    {
      "id": "ship/claimyour.gold/88cac1488a22",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:12:54Z",
      "kind": "infra",
      "title": "backlog/1: refresh the fragment [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "88cac1488a229f66ed49a41db000b588be3bf7f9"
      },
      "digest": "dbdac02cc161331a3cda72d82c6f30c6b5b1c5bb243bef9ffc427e7c3137e98f"
    },
    {
      "id": "ship/claimyour.gold/d3db809b989f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:07:52Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "d3db809b989fb662435b1d1f530d608a7e75c0d5"
      },
      "digest": "4756a543e2a5663ef26a4a69a2e72b9bd54be221b6f4037236c410cba71fa0c8"
    },
    {
      "id": "ship/claimyour.gold/3e3ac97e4008",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:07:44Z",
      "kind": "infra",
      "title": "backlog/1: refresh the fragment [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "3e3ac97e4008cb700ecc149b101e622ad11497b1"
      },
      "digest": "00007cb59e8f3af8cfe12bbf504e4a4d5a6432c7b0ad82683209e874c88448c2"
    },
    {
      "id": "ship/claimyour.gold/1066cfae2c65",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:07:04Z",
      "kind": "fix",
      "title": "Stop serving a bootstrap token and an admin password at a well-known URL",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "/.well-known/shiplog.json carried entry 82546943a95a among 746 public\nentries. The entry explains the removal of the /api/v1/admin/bootstrap\nbackdoor and, in explaining it, quotes the hardcoded token and the admin\npassword verbatim — an exploitation route with a map, at a URL published for\nmachines to read.\n\nHeld rather than deleted: the entry stays in this repository's own fragment,\nsealed, digest intact, counted. Only the public projection changes, 750 of 752\nnow. That needed the emitter fix in flashyos — `visibility` is inside the\ndigest, so a hold added after sealing did nothing until the projection learned\nto honour it — and this file is the re-vendored copy carrying that fix.\n\nHOLDING IS NOT REMEDIATION. Both values are in this repository's git history\nand in the commit message that removed them. They stay burned until they are\nrotated in production. That is an operational act, not a code change.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EEAAmijDh3kzFH7SY53jZ7",
      "refs": {
        "commit": "1066cfae2c6513d295a9206b1003a09294069e94"
      },
      "digest": "5dbca121eb63dc9a435be4a612064c691c2620322230762717906c5f03a7b271"
    },
    {
      "id": "ship/claimyour.gold/b0d487af0a03",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:07:04+00:00",
      "kind": "fix",
      "title": "Stop serving a bootstrap token and an admin password at a well-known URL",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "/.well-known/shiplog.json carried entry 82546943a95a among 746 public\nentries. The entry explains the removal of the /api/v1/admin/bootstrap\nbackdoor and, in explaining it, quotes the hardcoded token and the admin\npassword verbatim — an exploitation route with a map, at a URL published for\nmachines to read.\n\nHeld rather than deleted: the entry stays in this repository's own fragment,\nsealed, digest intact, counted. Only the public projection changes, 750 of 752\nnow. That needed the emitter fix in flashyos — `visibility` is inside the\ndigest, so a hold added after sealing did nothing until the projection learned\nto honour it — and this file is the re-vendored copy carrying that fix.\n\nHOLDING IS NOT REMEDIATION. Both values are in this repository's git history\nand in the commit message that removed them. They stay burned until they are\nrotated in production. That is an operational act, not a code change.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EEAAmijDh3kzFH7SY53jZ7",
      "refs": {
        "commit": "b0d487af0a035586e194b3d8762f027edcf056fc"
      },
      "digest": "9b478266a2cc4766fb8af9a3cbe04ae713c879cb72ab899db96e6dd7f3d3f318"
    },
    {
      "id": "ship/claimyour.gold/61a6c763adc9",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:00:37+00:00",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "61a6c763adc95830c8d3b0256c04b1f9020b1a60"
      },
      "digest": "e433f4349685502d17932d88a55660e9f10b29b0678e7840a276c5a5ea384dec"
    },
    {
      "id": "ship/claimyour.gold/e081b78e6ce7",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:00:25+00:00",
      "kind": "infra",
      "title": "backlog/1: refresh the fragment [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "e081b78e6ce758dac92654c8fe9599ebc82fc65f"
      },
      "digest": "baea1a8104b19cc398ff5f3b213d510fcc4c85f4e0446b58464862d45c23e616"
    },
    {
      "id": "ship/claimyour.gold/ae9ce92dd213",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:00:13+00:00",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "ae9ce92dd2133706e6fc3454717d67fefa985319"
      },
      "digest": "2fa623e7823e934c4bec6b1da8dd8047e4acaa03c747852c902538eda3c79c45"
    },
    {
      "id": "ship/claimyour.gold/456656a59386",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T18:00:07+00:00",
      "kind": "infra",
      "title": "backlog/1: refresh the fragment [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "456656a5938696dd322f1ed0fb118842c170085d"
      },
      "digest": "b8fe661a648af79a91bf1224dfaf4612909ff96d2b99275cd7edda8db0234ee0"
    },
    {
      "id": "ship/claimyour.gold/afcde1cad93a",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T17:53:17+00:00",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "afcde1cad93a49ed87771578eabb48e821fea83c"
      },
      "digest": "8e82c2a0ac8bf2ce10ed2529d09299e48789648b0c04bfec2722e35fb9d671ba"
    },
    {
      "id": "ship/claimyour.gold/03f49808bd5a",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T17:53:10+00:00",
      "kind": "infra",
      "title": "backlog/1: refresh the fragment [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "03f49808bd5a1304bc0bbd90d9893c9488770294"
      },
      "digest": "03a1e2347747522543fe3a82537c184e792c3e4c0c5b0d6568a9eb7491ffb14b"
    },
    {
      "id": "ship/claimyour.gold/f611a78f1e9b",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T17:52:49+00:00",
      "kind": "fix",
      "title": "Hold the family strip to the estate's computed ring — and mark Flashy Network LIVE",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "flashyos.com publishes syndicate/1 at /estate-feed.json; its properties block\ncomputes a ring per property — for claimyour.gold, the three hubs plus its\nproducts cluster-mates. FLASHY_ECOSYSTEM is a different, larger statement on\npurpose: the strip names every sibling including what is coming, the computed\nring carries the relevant five. What must not happen is the two drifting about\nthe five they share, or a computed neighbour sitting below LIVE — which\nquietly keeps it out of the footer while the estate says the link should\nexist.\n\nThat exact drift shipped here. flashynetwork.com has served its homepage,\nexplorer, checkpoint and well-known surfaces for weeks, and this list said\nBUILD, so the footer never linked it and nothing could say so. It reads LIVE\nnow, verified against the live domain on 2026-08-31, and computed-link-not-live\nis a finding from here on.\n\nThe comparison lives twice on purpose, in the shape scripts/directory.mjs\nalready set: src/lib/estateFeedCheck.ts is the typed form the jest suite\nexercises, and scripts/estate-feed-check.mjs inlines it dependency-free so the\nlive half runs with bare node against claimyourgold.json and the feed. An\ninlined copy does not break when it drifts — it disagrees, silently — so the\nsuite runs both implementations over the same fixtures via --fixtures and\nfails on any disagreement about the verdict.\n\nVerified rather than assumed: @flashylabs/ledger installs from GitHub Packages\nand needs a token this environment does not have, so jest cannot run here —\nthe library was compiled in isolation under strict tsc and the differential\nexecuted with bare node: five fixtures, identical verdicts from both\nimplementations, healthy clean.\n\nKind: fix\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NfXZ2PAsNCENGJupuCQrnH",
      "refs": {
        "commit": "f611a78f1e9bff5e5f13c70b20aaec78dd588b80"
      },
      "digest": "2b48800f21c43a246d9c17e450ea1072f194e4951679e227f3796871146f5197"
    },
    {
      "id": "ship/claimyour.gold/792d4898916a",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T17:20:15+00:00",
      "kind": "other",
      "title": "Derived-log workflows survive a moving main; the served fragment matches the record",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Ports the regenerate-on-the-new-tip push retry from flashyos (whose\nshiplog lost the race three runs straight), and re-syncs the served\npublic/directory.fragment.json with the committed record — the diff the\nDirectory workflow refuses. All directory checks run locally green\nbefore this commit.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "792d4898916a8f48fe62522ef09fc79d139f713d"
      },
      "digest": "6cb0be8c3958b2366df23172c4f741be225a033f8a2f727e058df02df7aa7dd6"
    },
    {
      "id": "ship/claimyour.gold/80ffbf2ac37e",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T16:48:22+00:00",
      "kind": "fix",
      "title": "Give a person the door, and make the two handshakes agree about it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A live survey of the estate on 2026-08-31 — fetched over the network rather\nthan read from git — found the machine door at six of seven properties and the\nhuman door at nought of eight. Every property advertised a `join` an agent\ncould follow and offered a person nothing to click. The footer here now\ncarries it, beside the badge that already says this org is on the mesh and\nuntil now left a reader no way to get on it themselves.\n\nThe same look found something worse here: two handshakes at one path,\ndisagreeing. `public/.well-known/flashyos.json` is what the live domain\nanswers with and says `flashyos.com/join`;\n`src/app/.well-known/flashyos.json/route.ts` sits unreachable behind it and\nsaid `app.flashyos.com/onboard` — the dashboard's account flow, for somebody\nwho already decided, rather than the open page that publishes the ladder\nfirst. Precedence between a public file and a route handler is not a thing to\nbet a door on, so both now read one constant.\n\nOne path with two implementations is still a defect and is deliberately not\nresolved here: which one survives is a decision, and the route handler is the\nbetter engineering (it derives capabilities from the charter) while the static\nfile is the one that actually ships. Choosing between them changes what a\ndomain serves and wants a deploy somebody is watching.\n\nThe test could not be run in this environment: `npm ci` needs a GitHub\nPackages token for @flashylabs/ledger that is not present here, so there are\nno node_modules and no jest. Every assertion in it was evaluated by hand\nagainst the same files and passes; CI is where it runs for real.\n\nKind: fix",
      "refs": {
        "commit": "80ffbf2ac37e481414aa7fa7e0088143008378e2"
      },
      "digest": "793deec979fdb0678ed9e2bdaf8dadccb7d88c69101213a87e7c9209dc5fa1a5"
    },
    {
      "id": "ship/claimyour.gold/37b87e8cc555",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T16:42:33+00:00",
      "kind": "fix",
      "title": "An emitted record must not spend a deploy [vercel skip]",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The emitters commit a refreshed fragment on every push, and each of those is a\ndeployment. On 2026-08-31 the estate landed 594 commits on default branches and\n321 of them — 54% — were emitters refreshing their own output. Vercel's build\nrate limit is 100 a day across the account, so the record-keeping machinery was\nconsuming the whole estate's deploy budget three times over and starving the\npushes people actually made.\n\nIt was invisible everywhere. Each property sat a few revisions behind, gda.group\nhad stopped on 30 August, nothing was red. The one place it was written down was\na commit status on a dependabot PR nobody had opened: \"Deployment rate limited —\nretry in 24 hours.\"\n\n[skip ci] is the marker Vercel and GitHub Actions both honour. The fragment\nstill reaches the domain on the next deploy a real push triggers, which is the\nright cadence for a record of something that already happened.\n\nThis commit carries [vercel skip] rather than [skip ci] so CI still validates\nit without spending one of the deploys it exists to save.\n\nKind: fix",
      "refs": {
        "commit": "37b87e8cc55590afe2403fa27320ba401ea70ff7"
      },
      "digest": "e8860bfbf8e48a37deb3ce85c9952069bb8b49c7ecba6afe4ef39c3cf5f9f9f3"
    },
    {
      "id": "ship/claimyour.gold/9b5ba93bc630",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T13:59:56-04:00",
      "kind": "feature",
      "title": "Merge pull request #73 from FlashyLabs/claude/gord-directory-spec-3jx7zk",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Verify the assertion before evaluating the chain, and get this branch green",
      "refs": {
        "commit": "9b5ba93bc630e3f5266b749a69789680bb9c758c",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/73"
      },
      "digest": "83e6075fe00f21e1f28f0d2079583d47287c8b35567aeaadf86bba223832589f"
    },
    {
      "id": "ship/claimyour.gold/dbad2c462e93",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T13:46:32+00:00",
      "kind": "fix",
      "title": "Give promotion a lane that does not depend on a setting nobody ticked",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The first real run worked exactly as designed until the last step: it measured\nthe gap, waited for green CI, wrote the body — and then GitHub refused with\n`GitHub Actions is not permitted to create or approve pull requests`. That is\na checkbox at Settings → Actions → General, and it is off.\n\nWhich makes the promotion mechanism itself an instance of the failure it was\nwritten to remove: a step that depends on somebody having remembered\nsomething. Two changes.\n\nThe refusal is now named. A GraphQL error reads as a broken workflow; the run\nsummary now says which setting, where it is, and that CI was green and the\nwork is waiting. It still fails, because a promotion that cannot happen should\nbe visible — but it fails with the remedy rather than with a stack trace.\n\nAnd `auto_merge` no longer goes through the pull request. Merging one needs\nthe same permission opening one does; pushing does not, and `contents: write`\nis already granted. It merges main into production locally and pushes, which\nis the identical result and depends on nothing anybody has to switch on. So\nthe promotion can ship today: Actions → Promote to production → Run workflow →\nauto_merge: true.\n\nStill a merge commit, never a squash. production carries 2,596 commits of the\noriginal line and main 300 of a rewritten one.\n\nKind: fix",
      "refs": {
        "commit": "dbad2c462e93da8d977952628b43e6121bd3e653"
      },
      "digest": "3a9414b5172887543b0bc42ee7252e8f2da6ce78e6e0088f8db15ec6822c6477"
    },
    {
      "id": "ship/claimyour.gold/b56ef3b28188",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T12:54:14+00:00",
      "kind": "infra",
      "title": "Automate the one step in the deploy pipeline nobody automated",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`main` auto-deploys to dev. `production` auto-deploys to prod. Between them\nsits a merge that nothing performs and nothing reports, and it stopped\nhappening: production ran 65 commits and a full day behind main, the site\nserved a twelve-node directory fragment against a repository holding\nnineteen, and no check anywhere went red. A promotion that depends on somebody\nremembering is a promotion that stops, silently, and a stale deploy reads\nexactly like a current one.\n\n`promote-to-production.yml` opens a pull request from main into production and\nkeeps it current — on every green CI run on main, and daily besides, so the\nalarm cannot go quiet just because no push happened. The body names how far\nbehind production is, how long the oldest unpromoted commit has been waiting,\nand what is in it.\n\nIT DOES NOT MERGE\n\nThere is a Terraform apply and a canary behind that branch on a live rewards\nproduct. When it ships is a judgement about risk; *remembering that it has\nnot* is not, and remembering was the broken half. One click, with the diff in\nfront of you — or `auto_merge: true` when you want it to go, which is a\none-word change and deliberately yours to make.\n\nIt raises the PR only over a commit CI has passed. The branch strategy says CI\ngreen on main before promoting, so a PR raised over a red commit would be\nasking somebody to approve the thing the rule forbids.\n\nA promotion merges and never squashes. production carries 2,596 commits of the\noriginal line and main carries 300 of a rewritten one; they were reconciled by\na merge yesterday, and squashing would start that divergence over from a new\nbase.\n\nKind: infra",
      "refs": {
        "commit": "b56ef3b281881f24d9903e84e5fe7860aa5c887d"
      },
      "digest": "8e12d7e9256af4189598f378c90a48b33329b4bc57f18f4f8d36390328719358"
    },
    {
      "id": "ship/claimyour.gold/6e901edc00b3",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T12:52:10+00:00",
      "kind": "fix",
      "title": "Type the wallet mock with the argument it receives, unblocking CI",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Four TypeScript errors, one test file, and main has been red since the module\ngold payout merged. `jest.fn(async () => ({}))` declares a mock whose call\nsignature takes no parameters, so `mock.calls` is an array of zero-length\ntuples: `[0]` on one is TS2493, and its type is `undefined`, so the two casts\nreading the credit's shape are TS2352.\n\nThe test was right about the behaviour and wrong about the type — which is\nhow it passed review and failed the runner, and why nothing about the payout\nlogic changes here. Typing the parameter makes `mock.calls[0][0]` a\n`CreditInput` and the casts unnecessary, matching how every other mock in\ntests/services declares its arguments.\n\nVerified rather than assumed. `@flashylabs/ledger` installs from GitHub\nPackages and needs a token this environment does not have, so `npm ci` cannot\ncomplete here — the construct was reproduced in isolation against\ntypescript 5 and @types/jest 29, producing the same four errors on the old\nform and none on the new.\n\nThis is what has been blocking promotion to `production`: the branch strategy\nrequires CI green on main first, and it has not been.\n\nKind: fix",
      "refs": {
        "commit": "6e901edc00b3964f7ac8f44db3ade46556998c54"
      },
      "digest": "a88b795fafdd1d0e2b3dd82d5c02a0c787b3c3a49ac6f028a4fb369ee860087b"
    },
    {
      "id": "ship/claimyour.gold/43e9394435bf",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T12:26:41+00:00",
      "kind": "other",
      "title": "Re-vendor the directory checker, which had drifted in twelve repositories",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`scripts/check-directory.mjs` is a copy of\n`packages/directory/vendor-check-directory.mjs` in flashyos, under a different\nname — and `estate-hygiene` matched vendored copies by the `vendor-*` filename\npattern, so it never compared this one. Twelve repositories were running a\ncopy old enough not to read `directory.externals.json` at all, which is the\nfile that tells a borrowed id from a dangling one.\n\nNothing failed. That is how a vendored file fails: not by breaking, but by\ndisagreeing about exactly the field somebody has just started writing.\n\nKind: chore",
      "refs": {
        "commit": "43e9394435bfa2b064ea0c16539c3443a30b481f"
      },
      "digest": "67293addb6b4cfa65a98c77d4bfb9c4bf7eeab6ce251c9bfefb2c50336d60c6a"
    },
    {
      "id": "ship/claimyour.gold/bba2c23be587",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T10:58:25+00:00",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "bba2c23be58732c0171fbb5acbc4e4b656bac1aa"
      },
      "digest": "f8227a1befca3da0c02f42fe0dbbf10cfaf9f11f88448f6f930cf63ef8ab03c5"
    },
    {
      "id": "ship/claimyour.gold/477bc7c7510a",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T03:02:00Z",
      "kind": "feature",
      "title": "Merge credentials/module-gold-reaches-the-ledger — 120 gold that was logged and never paid",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The seeded academy catalogue advertises 191 gold across its modules. Passing a\nmodule wrote `goldEarned` onto the attempt row, summed it into the\n`totalGoldEarned` the learner sees on their progress screen, logged a line — and\nwrote no ledger entry at all. 120 of the 191 were a number on a screen with\nnothing behind it.\n\nThe payout now goes through the ledger, and the interesting part is that it has\nto be safe across two applications. flashy-academy serves the same quiz against\nthe same database and pays through a durable outbox rather than here. Both\nderive the idempotency key from the attempt, and there is exactly one attempt\nrow per pass whichever application created it — so the key is the same string on\nboth sides, and the unique index on it makes the second attempt to pay a dedupe\nrather than a double credit.\n\nThe module title is now selected alongside the reward, because without it the\nledger description read \"Academy module passed: undefined\".\n\nFive new tests, run under Jest, which is this repository's runner. Baselined\neither side of the merge: main fails 126 suites and 37 tests before it and 126\nsuites and 37 tests after, all of them pre-existing module-resolution failures\nfrom an incomplete install. This merge adds five passing tests and no new\nfailures.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_0198vyysGCrfdioK9uQr3kbs",
      "refs": {
        "commit": "477bc7c7510a5f9660c3b8c0520f8eb086b7b973"
      },
      "digest": "4d200dc3ddb243d57ed239341323775b1e7851ef836dc3ccbd49fe4a4102e9df"
    },
    {
      "id": "ship/claimyour.gold/4cff62e61f67",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T02:18:20Z",
      "kind": "other",
      "title": "Re-vendor the backlog emitter: it can revise an item now",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`file` has taken `--wants` since the beginning and nothing could add them\nafterwards, so every item filed across the estate — all of them filed without\nwants — was permanently invisible to the matcher, which refuses an item that\nnames no `capabilitiesWanted`. A format whose central field is\nwrite-once-at-creation is a format whose central field is empty.\n\n`revise` changes everything about an item except its visibility. Promotion\nstays a separate verb because it is a separate decision: it refuses anything\nbut a `person/` id, and folding it in would give a revision the power to\npublish. Unmentioned fields are left alone — `close` is a revision too, and\nclearing on absence would strip every want in the repository.\n\nCopied byte-identical from flashyos rather than edited here. A stale vendored\nfile does not break; it disagrees, silently, about exactly the field somebody\nhas just added.\n\nKind: chore",
      "refs": {
        "commit": "4cff62e61f6774226c7c7d13a92e4d213329a2ce"
      },
      "digest": "adcb1d84fa0c67b458f5014826e93d2c23aaa238f636cda2c65a734ddd785628"
    },
    {
      "id": "ship/claimyour.gold/c24d633f9fd9",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T01:00:02Z",
      "kind": "feature",
      "title": "Declare the machine that files this repository's intentions",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two machines write this repository's record and only one was declared.\n`.shiplog/config.json` stamps `agent/<slug>-ci` on every sealed entry;\n`.backlog/config.json` stamps `agent/<slug>-bot` on every filed item. Both\nappear in published fragments. The second appeared in no declaration anywhere\nin the estate.\n\nIt survived the `-ci` rollout because the declaration looked complete:\n`recordEmitter` listed `backlog/1` among the record emitter's formats, so\neverything comparing formats saw it named and stopped, and nothing compared the\nsignature. A declaration naming the right format and the wrong machine is\ncomplete in every respect except the one that matters.\n\nThe record emitter's scope narrows to `shipped/1`, which is what it signs. The\nbacklog emitter is declared beside it with its own `operates` and its own\n`delegatedTo` from the accountable human, bounded to `backlog/1`.\n\nTwo machines is not an artefact of tooling. The tenses are shaped differently\non purpose — an item decays and is never sealed, an entry is sealed and never\ndecays — and different things write them at different times: the seal on a push\nto the default branch, the filing whenever somebody records an intention.\n\nBoth ids are read from the config that stamps them, never composed.\n\nKind: chore\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "c24d633f9fd90c227358a1228c4d555fe7262fef"
      },
      "digest": "4403b67569230699f16b830c7e7e01130c46407dcaa46a55f081770720431d1e"
    },
    {
      "id": "ship/claimyour.gold/1bbed74b53b0",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T00:50:45Z",
      "kind": "feature",
      "title": "Declare the machine surfaces this property serves",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Every property in the estate serves the same handful of documents — a\nhandshake, a charter, backlog/1, shipped/1, checkpoint/1 — and said nothing\nabout them in its own record. That silence is most of why the estate measured\nas thirty graphs rather than one: a fragment describing only its own\norganisation has no reason to name anything another repository defines, so\nnothing crossed a boundary except one person's name on a commit.\n\nServing a format is a fact about this repository; the format belongs to\nflashyos. `cites` is the edge for referencing something somebody else\nauthored, so each of these is a real join rather than a manufactured one.\n\nDetected from disk, never listed. A hand-kept list keeps claiming a surface\nthe day somebody deletes the file, and a declared surface that cannot be\nfetched is worse than an undeclared one — a promise in the record with\nnothing behind it.\n\n`directory.externals.json` is emitted beside the fragment and names what this\nrepository borrows: the standards flashyos authors, and the person\ngord-holdings is the authority for. `check-directory.mjs` reads it instead of\ntaking `--external` flags, so the list cannot drift from the emitter.\n\nThe vendored checker was also one revision behind the canonical copy in\nflashyos and would have rejected an `engaged` edge. Re-vendored.\n\nKind: feature\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01FDosmV9fXV6oZ9NXe7PZ76",
      "refs": {
        "commit": "1bbed74b53b07a5f62c650c6529af2bb93e00b9f"
      },
      "digest": "fc856b8f2f6ebdc0833ebc7abb169f06cfa3f4c381a10d064515fc54b4c06f3e"
    },
    {
      "id": "ship/claimyour.gold/d91d9a64ed25",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-31T00:45:18Z",
      "kind": "docs",
      "title": "Say whose authority the record emitter signs under",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`operates` says this organisation runs the machine that seals its record. It\ndoes not say who answers for what the machine signs, and that is the fact a\nsignature rests on: an agent acts *for* somebody, the somebody answers, and an\nagent with no stated bound is one nobody can say has exceeded anything.\n\n`delegatedTo` is that edge — person to agent, carrying the same scope the\nemitter operates under. It is the shape of a Flashy ID root grant, whose issuer\nis the accountable human and whose scope a chain may only ever narrow. The\nrecord states the delegation; the signed assertion that enforces it lives in\nFlashy ID, and no signature belongs here, because proof never moves into the\nrecord.\n\nThe edge type has been in the vocabulary since the vocabulary was written and\nno fragment in the estate had ever used one. Writing the first exposed two\nfaults in flashyos that are fixed there: the rule required `scopes` where the\nedge carries `scope`, so no delegation could have satisfied it, and the\nflat-to-embedded conversion discarded every relationship attribute but two, so\nan edge that stated what it owed was reported as missing it.\n\nKind: chore\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "d91d9a64ed2505fe82d4b350b9f21061753a1917"
      },
      "digest": "caac9b53b7bf39c48b8bef1f38e5a1c1907a259876bc906c407f2e8423fcd384"
    },
    {
      "id": "ship/claimyour.gold/066bafae91a1",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T22:06:01Z",
      "kind": "other",
      "title": "Re-vendor the checkpoint and frontdoor emitters",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two dead imports were found by running a linter over a repository that vendors\nthese files: a `join` from `node:path` in `vendor-checkpoint.mjs` and another\nin `vendor-emit-frontdoor.mjs`. Both are fixed at their source in flashyos and\ncopied here byte-identical.\n\nNeither changes behaviour. The reason to carry the copy anyway is the estate\nrule that produced the fix: a vendored file that disagrees with its source does\nnot fail, it disagrees — silently, about whichever field somebody has just\nchanged — and `estate-hygiene` compares these byte-for-byte precisely so a copy\ncannot quietly fall behind.\n\nKind: chore\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "066bafae91a1acea996c8ff9c8f3d5d908633fc4"
      },
      "digest": "a0a643e6a882f18736a9fef552ea51d1661442d85242517bb900abaed946d415"
    },
    {
      "id": "ship/claimyour.gold/7afcf32a903f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T21:44:07Z",
      "kind": "fix",
      "title": "Read the emitter id, do not derive it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The declaration added moments ago used `${charter.slug}-ci` and was wrong here:\nthis repository signs its record with an id the charter slug does not produce,\nso it declared an agent that matched no signature anywhere. A declaration that\nmatches nothing is indistinguishable from one that works — every check that\nlooks at shape passes, and the provenance number does not move.\n\nThe id now comes from `.shiplog/config.json`, which is the file that actually\nstamps it. Two of ten repositories were affected: ClaimYour.Gold signs\n`agent/claimyour.gold-ci` against a charter slug of `claimyour-gold`, and\ndais-global signs `agent/dais-global-ci` against a slug of `dais`.\n\n`tools/emitter-declaration.test.mjs` in flashyos now compares the declared id\nagainst the stamped one, which is the check that was missing.\n\nKind: fix\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01FDosmV9fXV6oZ9NXe7PZ76",
      "refs": {
        "commit": "7afcf32a903f794a35415e73145646f595c3c4ee"
      },
      "digest": "c79e8db448f1b3af8e8d994bf0bbb7efa18716d0a0b728258a91b5578dd7825d"
    },
    {
      "id": "ship/claimyour.gold/3794c24a7770",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T21:38:20Z",
      "kind": "feature",
      "title": "Declare the machine that signs this repository's record",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Every sealed entry and every fragment here carries\n`assertedBy: agent/<slug>-ci`, and until now that was an id nothing in the\nestate declared. Across thirty properties it was 2,478 edges citing an agent\nthat formally did not exist — provenance that reads as provenance and carries\nnone, which is worse than an empty field, because the empty field is honest\nabout not knowing who made the claim.\n\nDeclared as an Agent the organisation `operates`, not as a charter role. A\nrole is a governance label the org answers for and it is rendered into the\nhandshake's advertised capabilities, so a \"ci\" role would tell the network\nthis organisation does continuous integration for other people.\n\nThe canonical form is `declareEmitters` in `@flashyos/directory`. It is\ninlined here because `scripts/directory.mjs` is dependency-free by design, and\n`tools/emitter-declaration.test.mjs` in flashyos is the drift test that keeps\nthe two in step.\n\nKind: feature\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01FDosmV9fXV6oZ9NXe7PZ76",
      "refs": {
        "commit": "3794c24a7770ce73484fcbc460a2b8dacdf6cf9c"
      },
      "digest": "216d94ea68fe664fd7058bc23d1d5a4bc177f74da8b5a1120d5a40b2277a34c6"
    },
    {
      "id": "ship/claimyour.gold/6620270e4104",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T19:45:06Z",
      "kind": "fix",
      "title": "Re-vendor the charter checker: it had drifted from the spec",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The vendored checker rejected renamedFrom, which the charter defines and the\nrole-rename sync reads; rejected a digit in a role name, which the spec's own\nregex allows; and enforced no length bound at all, so the 24-character role\nname cap was the one rule this pre-install check could not see.\n\nEleven byte-identical copies across the estate agreed with each other\nperfectly and disagreed with @flashyos/aao in all four places. The monorepo\nnow runs both checkers over the same documents and fails on any disagreement\nabout the verdict.\n\nThis charter still passes.\n\nKind: fix",
      "refs": {
        "commit": "6620270e41049c03b876e5523ea2ee6e896b86d3"
      },
      "digest": "a15f53bea450b956e0f432b6afc3fafd8053fb458f401a18d565df63af2b9472"
    },
    {
      "id": "ship/claimyour.gold/70f8074103e7",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T19:39:22Z",
      "kind": "other",
      "title": "Conformance from the package, not from a copy of its rules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "tests/app/mesh-conformance.test.ts carried its own SPEC_KEYS and FAMILIES\narrays and its own 24-character role-name cap, typed out from the spec. A\nvendored snapshot of a live source with nothing to notice when the two\ndiverge — the failure mode this estate has a rule against, applied to the\ndocument a stranger reads to decide what this org is.\n\nassertProperty applies the published rules and imports its constants from\n@flashyos/aao, against the documents the two route handlers actually serve.\nrequireThresholds carries the old every-role-has-a-gate assertion.\n\nWhat stays is what is true of this product and of no other org: every role\nat LOW rather than one at CRITICAL, the reward never called real gold, and\nthe role names FlashyOS's and Flashy.Academy's charters claim to share with\nthis one.\n\nThis is also the property that found the packaging defect. It runs jest,\nwhich resolves with CJS conditions; the package published only an ESM build\nunder an exports map naming only `import`. The largest product in the estate\ncould not import its own conformance checker. Fixed upstream in 0.2.3, which\nships a CommonJS build — no jest configuration is needed here.\n\nKind: refactor",
      "refs": {
        "commit": "70f8074103e72accc0705b497ad777c213382445"
      },
      "digest": "0765f6f05b6a50ea584c7e1483f0d288fddc0be0a82d6d069b66e2670dc63f0a"
    },
    {
      "id": "ship/claimyour.gold/b06e01bc2221",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T18:13:02Z",
      "kind": "feature",
      "title": "Merge: their charter had the real slug, my branch had the routes to serve it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Another session wrote this charter on main while I wrote one on a branch, and\nthe difference that matters is one hyphen. Theirs says `claimyour-gold`, which\nis the slug this org is actually registered under on the live network. Mine\nsaid `claim-your-gold`, which I invented from the product name and which\nresolves to nothing — a handshake naming a slug that does not exist sends an\nagent to a profile that is not there, which is worse than serving no handshake\nat all. Theirs, entirely.\n\nThe halves turned out complementary: main had the charter and nothing serving\nit, which is the exact state that leaves a property at L1 forever, because\n@flashyos/conformance reads /.well-known/flashyos-charter.json and nowhere\nelse. This branch had both route handlers and the test. So: their charter, my\nroutes.\n\nTwo assertions rewritten against their roster rather than mine:\n\n  The slug, with the reason above written next to it.\n\n  I had asserted `rewards` is CRITICAL and nothing else is. Their charter has\n  no `rewards` role and gates all nine at LOW. That reads strange until you\n  look at what this repository is — 188 workers around a reward economy, where\n  almost anything shipped can change what somebody earned, sees, or expects to\n  redeem. Singling out one role as the dangerous one would imply the other\n  eight are safe unattended, and none of them are. The test now pins that.\n\nAlso fixed my own port: jest's `expect` takes no message argument, unlike\nvitest's, so `expect(value, name)` silently passed the name as a matcher\noption. The role name moves into the compared value, so a failure still says\nwhich role broke it.\n\n`npx tsc --noEmit` reports exactly one error, the documented phantom from the\nflashy-ledger symlink's duplicate mongodb types, which cannot occur in CI.\n365 tests green across tests/app, tests/lib/os and tests/lib/ledger.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01VgrPGGUFKMq9zXBHnfcTgs",
      "refs": {
        "commit": "b06e01bc22214c24d760e5bbbb4cf459e423ef50"
      },
      "digest": "5bddf4e9b0d75b6ffa9a54892581905ba6c87e518bc22c3dcc964881f499d7aa"
    },
    {
      "id": "ship/claimyour.gold/3c85f8cbc5bd",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T18:01:02Z",
      "kind": "other",
      "title": "Re-emit against the rebased tree",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Kind: chore",
      "refs": {
        "commit": "3c85f8cbc5bd893f11f87a8895e44c0748c71134"
      },
      "digest": "1e031e07245975ead37a55fff82f3c8dc3abb4e134302fb47167162eeeca7744"
    },
    {
      "id": "ship/claimyour.gold/bc0e5eb4734d",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T17:58:44+00:00",
      "kind": "fix",
      "title": "Carry the current vendored emitters",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A stale copy fails silently and in the dangerous direction: it does not know\nabout rules added since it was vendored, so it ignores them rather than\nerroring. Re-emitted and re-verified against the refreshed copies.\n\nKind: fix",
      "refs": {
        "commit": "bc0e5eb4734d320e84ad94aa8b00d2a980fca5a4"
      },
      "digest": "ac60f54e12167183c0c689f919932e2460ddfe602468820ef422660b2478380b"
    },
    {
      "id": "ship/claimyour.gold/3a2b0155ddf1",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T17:37:40+00:00",
      "kind": "fix",
      "title": "Fail loudly on a fragment that exists and cannot be parsed",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The emitter treated an unparseable fragment as an absent one and built a head\nover whatever else it could read. A conflicted fragment produced a\nvalid-looking head over nothing.\n\nKind: fix",
      "refs": {
        "commit": "3a2b0155ddf19ed1b376d3b7d18154fef0d99d2f"
      },
      "digest": "7f19525594d7aabad97993f5acf2ac320af2846dab90bf128d910b2b3851731a"
    },
    {
      "id": "ship/claimyour.gold/ee13e63009e7",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T17:22:26+00:00",
      "kind": "other",
      "title": "Re-emit the log and its checkpoint after rebase",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Kind: chore",
      "refs": {
        "commit": "ee13e63009e7b3aa69a060d1b9afa6ccbe832e57"
      },
      "digest": "b0e8cb400422e12c3200f7becfac4b00143491f5b33523a94fb18b6d2405e8b4"
    },
    {
      "id": "ship/claimyour.gold/7b5945435e03",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T17:18:11+00:00",
      "kind": "feature",
      "title": "Adopt checkpoint/1 — a tree head over what this repository seals",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "An RFC 6962 Merkle root over the sealed claims already published here, served\nbeside them. Anyone holding the fragments can recompute it and see whether the\nrecord still describes what it said it did.\n\nThe head is deliberately unsigned. A signature over a root computed and checked\nby the same party is ceremony without a property — what makes history provably\nappend-only is a witness who is not us, and that is not built. The root catches\ndrift and after-the-fact edits, and nothing here claims more.\n\nIt is refreshed by the shiplog workflow rather than its own, so the head and\nthe log it commits to always move in one commit. A separate workflow would\nleave a window in which the published root and the published record disagree,\nand a reader hitting that window sees a forged-looking estate.\n\nKind: feature",
      "refs": {
        "commit": "7b5945435e035e82b28d9292c91981c52519b094"
      },
      "digest": "d493d6f4a1ac1ad05d94a926262110779eadcf0beb4b66a297067dcbc5e16d80"
    },
    {
      "id": "ship/claimyour.gold/b7e8e125cc39",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T16:50:40+00:00",
      "kind": "other",
      "title": "Merge main, then publish",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Another session adopted these formats here independently. Its author\ntable and its branch-agnostic workflows are better than mine and are\ntaken as-is; the emitter is mine, because it carries three things theirs\ndoes not and one of them is load-bearing under their design.\n\nAn emit is now a union rather than a replacement. Their workflow fires on\nany push and gates the job on the default branch, which is the right fix\nfor the branch-pinning trap — but combined with derive-and-overwrite it\nwould let a feature branch rewrite the trunk’s log with its own\nfirst-parent shape. Together the two changes are safe.\n\nAlso mine: .shiplog/held.json, so publishing a log is not the same\ndecision as publishing every entry in it; a guard that stops an agent’s\ncommits being filed under a person; and a filter for this format’s own\nrefresh commits, which were being recorded as things that shipped.\n\nvisibility is now public. That is the decision that turns an internal\nrecord into a changelog anyone can read.\n\nKind: other",
      "refs": {
        "commit": "b7e8e125cc3927e684b1b1e67f979fd8dd35f0de"
      },
      "digest": "c3eb94ddd9a95f3f301ce4122e4a81816435a830ec6a3ba0778b37022bf5a1cc"
    },
    {
      "id": "ship/claimyour.gold/0504b6ca03f1",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T16:24:30+00:00",
      "kind": "feature",
      "title": "Publish the log: 282 entries across the estate become public",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Everything derived has landed private since adoption. This flips\nvisibility for the estate-owned properties, which is the decision that\nturns an internal record into a public changelog.\n\nTwo entries are held back by .shiplog/held.json, with the reason written\nnext to each: one names a credential that is still unrotated, one is a\nfrank internal note about a durability gap in a live product. Held, not\ndeleted — both are still in this repository’s own record, sealed and\ncounted. Only whether a stranger can read them changes.\n\nThe vendored emitter is re-copied in the same commit. The hold did\nnothing until it was: the previously vendored copy predated the feature\nand published the held entry regardless, silently.\n\nKind: feat",
      "refs": {
        "commit": "0504b6ca03f1e08d3085eeeaf961b0c8004198c8"
      },
      "digest": "371981da97c42797f9fecc7853fe84f34d062a978d7618f19b5e8b16d90566f6"
    },
    {
      "id": "ship/claimyour.gold/4e2bca41b3e2",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T16:18:21+00:00",
      "kind": "fix",
      "title": "Map the estate's commit addresses to who they belong to",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`authors` was empty and `defaultAuthor` filed every entry under one identity,\nso this log looked fully attributed while agent-authored commits were recorded\nas the person named as the default.\n\nThe map is declared once in flashyos `tools/estate-authors.mjs` and synced\nhere. Five addresses are left unmapped on purpose, each with a stated reason.\n\nKind: fix",
      "refs": {
        "commit": "4e2bca41b3e2cb195aaf444f942b91e22343c82d"
      },
      "digest": "03f7f7b8690983b06d0d64d670e58a37c88b58cc6b82e51f0ecc475811fe89db"
    },
    {
      "id": "ship/claimyour.gold/41126bd03cc7",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T16:04:21+00:00",
      "kind": "feature",
      "title": "Adopt the two tenses: what this repository intends, and what it shipped",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`backlog/1` and `shipped/1`, both emitted by a vendored, dependency-free\nscript and refreshed by a workflow on this repository's default branch.\n\nEverything lands private. The served fragment publishes nothing until\nsomebody changes one field, which is the decision that turns an internal\nlog into a public changelog — not a side effect of adopting.\n\nThe log credits the agents that wrote the commits. That needed a fix\nupstream first: with an empty `authors` table every unrecognised address\nfell through to `defaultAuthor`, and the estate's first derived log read\n100% human-authored over a history that was 95/107 agent-authored. `adopt`\nnow seeds the machine addresses it finds in the history.\n\nThe workflow triggers on the branch `git symbolic-ref refs/remotes/origin/HEAD`\nreports, which is not always `main` in this estate and is never the branch\nadoption happened on.\n\nKind: feat",
      "refs": {
        "commit": "41126bd03cc7220cc34a443ef76d95251f59716c"
      },
      "digest": "524a6a2c89350fea8ff9eb192b9c8fdfc0b2e8736664d579c74b958f47c2cfca"
    },
    {
      "id": "ship/claimyour.gold/a50b190a4ea1",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T15:46:14+00:00",
      "kind": "fix",
      "title": "Stop pinning the shiplog and backlog workflows to a branch name",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Each workflow triggered on `branches: ['<the default branch at adoption>']`.\nEleven repositories in this estate have a `claude/*` branch as their GitHub\ndefault; renaming one to `main` is the right thing to do and would have stopped\nits workflow firing. Nothing would have failed — the fragment would simply have\nstopped advancing, and a stale changelog reads exactly like a current one.\n\nThe trigger now matches any push and the job is gated on\n`github.ref_name == github.event.repository.default_branch`, resolved per run,\nso a rename is survived rather than discovered. `branch` is dropped from the\nconfig: nothing read it, and a stored branch name is a snapshot of something\nthat changes.\n\nKind: fix",
      "refs": {
        "commit": "a50b190a4ea116550a5835d2f9dd650887e51c50"
      },
      "digest": "383c85847bc2019bf1b1dfdac73557225756389ab582331532afa635b3923490"
    },
    {
      "id": "ship/claimyour.gold/45fb05b54055",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T13:20:58+00:00",
      "kind": "infra",
      "title": "Reclassify the log against the convention this estate writes in",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The derived log was classified only by conventional-commit prefixes, and\nthis repository writes declarative English. Unclassified went from 94%\nto 27% by reading the estate's declared imperative lexicon, looking\npast a project prefix to the verb behind it, and dropping merges of\nanother branch into this line — which are not things that shipped.\n\nNothing is published: entries remain private and the served copy is the\npublic projection.\n\nKind: infra\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01FDosmV9fXV6oZ9NXe7PZ76",
      "refs": {
        "commit": "45fb05b540551ed9df91e0833350d5f0b83a456f"
      },
      "digest": "45c8956d4d0422e5aab31f3a1a753f5b8a5bf1768a02297faeb476a6bf60d512"
    },
    {
      "id": "ship/claimyour.gold/88423aed22be",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T05:45:01+00:00",
      "kind": "feature",
      "title": "Adopt backlog/1 and shipped/1",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "This repository now publishes the two tenses the estate records: what it\nintends, and what it shipped. Both are emitted by a dependency-free\nvendored script, so nothing here gains a toolchain it did not have.\n\nNothing is published by this commit. Backlog items are filed private and\nreach the served fragment only when a named human promotes one; shipped\nentries land private until someone changes one field in\n.shiplog/config.json. The served copy is the public projection and the\nemitter writes it, so a private record cannot reach a URL through a\nforgotten copy step.\n\nDerived 50 entries from this repository's own history, every seal\nrecomputed. Org org/claimyour-gold, served at public/.well-known/shiplog.json.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01FDosmV9fXV6oZ9NXe7PZ76",
      "refs": {
        "commit": "88423aed22be8a8917a9ce6a92152a9cb074da7b"
      },
      "digest": "45a0b47973dff79a8c172f451b8c1b91fc10a202ba8fc1047cf35c8bd57013fb"
    },
    {
      "id": "ship/claimyour.gold/cab388f01102",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T03:07:48+00:00",
      "kind": "feature",
      "title": "Advertise a way in a stranger can actually use",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The handshake's `join` field is the one thing in that document somebody\nactually follows. Every handshake in the estate pointed it at\napp.flashyos.com/onboard, which redirects anyone without a session to a\npassword form. A stranger following the URL our own standard tells them to\nfollow arrived at a login they had no account for.\n\nIt now points at https://flashyos.com/join — open, no account, nothing to\ninstall.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "cab388f01102265ba027c7d0d5490cfbc8bc8925"
      },
      "digest": "5652269b6c356f6820064bf009661b26e47931c42bdbfb72e24234b7f5820b1f"
    },
    {
      "id": "ship/claimyour.gold/e32b2d606b58",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T02:26:33+00:00",
      "kind": "infra",
      "title": "Point the front door at the ladder's new home",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The ladder moved from gord.ventures to gord.holdings. It is an estate-wide\nclaim — every door in the estate points at it — and estate-wide claims belong\nto the parent rather than to one sibling that also has its own lanes. The old\nURL had no deployment behind it, so this door was directing anyone who read it\nto a 404.\n\nConfig and emitted door, nothing else.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "e32b2d606b58e68d70ab7a418a0a8c81a4c162c5"
      },
      "digest": "443621c3200865756ca6a871c4dd3d2763fcc41cb150707e1aaf98ec2d024ab8"
    },
    {
      "id": "ship/claimyour.gold/102e664f4fab",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T01:35:00+00:00",
      "kind": "feature",
      "title": "Serve the directory fragment, which this property was not doing",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The fragment lived only at the repository root. A Next.js app does not\nserve the repository root, so https://<this property>/directory.fragment.json\nreturned 404 — and the estate's directory is federated, meaning every\nproperty is supposed to publish its own fragment for anyone to fetch and\nmerge.\n\nThirteen of fourteen properties were in this state. The consequence is\nlarger than a missing file: the estate graph could only be assembled by\nsomeone with a git checkout of every repository, which defeats the entire\nreason for federating it. A graph you can only build from a laptop proves\nthe files are on that laptop. A graph assembled from published URLs proves\nthe estate publishes what it says it does, can be reproduced by somebody\nwho does not trust us, and is the only shape that lets an organisation we\ndo not own ever join it.\n\nSame defect as the charter, found the same way and fixed the same way: the\nfragment is copied into the served directory and CI diffs the served copy\nagainst the source so the two cannot drift.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "102e664f4fab390a5037f90831c173aa76cfd2ab"
      },
      "digest": "dd6b008c1dd8bf3201ab6be9f62dbf3d16de095b3fa03df29e8ab579ba4526b2"
    },
    {
      "id": "ship/claimyour.gold/80f0bfa1f666",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T01:12:52+00:00",
      "kind": "feature",
      "title": "Emit a directory fragment, the last thing keeping this out of the graph",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The charter and the door landed yesterday; the fragment did not, so the\nlargest property in the estate — 396 routes — appeared nowhere in the\nestate graph. Twelve nodes and twelve edges: the organisation, its nine\ndeclared roles as agents, the property, and the one claim this site is the\ncanonical home for.\n\nThat claim needed care. The emitter was adapted from flashy-gold's, and\ncarried across unchanged it declared prop/flashy.gold and\nclaim/what-the-flashy-gold-unit-is — this repository asserting authority\nover a sibling's property and a sibling's definition. The estate merge\nwould have rejected it as contested authority, which is what that check is\nfor, but it is better not to have shipped it.\n\nThe split is real rather than cosmetic. Flashy Gold is the authority for\nwhat a unit is; this property is the authority for how a person actually\ngets one. Two claims, two homes.\n\nMerged with the other thirteen fragments across the estate: 275 nodes, 267\nedges, no contested authority.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "80f0bfa1f6660c19371ee0c571c6bb109d2fe3a6"
      },
      "digest": "74bf3c3803aaca0b90238256f2e714992d9a3f97dea54af72d28940b763755f0"
    },
    {
      "id": "ship/claimyour.gold/c604f1209eb9",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-30T00:26:46+00:00",
      "kind": "feature",
      "title": "Join the mesh: charter, handshake and front door",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "This was the only live property in the estate publishing none of the\nthree. No charter, no handshake, no door — while the group publishes a\nstandard telling other organisations to serve exactly those files.\n\nThe charter existed. It had been sitting on coordination/roster-follows-\nthe-charter in the pre-conformance shape — org instead of slug, _comment\ninstead of x-comment, no aao version, no accountable human, and no measure\nor capabilities on any role. Nine real roles with real purposes, unmerged\nand unserved. Brought onto main in conforming shape with the roles and\ntheir renamedFrom mappings intact.\n\nEvery role carries humanApprovalAtOrAbove: LOW, the most restrictive\nsetting the standard has — a person approves anything at or above low\nimpact. That is a floor rather than a finding. Nobody has reviewed what\nthese agents may safely decide alone, and until someone has, the honest\ndefault is the one that asks a person more often. Loosening any of them\nshould be a deliberate act with the reasoning attached.\n\nThe handshake is new. Its capabilities are derived from this property's\nown charter rather than copied from a sibling — a first draft carried\nFlashy Academy's curriculum, credentials and placement, which this\nproperty does not do and could not have honoured.\n\nThe door opens exactly one lane, integrate, because this is a consumer\napp: someone claiming a reward is not being recruited into a governance\nstandard. That restraint is declared in the config rather than remembered,\nand the estate-wide merge fails if a consumer property ever opens the\ncapital lane.\n\nThe charter is copied into public/ so it is actually served — at the\nrepository root a Next.js app never serves it, which is why nine of the\nestate's ten live properties were returning 404 on /flashyos.roles.json\nwhile telling everyone else to publish it. CI diffs the served copy\nagainst the source.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5",
      "refs": {
        "commit": "c604f1209eb92979c9f4ce9922f08ce63a2ba129"
      },
      "digest": "674393b89bcceaedc530ef3ad07362432e3157ac971efac6828a3a195cc7ab54"
    },
    {
      "id": "ship/claimyour.gold/3c6e6a626126",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-28T03:18:08+00:00",
      "kind": "docs",
      "title": "re-measure the Academy extraction, and drop one stale exemption",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`academy-removal-status-2026-08-27.md` said route parity was unverified.\nIt is now measured, by directory-set comparison of both working trees:\nflashy-academy has all 62 Academy pages and all 161 Academy API routes this\nrepo serves, plus six of its own. Zero missing in either direction. That is\nthe check gating \"stand up the deployment\" — a cutover to a service missing\nroutes 404s live pages — and it passes.\n\nEvery coupling now has a destination. Five moved to flashy-academy this\nsession (both affiliate routes, employer alumni-search, and the two BullMQ\nworkers as cron routes); super/onboarding-funnel needed nothing, because\nflashy-academy's admin/academy/funnel-report already calls the same\nservice; and learn/[slug] has a seam waiting for it.\n\nTwo corrections to yesterday's note, both in the direction of less\nprogress than claimed:\n\n- \"sitemap.ts no longer imports Academy\" was true only in the sense that\n  the import moved into src/lib/academySitemapEntries.ts, which the guard\n  exempts by filename. The coupling is real and deferred: this repo's\n  sitemap should stop emitting /academy/* entirely once Academy is gone.\n  Its allowlist entry was doing nothing, though — verified by removing it\n  and confirming lint results are byte-identical — so the list is 10, and\n  10 is now the honest number.\n- learn/[slug] is *not* switched to its new seam, on purpose. Cutting the\n  import before flashy.academy is deployed hides a live CTA to buy a\n  number on a checklist.\n\nThe new material is §4: nothing schedules flashy-academy's twenty cron\nroutes, anywhere in the estate, and fifteen of them have never had a\ncadence written down — there or here, where they were ported from. For\ngold-payouts that means learners go unpaid for as long as nothing calls\nit. Recorded, with the undecided ones marked undecided rather than\nguessed.\n\nCommitted with --no-verify: the hook fails on the phantom mongodb symlink\nerror documented in CLAUDE.md, confirmed to be the only one.\n\nCo-Authored-By: Clau",
      "refs": {
        "commit": "3c6e6a6261260b7472e52886c5781a42bb8c3792"
      },
      "digest": "894b50e933de52cc751748dd03191c9c343044fe2d6a9d0f539c4fc7a7e390d6"
    },
    {
      "id": "ship/claimyour.gold/84baf423e486",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-28T02:28:55+00:00",
      "kind": "feature",
      "title": "Record the phantom mongodb type error",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Anyone with a sibling flashy-ledger checkout sees one tsc error that is\nnot real: two copies of mongodb's types meeting through the symlink. The\nledger declares mongodb as a peer dependency, which is right; the\nduplicate exists only because the sibling installed its own copy for its\nown tests, and it cannot occur in CI.\n\nI tried a paths mapping and removing the nested copy; neither resolved it\ncleanly, so rather than leave a half-fix in the tree I am recording the\nsymptom. A phantom error nobody has written down is how a real one gets\nwaved through — and it is also why the new pre-push hook can fail on a\nclean tree, which the note says explicitly so --no-verify stays a\nconsidered choice rather than a habit.",
      "refs": {
        "commit": "84baf423e48618b547684718e27158ec76f8ced6"
      },
      "digest": "c8ca27b423a006d73c53819053ae6e381e04ef244b2c016fdc21b75257dd83fc"
    },
    {
      "id": "ship/claimyour.gold/9e5180396b79",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-28T02:20:46+00:00",
      "kind": "fix",
      "title": "the 'language' input was never valid, so it was ignored",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The action's own warning names it: \"Unexpected input(s) 'language',\nvalid inputs are [... 'languages' ...]\". Every CodeQL workflow in the\nestate passed the singular form, which GitHub discarded — so the matrix\nlanguage selection has never actually been applied.\n\nFound while checking whether the earlier scoping fix worked. It had not,\nand the real blocking error is unchanged: code scanning is not enabled\non the repository, which is a settings toggle.",
      "refs": {
        "commit": "9e5180396b79607f006d61ca31f81bba9430f352"
      },
      "digest": "d379e6abbd5ff543d2756679b84e381965f36a3455e4d48671248106c25c7ae1"
    },
    {
      "id": "ship/claimyour.gold/ca289bd20ed6",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-28T02:17:10+00:00",
      "kind": "infra",
      "title": "Retire the full-suite pre-push hook",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The hook ran all 11,168 tests before every push. At that size the honest\noutcome is not higher-quality pushes — it is a habit of reaching for\n--no-verify, which disables every check including the cheap ones that\nwould have caught the mistake.\n\nIt now runs typecheck plus the os and ledger seam tests: 267 tests in\nabout nine seconds, against several minutes before. CI keeps the full\nsuite, which is where a slow, complete gate belongs.\n\nThe comment at the top says how to run everything by hand before pushing\nsomething risky, so the fast path is a default rather than a ceiling.",
      "refs": {
        "commit": "ca289bd20ed64a4f4d9371abe159013b5993b594"
      },
      "digest": "d64004e8e50b484f4060ce02b08496ee0781e7529199aedc15c3d2e2efd942ca"
    },
    {
      "id": "ship/claimyour.gold/2e93ec93038c",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-28T01:53:25+00:00",
      "kind": "security",
      "title": "make CodeQL able to run at all",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "CodeQL had failed on every run since it was added — five for five, never\nonce green. Two causes, neither a code finding:\n\n1. 712 files it could not parse. refences/ held complete vendored copies\n   of three other applications — their own next.config.mjs, src/, config\n   files, 224 files and 1.3MB. Nothing imported them; their entire\n   footprint was three separate carve-outs (tsconfig, jest, eslint) that\n   existed only to keep them out of every tool, plus enough parse errors\n   to turn the scan into a configuration error. Removed, along with the\n   three now-dead exclusions. Recoverable from history if ever wanted.\n\n2. Code scanning is not enabled on the repository, so results cannot\n   upload. That is a settings toggle and is Michael's to flip.\n\nAdds .github/codeql-config.yml so vendored trees, build output and\ngenerated clients can never break the scan again — the same config is\ngoing to every repo that runs CodeQL.\n\nSuite green (1264 suites), typecheck unchanged, lint clean.",
      "refs": {
        "commit": "2e93ec93038c60ff039d6843e839978637eb427b"
      },
      "digest": "ee5fd5a58a2c5c8d23e5280d44b85923072d241c2123590e7c4ec9ffba8d9ee3"
    },
    {
      "id": "ship/claimyour.gold/b168a934c121",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-28T01:30:12+00:00",
      "kind": "infra",
      "title": "Make the secret scan mean something: allowlist the six placeholders",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "gitleaks went red on its first run against main. All six matches are\nplaceholders — a docs example key, the award-points sample body rendered\nin the client settings page, and four test fixtures including a base64\nstring whose own comment says it is too short to be a key. None is a\ncredential.\n\nA security check that is always red is one nobody reads, so the six are\nallowlisted by their literal text rather than by file or directory: a\nreal key committed to any of those same files still fails the scan.\nVerified by planting an sk_live-shaped key in the allowlisted test file\n— still caught — and removing it again.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "b168a934c1218a304dece533bab0ba70b0af84cd"
      },
      "digest": "7d82403bbfca4bd064956d49f351810b84387ce5deb995b3651e566d28984c20"
    },
    {
      "id": "ship/claimyour.gold/917ae62fe3ac",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-28T01:25:03+00:00",
      "kind": "other",
      "title": "A partner can set their own conversion rate from their own dashboard",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The client settings page has always POSTed the rate with a session cookie\nand no signature — the secret key never reaches the browser, by design.\nThe route accepted only HMAC, so Save failed the signature check every\ntime: no partner has ever been able to change their rate from the UI.\n\nSession first, HMAC second. Both callers work, and a request with neither\nis still rejected by authenticateClient exactly as before. The existing\ntests mocked authenticateClient outright, so they passed against a route\nthe browser could never reach; the new cases cover the dashboard path and\nthe reject-both path, and the dashboard case fails without the fix.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "917ae62fe3ac5bf3b4b902e89a8db83783a44c34"
      },
      "digest": "01ad04286f65be22f619e51840e5966a2877dd1dbb395d9b47ca5bf4d9e03805"
    },
    {
      "id": "ship/claimyour.gold/d6b9e26f33d6",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T23:34:08+00:00",
      "kind": "feature",
      "title": "Merge the Experience Ledger — XP on the ledger's books, with its follow-ups landed",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The twelve XP commits (XpEvent hash-chained per (customerId, skill),\nprices as data, anomaly flags for human review) plus the three\nfollow-ups from docs/xp-ledger-landing-followups-2026-08-21.md: the\nskill-gate test asserts against goldLedger, the hunter-engagement route\nderives the canonical idempotency key from sourceRef so Academy's\nresent reports collide instead of paying twice, and the crew-war XP\naward is awaited and attributable.\n\nFull suite on the merged tree: 1,259 suites, 11,144 tests, tsc and\neslint clean.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "d6b9e26f33d60406d5f5ee482fe9060bb278cb41"
      },
      "digest": "e6d85f2df670839659baeb25c033137e28a989c661dc48948ced8dfccae48fe7"
    },
    {
      "id": "ship/claimyour.gold/3f83705d2d16",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T23:16:24+00:00",
      "kind": "other",
      "title": "Lockfile: the real resolved URL and integrity for ledger 0.8.0",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The hand-pinned entry lacked the trailing shasum segment GitHub\nPackages requires in download URLs, so npm ci 405'd on main and the\ndev deploy failed with it. This entry was regenerated by the\nsync-lockfile workflow against the registry, and the artifact it pins\nwas verified file-by-file against a local build of flashy-ledger main\n(aggregate dist sha256 bfc45270…, identical) before being trusted.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "3f83705d2d1671d99dad0b8dea7bb0c144807b8d"
      },
      "digest": "27cd419d60f9152bc88fc02c7f8c14dcebbd2914d970c95de0033b09b8e9a0e4"
    },
    {
      "id": "ship/claimyour.gold/7450b9d7fe86",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T22:46:28+00:00",
      "kind": "infra",
      "title": "Delete the alliance-raid mint, wall off raids from gold, make the gate one command",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Three of the four standing decisions, executed on the standing approval.\n\nresolveAllianceRaid credited raiderGoldDelta x 2.0 to two captains with\nno debit anywhere - an uncapped mint of a redeemable currency on a\nuser-triggered action, reachable from a live route. The multiplier is\ndeleted, not tuned; the raid still resolves and dissolves the alliance,\nand spoils return as commodities when the economy cuts over. A tombstone\ntest proves no write path that could carry gold runs.\n\nAn eslint rule now bans every raid-named service and job from importing\npostEntry or postTransfer at all: raids move commodities, full stop. The\nrule was proven to bite - a test import failed lint - and the codebase\npasses clean because the mint was its only violation.\n\ngate:cyg-led turns the SP-6-D4 exit from prose into one command: the\n30-day invariant streak (a skipped day breaks it - an absence is not a\npass), the empty legacy-writer list, and a full float/minor wallet scan.\ndocs/cyg-led-exit.md carries the sign-off table; a name and a date there\nis the signature.\n\nreport:net-supply is the economy owner's weekly figure - net units\ncreated minus destroyed per asset per ISO week, grouped by sourceType.\nIt reads gold today and all five assets the day commodities land,\nbecause it groups by whatever the ledger actually holds.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "7450b9d7fe86cf553af729a57e1ae07de75dcf76"
      },
      "digest": "78e095e2943125771e12a77b0b97d9d6764fd7512a0c6c46e994d9fa6ab2c932"
    },
    {
      "id": "ship/claimyour.gold/223bbc09c8bd",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T22:32:47+00:00",
      "kind": "infra",
      "title": "Require ledger ^0.8.0 — the anchor imports its merkle domain",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The lockfile entry carries no integrity hash because 0.8.0 is not\npublished yet: merge flashy-ledger first, then npm install here.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "223bbc09c8bd5ceef36bd62bf34b1fb6c863fc28"
      },
      "digest": "7d16fc60e028afd286d0a56b0cf3dc0214e26cf530d57415a066f10e5b8050ce"
    },
    {
      "id": "ship/claimyour.gold/3fa20a18bdc8",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T22:28:43+00:00",
      "kind": "feature",
      "title": "Anchor every day of the ledger, and open the public read API",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The Merkle spec has been finished on flashy-network for weeks, fed by\nfixtures - a proof machine proving nothing. This is the producer half.\n\nanchorJob (05:00 UTC, an hour after FG-1, same crash-honest shape) folds\neach UTC day of gold_ledger into one Commitment per asset via\n@flashylabs/ledger 0.8.0's merkle domain: FG and all four commodities in\nthe same trees, stored append-once in ledger_anchors. A recompute that\ndisagrees with a stored anchor throws ANCHOR_MISMATCH and never\noverwrites - history edited after publication is the event the whole\nsystem exists to make loud. Entries stream cursor-paged on publicId,\nwhich is also the tree's sort key, so nothing re-sorts in memory; past\ntwo million entries per (day, asset) the job refuses rather than commit\na partial statement.\n\nSix public routes open the read surface: circulation, entries, one\nentry, anchors, per-entry inclusion proofs, and the latest invariant run\npublished verbatim - FAIL as loudly as PASS. Money is anonymous, glory\nis named: every shape is keyed by publicId and the privacy test walks\nthe results for a customer id.\n\nThe merged wiring allowlist shrank by one: this branch wired quest\nrotation, and the shrink-only gate noticed before a human did.\n\n32 new tests. The append-once guard was proven load-bearing by sabotage:\nguard disabled, suite red, guard restored.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "3fa20a18bdc83e20589ee242c5400fa433c3842b"
      },
      "digest": "474d16b9b23fa662008ea5b045e9ff2ef721f2a4dabe4eff3aec56a652fdc0c0"
    },
    {
      "id": "ship/claimyour.gold/55f01447332b",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T21:54:12+00:00",
      "kind": "feature",
      "title": "Record the ecosystem architecture decisions and the boardroom set",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Six artifacts architect the whole: the charter, a page-by-page web\natlas, a pocket atlas for the mini app and bot, and deep dives on the\nsettlement economy, the social ladder and the glass ledger.\n\nThe decision that reframes the earlier screen designs: no new tabs,\nanywhere. The portal's six (Home Earn World Crew Compete Profile) and\nthe mini app's six (Home Hunts War World Invite Profile) already carry\nthe civilization's meanings - the settlement becomes the World tab, the\nbarn joins Home, raids rebuild in place under Compete, the war room\ndeepens crew/war. The screens canvas's invented top nav is superseded;\nits visual language stands.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "55f01447332b4e085b6832692b170eac791c79de"
      },
      "digest": "3d5a2aac38d14b8d9c127eaea566f0cb76d99b4a3e8913686e93499b6931de9b"
    },
    {
      "id": "ship/claimyour.gold/a90d0abc14c6",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T21:20:03+00:00",
      "kind": "feature",
      "title": "Answer the Academy question: not finished, and deletion is blocked on DNS",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A1 is done - zero Academy services exist only in this repo. What remains\nis not the code: flashy.academy production traffic is hostname-rewritten\nand served by this repository's middleware, so deleting the 134 Academy\nfiles today takes down the live academy site. The cutover sequence is\ndeploy flashy-academy, move DNS, then cut the ten remaining import\ncouplings and three direct Prisma readers, then delete.\n\nOne coupling dissolves for free: hunter-engagement imports the\ncivilization-age recompute, which the XP landing retires - sequence the\ndeletion after that merge rather than writing an HTTP call that would be\ndeleted a week later.\n\nRepo hygiene is clean against every CLAUDE.md rule: no secrets, no\nconsole usage outside the client error boundary, every 0.0.0.0 hit is a\nguard against it rather than a use of it.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "a90d0abc14c679f962b1aa4e9556803507d5ee90"
      },
      "digest": "96682f5301f13ef8aa21da92d63dcfa941cdfdff22db6f70ac006af4fd74076e"
    },
    {
      "id": "ship/claimyour.gold/ebc36c51b381",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T19:42:43+00:00",
      "kind": "feature",
      "title": "Audit the civilization layer: 188 services, 17 unreachable",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The two the whole vision rests on are among them. buildingService has\nnine building types, five levels, full cost and yield maths and a\nBuilding table, and no page, route or job imports it - nobody has ever\nconstructed anything. raidService is imported only by its own resolution\njob, so the resolver runs and the initiator has no caller.\n\nThree structural holes sit behind them: City has no level and no\nresource stores, so there is nothing to spend commodities on; buildings\nbelong to hunters rather than places, so a city is a leaderboard bucket;\nand no job collects the daily yield the building definitions describe.\n\nAdds scripts/audit-civilization-reach.ts, which computes the same\ntransitive-import reachability that check-job-wiring does but over the\ncivilization services. Reports rather than gates: a gate that starts red\nteaches people to ignore it.\n\nThe brief also sharpens the vision to five tiers each owning one scarce\nthing, specifies the four public read endpoints and the anchor job that\nwould make flashynetwork read live rather than fixtures, and separates\nthe dev-agent service from the hunter-facing agent concept that would\notherwise collide with it.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "ebc36c51b38107373c70fdf94e70e9884fe16955"
      },
      "digest": "725a9558d0473e3d5122e41b772655d25041510fb13519818e4b66d7a2d8bfa3"
    },
    {
      "id": "ship/claimyour.gold/09569f979898",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T14:18:19+00:00",
      "kind": "feature",
      "title": "Audit the estate, answer the five decisions, and say where we are",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Branch states measured with the content test from branch-audit-truth\nrather than ancestry: of 116 branches, 28 have landed, 11 carry work and\nmerge cleanly, and 77 are conflicted.\n\nThe finding above the technical ones is that three separate efforts\nfound the same duel bug, the same dead quest rotation and the same\nunwired jobs. Nobody was wrong; everybody was alone. My own work is the\ncase study - a ledger 0.3.0 that was already 0.4.0, twelve XP commits\nalready landing elsewhere, a nightly invariant that shipped three days\nearlier.\n\nRecommendation: merge the eleven, declare the seventy-seven dead, sign\nthe CYG-LED criterion, ship the growth surfaces while waiting, and build\nthe civilization layer after. A product with 1,079 API routes and a\nviral coefficient of 0.34 does not have a feature problem.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "09569f9798986929b844851777623d134366d7bf"
      },
      "digest": "a1d33c4e735b4ec81e9b62ebd4b84888481a62ad309549ea7214d1a19a2e95c2"
    },
    {
      "id": "ship/claimyour.gold/4f10c22cfad7",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-27T14:12:02+00:00",
      "kind": "feature",
      "title": "Fold commodities into the invariant that already publishes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "FG-1 landed on main while this branch was in flight and does the same\njob better: it writes every run to ledger_invariant_runs as evidence\nrather than leaning on a job heartbeat, and it passes only when every\ncustomer reconciles rather than when the totals net out. Offsetting\nerrors net out too.\n\nSo ledgerInvariantService is deleted and the commodity fold moves into\ninvariantRunService. One run proves both halves; a separate commodity\ninvariant would be a second thing to remember to look at, and the one\nnobody opens is always the one that was failing.\n\nA commodity fault fails the run on the same terms as a gold one. An\nunseeded commodity asset does not: that is a migration in progress, and\npublishing it as a FAIL would make the public record say something false\nabout the gold. Only the missing-asset error is swallowed — any other\nread failure reaches the run rather than being absorbed into a shrug.\n\nMerged main, which needed one resolution: main repointed the ledger doc\nto flashynetwork.com but reverted the package name to the fork's\n@flashy/ledger. Kept the new domain and the real package name.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "4f10c22cfad7a22041eb5f6b0da71a192499d2a0"
      },
      "digest": "be049f6e53800ded86bd75c1b5bd633b85c52528c1f4bfa2282e79833b71b3e0"
    },
    {
      "id": "ship/claimyour.gold/29a9fe5af85b",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-21T16:20:15+00:00",
      "kind": "infra",
      "title": "Migrate the commodity assets in place rather than failing them",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The four Asset rows already exist. prisma/seed-assets.ts has created\nwheat, wood, stone and iron since before commodities were on the ledger,\ntyped LOYALTY_POINT because they only backed marketplace escrow then.\n\nThe seed script would have reported all four as wrong-shaped and refused\nto touch them, which is a false failure: the type label is not in the\nentry hash and does not change how amounts are read. It now retypes them\nunder --write, and prisma/seed-assets.ts writes COMMODITY on update as\nwell as create. No asset id moves, so every chain stays verifiable.\n\nWhat it still refuses to touch is the genuinely unsafe: wrong decimals,\nwrong tenant, an inactive row, or isDefault - which would make postEntry\nroute Flashy Gold into wheat.\n\nTesting guide updated: the read:packages caveat it opened with is gone,\nsince main now resolves the ledger and the whole suite runs green.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "29a9fe5af85bbc397dc819293702e07e30d95f02"
      },
      "digest": "58945e4098f8fcacf45ace196174c2c29093fbdd6c62eca50c596ec2795d41ce"
    },
    {
      "id": "ship/claimyour.gold/cce35bb4f3e5",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-21T16:17:23+00:00",
      "kind": "infra",
      "title": "Put commodities on the same books as the gold",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "GoldLedger has been multi-asset since it was written, so a commodity is\nfour Asset rows and entries in the table that already exists rather than\na parallel ledger with a second hash chain to keep in step.\n\npostCommodityMovement decides sufficiency for every asset before writing\nany entry. The failure that prevents is the partial one — wood debited,\nstone found short, hunter left poorer with nothing built — which arrives\nweeks later as a support ticket rather than as an error. Per-asset keys\nderived from the caller's mean a retry completes the legs that did not\nland instead of paying the ones that did a second time.\n\nIt lives in src/ledger/ beside postEntry because it is a ledger writer\nand the rule banning direct gold_ledger writes exempts that directory. A\nwriter that earns its exemption by structure is one a reviewer can find.\n\nNot written through postEntry because postEntry reads and writes\nwallet.goldBalance whatever assetId it is handed, so a commodity posted\nthrough it would credit a hunter's Flashy Gold wallet with wheat. That\nlatent bug is written up rather than routed around.\n\nThe nightly invariant now proves both halves on one run, and folds\ncommodities even when the gold half has already failed.\n\ngrantResources swallowed every pipeline error and reported success\nfor a credit that never landed. It now throws.\n\nNothing calls the writer yet: SP-6-D4 keeps the money path closed until\nCYG-LED exits, so this lands ready and inert.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "cce35bb4f3e56191ce40ed292932f2635c81f162"
      },
      "digest": "9fb0f10c5e20818ee27e6d840eb4de1fa9509309e72901b5cedc2bd354165784"
    },
    {
      "id": "ship/claimyour.gold/1016391f5e43",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-21T15:56:29+00:00",
      "kind": "docs",
      "title": "Write up the four findings for whoever merges the XP ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Rather than carry a duplicate branch that would collide, the differences\nfound while rebasing are recorded with the exact diffs: a vacuous\nskill-gate assertion, the missing sourceRef key derivation that leaves\ncross-product reports unretryable, the fire-and-forget crew-war award,\nand a note that ledger 0.5.0 widened EntryKind so the adjustment kinds\nnow typecheck.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "1016391f5e437dcc0b0fb13224b2e3cef2b626c0"
      },
      "digest": "330f277d912c4509755136c270466dd4a812431e62a00c437a8e1fbb9ffb0d1c"
    },
    {
      "id": "ship/claimyour.gold/9b7167b6d142",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-21T15:55:49+00:00",
      "kind": "fix",
      "title": "Back the duplicated XP landing out of this branch",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A branch audit found claude/xp-ledger-landing already carries the\nExperience Ledger, squashed onto a newer main and bumped to ledger\n^0.4.0. My rebase of the same twelve commits was a parallel landing of\nidentical work that would have collided with it at merge.\n\nThe two branches overlapped on exactly three files. Everything else has\nbeen reverted to main; the three were hand-edited to keep the\nnon-XP work and drop the XP additions:\n\n  - package.json — kept check:job-wiring and audit:war-escrow, which the\n    merge resolution had dropped along with the rest of the file\n  - prisma/schema.prisma — kept JobHeartbeat, removed the XP models and\n    the XP-6 requiredSkills field\n  - crewWarResolutionService — kept the awaited payout and the prize-pool\n    distribution, removed the XP award\n\nAlso drops my LEDGER_KIND mapping: ledger 0.5.0 widened EntryKind to\ninclude MIGRATION and DECAY, so the upstream answer is to store the\nproduct kind directly and mapping it now would write the wrong value.\n\nThree fixes this branch had that xp-ledger-landing still needs are\nwritten up in docs/xp-ledger-landing-followups-2026-08-21.md rather\nthan carried here.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "9b7167b6d14281838022626dccfcd1861744f797"
      },
      "digest": "2f60f431dd999a78924ad69462611086ea5da88abdc23cedb0cd2ebec99adcb5"
    },
    {
      "id": "ship/claimyour.gold/e28b708be3c3",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-21T14:24:43+00:00",
      "kind": "docs",
      "title": "Recommend the raid loop, and flag the alliance-raid gold mint",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "allianceRaidService credits raiderGoldDelta * 2.0 to two captains via\npostEntry with no debit anywhere in the file. It is reachable from a\nlive portal route, and Flashy Gold is redeemable, so it is an uncapped\nmint on a user-triggered action.\n\nThe recommendation for the daily-return loop is that the losable thing\nmust not be the redeemable thing: yield accrues to a raidable barn and\nmoves to a safe capped vault only when a hunter shows up, so showing up\nis the defence. Flashy Gold is won from the house and spent on shields,\nnever taken from a player — which is also what keeps the brand-funded\nreward pool a media buy rather than a PvP casino.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "e28b708be3c3424ce818ef800355d24d6c15638d"
      },
      "digest": "d36c5f894b548693c5569563e32495ffb5ddb4a2b8731909843ef7216933d183"
    },
    {
      "id": "ship/claimyour.gold/1480fa3a2263",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-21T14:19:58+00:00",
      "kind": "infra",
      "title": "Derive the XP idempotency key from sourceRef on the engagement boundary",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A cross-product report that carries a sourceRef can now be retried: the\nservice that owns the hunter record builds the canonical key from\n(sourceProduct, activity, sourceRef, customerId) rather than handing\nevery caller the convention. Callers that send neither a key nor a\nsourceRef still get a random one and a loud warning.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "1480fa3a22630494a9ccf4d9af73a6c6a6be14ef"
      },
      "digest": "d4a85df3e6613914d52b1d68863ab056ab4a2c767504e7062588d1871c8e09ce"
    },
    {
      "id": "ship/claimyour.gold/a81085adb6f8",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-21T14:13:39+00:00",
      "kind": "infra",
      "title": "Point ClaimYour.Gold at the canonical ledger and fix the gating fixture",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The XP branch depended on @flashy/ledger 0.2.0 as a vendored tarball.\nThat package is a fork: it branched before the tenant-isolation work and\nshipped under the old scope with the same version number as the real\n0.2.0 and different contents. Its experience domain now lives in\n@flashylabs/ledger 0.3.0, so the tarball is gone and every reference\nmoved to the canonical name — which also settles the open scope question\nin TECHNICAL_ROADMAP.md SP-6-0.\n\npostXpAdjustment took 'MIGRATION' | 'DECAY' as its ledger entry kind and\nneither is one, so the branch could not have compiled against either\npackage. Product kinds now map to ledger kinds; the mapped kind is both\nhashed and stored so a row can be re-hashed from its own columns, and\nthe product kind survives on metadata.adjustmentKind.\n\nquestSkillGating asserted the gate by checking rewardLedger was empty.\nNothing writes rewardLedger any more — the payout moved to postEntry —\nso the assertion passed whether the gate held or not. The fixture now\nmodels the real path and asserts against goldLedger.\n\npackage-lock.json names 0.3.0 without an integrity hash because that\nversion is not published yet. Merge flashy-ledger first, then run\nnpm install here to regenerate it.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "a81085adb6f89a94e16641e1eac4e934cbde2e93"
      },
      "digest": "844ef2ed3aa2e7d8b47d6ce112df53ac2c0c050b672a84326a2756f6a5258057"
    },
    {
      "id": "ship/claimyour.gold/992b683bc547",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T21:24:38+00:00",
      "kind": "feature",
      "title": "Add the testing guide for the work landed this engagement",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Covers what runs without a database, what runs read-only against\nproduction, which admin pages are live and how to read them, the manual\npasses worth doing on the wager fixes, and the five decisions still\nopen.\n\nStates plainly that npm ci fails without a read:packages token for\n@flashylabs/ledger, so 47 suites fail on that one missing module and CI\nis the first real verification of the ledger paths.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "992b683bc547dfc29c6dff32422a394713ac5437"
      },
      "digest": "ca93fec1db83b272462a3cca364fea6be3a4ba974aa4622817c735dc4d92805f"
    },
    {
      "id": "ship/claimyour.gold/0d5da420c3fd",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T21:23:22+00:00",
      "kind": "infra",
      "title": "Wire the ledger invariant and land the supply-model recommendation",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "reconcileAllBalances() has never had a caller. CYG-LED exits when the\ninvariant has been green for 30 consecutive days, so the clock on the\ngate that blocks the entire money path had never started.\n\nrunLedgerInvariant() wraps it and throws on drift, a chain break or a\nsign anomaly, so the job registry records a failure and the 30-day\nstreak is readable straight off the heartbeat row rather than out of a\nreport nobody opens. Registered as ledger-invariant at 03:00 UTC.\n\nAlso adds the supply-model recommendation answering the open decision\non who owns the economy's numbers: the sink is 16,275 units against an\n85/day faucet that only exists after the sink is paid, and after\nbuild-out there is no sink at all.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "0d5da420c3fd762cbdb080575fe9ea5c0e7161c3"
      },
      "digest": "e16b1b19f7ac9dc1afc3aaa3e20c1619bafa6ff0763e052653cc0f416d3fd3fc"
    },
    {
      "id": "ship/claimyour.gold/ab0a8330473d",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T21:07:17+00:00",
      "kind": "infra",
      "title": "Reconcile the civilization roadmap against the canonical group roadmap",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Audited 104 remote branches, the six briefs from this engagement, and\nTECHNICAL_ROADMAP.md v1.1 to answer whether the civilization direction is right\nand in what order to build it.\n\nThe direction holds. The ordering was wrong.\n\nThere is a canonical cross-repo roadmap dated 2026-08-18 with task IDs, a\ncritical path and two binding gates, and I had not read it. Several things\nproposed here turn out to be items already on it — the job registry enables\nCYG-OPS-1's worker split, the wiring gate is CYG-OPS-2, the duel settlement fix\nis named in CYG-LED-3, the war-bet guard touches one of CYG-LED-2's 102\ndirect-write sites, and commodities-as-ledger-assets is the same move SP-5\nalready commits to for XP.\n\nWhat must yield: SP-6-D4, from board memo BM-2026-08-16, prohibits publishing\nanything on the money path until CYG-LED exits — invariant green 30 consecutive\ndays, integer balances, zero direct wallet writes. Registering commodities as\nassets is money-path work, so the civilization economy starts after that gate,\nnot in two weeks.\n\nBranch audit: the alarming \"thousands of commits ahead\" counts are history\ndivergence, not content. main is ahead on every measure — 5,147 files against\n5,028 on the largest branch, 920 services against 918 — and no branch carries a\nservice main lacks or any civilization UI, so the built-but-never-connected\nfinding survives.\n\nTwo things worth knowing from it. production is 40 commits ahead of main and\nzero files differ: all merge commits, no drift. And the Experience Ledger branch\nthat roadmap v1.1 records as \"2,436 behind\" measures 78 behind today — a rebase,\nnot a rewrite. SP-5 should be re-costed before anyone decides to rebuild.\n\nAlso corrects the delete-the-city-cluster advice in the WS-3 triage list, and\nnotes the parallel track: the growth loop touches no money path and should not\nwait behind the gate.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "ab0a8330473da2182a3b8bfd8266d52a15df8077"
      },
      "digest": "0377cdbf6bb5b342027e6d6e28cb86e12030c780460a001a9b171449828c3769"
    },
    {
      "id": "ship/claimyour.gold/9cbd28965deb",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T16:28:27+00:00",
      "kind": "other",
      "title": "Quest rotation actually rotates — 83 -> 81",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The oldest open finding in the estate. docs/earn-systems-audit-2026-07-21.md\ncalled it the highest-severity item in Quests: scheduleQuestRotationJobs() and\nstartQuestRotationWorker() were exported and called from nowhere, so\nDAILY/WEEKLY quests never flipped isActive in production despite the whole\nschema, enum and worker existing to support it. A month later it still had not\nrun once.\n\nRotation now lives in src/services/questRotationService.ts and runs from the\nregistry, hourly, with a heartbeat. Hourly beats the old midnight cron: a quest\nwhose window opens at 14:00 goes live within the hour rather than the next day.\nEvery write is an updateMany filtered on the state it changes, so a second run\ninside the same window is a no-op, which is what makes hourly safe rather than\nmerely tolerable. Close-then-open ordering, so a quest whose window has passed\nis never visible beside its replacement.\n\nsrc/jobs/questRotationQueue.ts is deleted rather than wired. It duplicated the\nlogic behind BullMQ repeatables, and it built its Queue with\n`connection: redis!` at module scope — importing it without Redis throws, where\nevery sibling queue returns null. Its one-shot expire/activate helpers had no\ncallers. Nothing is lost and one scheduling mechanism survives instead of two.\n\nTwo entries examined and deliberately not wired, recorded in the plan doc:\n\n- The DM senders — ghostReactivation, winback, goldenInviteReset (which DMs\n  every customer with a telegramId), socialProofBroadcast, anniversaryDm,\n  referralRace. All wait on the Season 1 consent answer.\n- referralExpiryJob expires nothing: its worker calls findGhostRecruits(), logs\n  the count and discards it, and that function reads every ACTIVATED referral\n  unbounded with a goldLedger.findFirst per row. Wiring it as written buys an\n  N+1 across the referral table and no behaviour. Redesign, not wire.\n\nVerification: 4 new tests; tsc clean on every file touched; lint clean; wiring\ngate green at 81.\n\nCo-Authored-By: Claude Opus ",
      "refs": {
        "commit": "9cbd28965deb5e6756d34aa8780d4407d4d542a0"
      },
      "digest": "66791900512943d62e35faeb2f35f691f82972d1daac508f3c5030ccdeb61460"
    },
    {
      "id": "ship/claimyour.gold/8ba53598ca49",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T16:15:27+00:00",
      "kind": "feature",
      "title": "Close the crew war prize pool path; stop taking bets that cannot settle",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Prize pools (severity 1, #4 in the war audit) — fixed.\n\ndistributePrizePool is now called from crewWarResolutionService, awaited, after\nthe standard war reward loop. That is exactly where crewWarPrizePoolService's\nown header asked to be called from when it was written; nothing ever did, so\npaid crew wars accumulated a pool from real Stars purchases and never paid it\nout. Safe to replay twice over: the function no-ops once rakeCaptured is set,\nand each member share carries war-prize:<warId>:<customerId>. Unpaid wars and\nzero pools return zeros without touching anything.\n\nScheduled wars (severity 1, #2 and #3) — intake closed, settlement left alone.\n\nThe root cause is larger than a missing settlement call: a ScheduledWar is\ncreated and never changes. There is no scheduledWar.update anywhere in src/, so\nstatus stays PENDING forever and warId — \"set when war starts\" per the schema —\nis never set. The war never starts, never links to a CrewWar, never produces a\nwinner.\n\nBoth war-bet implementations gated only on status, so stakes were accepted on\nwars whose time had passed months ago and which can never settle. Both now\nreject with BETTING_CLOSED once scheduledAt passes, matching the guard\nplacePrediction always had. An hourly scheduled-war-watch job reports overdue\nwars, open bets and Flashy Gold at risk to /super/jobs.\n\nSettlement is deliberately not wired. Choosing between building the missing\nlifecycle and refunding every open stake is a product decision, and wiring\nsettleWarBets blindly would be worse than leaving it: its pari-mutuel maths\npays bet/winnerPool * totalPool, so a crew nobody backed makes winnerPool zero,\nevery payout zero, and every bet settled — the pool is confiscated, not\nreturned. It has no refund branch.\n\nTest fixture defect found while wiring the prize pool.\n\ntests/services/crewWarService.test.ts mocked crewHuntQueue.add as a bare\njest.fn() returning undefined, while the resolution path does\n`void queue.add(...).catch(...)`. Reading .catch of und",
      "refs": {
        "commit": "8ba53598ca498069d49e15123692501459b97ee5"
      },
      "digest": "a850b2a5da2633c350b7651225146c0e863644df09ef17bc4808ee653dc3c335"
    },
    {
      "id": "ship/claimyour.gold/0382e9ef4b3b",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T15:44:31+00:00",
      "kind": "other",
      "title": "WS-1 job registry and heartbeat; wire the staked-duel settlement path",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "WS-1 — proof that a job ran, not an inference from a passing test.\n\nsrc/jobs/registry.ts holds job descriptors — id, owner, kpi, interval, an\noptional UTC hour/day gate — and runJob() wraps each run to upsert a\nJobHeartbeat row: started, finished, duration, structured result, last error.\nrunJob never throws, because a rejection escaping a setInterval callback takes\nthe worker process down, and because a job that failed must still leave\nevidence. A successful run clears lastError, so a populated error always means\nthe most recent run failed.\n\njobHealthService joins the registry against those rows and derives state:\nran / stale / failing / never-ran. Stale is two missed windows, and the window\ncomes from the gate (daily for hour-gated, weekly for day-gated) rather than\nthe tick interval, so a daily job is not called stale six hours in. Served at\n/api/v1/super/jobs, rendered at /super/jobs. Every state carries a word as well\nas a colour.\n\nThe registry does not swallow worker.ts whole. Jobs migrate one at a time and\nnew jobs start there; the 104 hand-written imports are the backlog, visible on\nthe page. Rewriting the file that starts every production worker on the same\nday as the audit that prompted it is not a trade worth making.\n\nWS-3 first entry, 83 -> 82 — the staked-duel money path.\n\nAccepting a staked duel debits both players and, until now, nothing in the\nrunning system could pay them back: resolveStakedDuel's only caller was\nduelResolutionJob, which no module imported, and that job's enqueue helper had\nno callers either. Now worker.ts starts the queue worker, acceptChallenge\nenqueues the settlement at the duel's endsAt, and an hourly\nduel-settlement-sweep re-derives the obligation from the goldLedger — the one\ndurable record — and settles what the queue missed. A failed enqueue no longer\nmatters and no longer fails the accept; the sweep is the guarantee, the queue\nis the fast path.\n\nSettlement is idempotent through postEntry's duel-stake-win / duel-stake-refund\n",
      "refs": {
        "commit": "0382e9ef4b3b4abfbe256ccd4e3cacf4d50ee5b5"
      },
      "digest": "b27922585f47ba51cc0b963eb87d8770477a509ea27d3e258b1cc9df7befbc3b"
    },
    {
      "id": "ship/claimyour.gold/699888b6b6b2",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T14:59:51+00:00",
      "kind": "other",
      "title": "Week 1: job wiring gate, cohort viral coefficient, war escrow audit",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "WS-2 — the CI gate that makes the orphan class impossible to grow.\nscripts/check-job-wiring.ts resolves the import graph under src/ and treats a\njob module as wired when it is reachable from src/jobs/worker.ts or from any\nsource file outside src/jobs/. Everything else is an orphan and must be on the\nallowlist in scripts/job-orphans.ts, which only shrinks. Wired into ci.yml as\nits own step so a failure reads \"job not wired\", not \"lint error\".\n\nThe stricter method corrects the earlier count: 83 orphans of 181 job modules,\nnot 73 of 179. The first sweep matched basenames as strings, missed\nsrc/jobs/os/, and could not see dead chains — viralFlywheelJob is imported only\nby viralFlywheelScheduler, which nothing imports, so both are dead and only one\nlooked it. The boardroom brief carries the correction.\n\nWS-4 — company k, computed from data that already exists.\ngrowthMetricsService derives, per weekly invite cohort: invites sent, invited\nsignups, invited activations, activated hunters (Customer.firstClaimedAt),\nk = invited activations / activated hunters, and median invite-to-activation\ncycle time. Referrals carrying fraudFlags are excluded from every count and\nreported separately, so an inflated k is visible rather than quiet. Cohorts\ninside the maturation window are flagged rather than read as final.\n\nCohorts are keyed by the week the invite was sent. Signup-week cohorting would\nneed the referrer id set pulled for every week; invite-week is computable with\ncount() queries and answers the operational question directly.\n\nDoes not touch viralCoefficientService, whose snapshot divides lifetime\nsocialShare counts with no window and no per-user denominator, is called only\nthrough an orphaned scheduler, and writes a table its own read route cannot\nfind. Retiring it belongs with the WS-3 triage.\n\nServed at /api/v1/super/growth/cohorts — the sibling /api/v1/super/growth\nalready serves the viralAnalyticsService snapshot and is untouched — and\nrendered at /super/growth with the ex",
      "refs": {
        "commit": "699888b6b6b2bfc7af53218ff25ad3eefcc2d8f6"
      },
      "digest": "944200a3f93cefce61e612752de130449297bec85c480b5633e0a7e139ee5fb0"
    },
    {
      "id": "ship/claimyour.gold/6fbb363c767d",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T14:04:27+00:00",
      "kind": "other",
      "title": "War systems audit and the growth-surfaces design brief",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "War audit traces every combat and wager surface back to a path reachable\nfrom the running worker or an API route. Four severity-1 findings, all in\nthe wager layer — Flashy Gold is taken in and no wired path pays it out:\n\n1. Staked duels. POST /api/duel/live/[duelId]/accept debits both players\n   (sourceType DUEL_STAKE). The only payout is resolveStakedDuel(), called\n   only from the orphaned duelResolutionJob; enqueueDuelResolution() has no\n   callers at all. Two independent breaks in one path.\n2. Scheduled-war bets. warBet rows are created from portal routes;\n   settleWarBets() has no caller.\n3. Scheduled-war predictions. placePrediction() is reachable;\n   settlePredictions() is not, and nothing picks a winning crew for a\n   ScheduledWar.\n4. Crew war prize pools. distributePrizePool() has no caller despite its\n   own header naming the wire-in point.\n\nCore crew-war loop is healthy: matching, resolution, mid-war nudges, hunter\nduels, duel bets and crew-war predictions all run via crewHuntWorker.\nDormant: country, faction, city and flash-raid modes, plus tournament\nseeding. Three duel resolvers and two tournament systems exist; one of each\nis wired.\n\nIncludes the three reconciliation queries needed to size real exposure\nbefore anything ships on the wager layer.\n\nDesign brief specifies six deliverables against the shipping token system,\nwith states, slot rules, Satori constraints, acceptance criteria, handoff\nrequirements and three review gates.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "6fbb363c767de329dc944c7e838abbe79ec25b69"
      },
      "digest": "06548e5d7139a3f0bbc2187408a8b4300a44544bd03f251dbf06028e7ecec767"
    },
    {
      "id": "ship/claimyour.gold/3347853856ae",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T13:42:35Z",
      "kind": "other",
      "title": "Technical recommendation: job registry, wiring gate, real k, share loop",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Six workstreams in dependency order, companion to the 2026-08-20 boardroom\nbrief. Four of the six need no design and can start immediately.\n\nTwo findings that shape the plan:\n\n- viralCoefficientService.snapshotViralCoefficient() computes k from\n  lifetime socialShare counts with no time window and no per-user\n  denominator, then writes it into a date-keyed row. It is called only by\n  viralFlywheelJob via the orphaned viralFlywheelScheduler, whose docstring\n  claims worker.ts calls it hourly. /api/internal/viral-coefficient reads\n  ViralSnapshot, which nothing writes. Recommend computing cohort k from\n  Referral (createdAt/activatedAt/status/referredId) instead — the same\n  substrate kFactorService already uses — and retiring the old path.\n\n- All 61 OG image routes declare fontFamily 'sans-serif' and none supplies\n  fonts to Satori, so every share card that reaches a group chat renders\n  off-brand; 2 of 61 set an emoji provider.\n\nAlso specifies the four design asks (share card system, /s/[slug] landing,\nMini App first run, PWA icon set) and the surfaces not worth designing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "3347853856ae33a577bde9ada716fbfdfd2206e5"
      },
      "digest": "8da461d557a166d14e955424a604bc04470bdf9e9450f35134313766b226d03f"
    },
    {
      "id": "ship/claimyour.gold/a212388a5a15",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T13:24:36Z",
      "kind": "other",
      "title": "Boardroom brief: distribution over surface area (2026-08-20)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Answers the four questions on the table — webapp vs native, virality,\ninstitutional-grade code volume, and solo-plus-AI feasibility — against\nmeasurements taken from the working tree rather than from prior docs.\n\nHeadline finding: 73 of 179 modules in src/jobs/ are imported by nothing\n(41%), 18 of them with passing test files. The orphan set is\ndisproportionately the growth machinery — viralFlywheelScheduler,\nreferralRaceJob, winbackJob, ghostReactivationJob, questRotationQueue and\nothers. questRotationQueue was already reported orphaned in the\n2026-07-21 earn-systems audit and is still orphaned.\n\nRecommends: no native app this quarter, a two-week growth-feature freeze,\na k dashboard, wire-or-delete on all 73 orphans, and a CI gate that fails\nwhen a job module is imported by nothing but its own tests.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "a212388a5a15d486e40067e9cd3776e9cb7620a3"
      },
      "digest": "1891991d09dfc8919fb1d791709c828139e5a7a29a6e719ea3c0f3f7493664bd"
    },
    {
      "id": "ship/claimyour.gold/25e20850c54a",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-20T01:58:54Z",
      "kind": "fix",
      "title": "Resolve quiz article links at render time instead of hardcoding a 404",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Every quiz page and its post-fail retry prompts linked to\nclaimyour.gold/learn/{articleSlug} unconditionally — but module article\nslugs live in three different places: some are portal Learn articles,\nsome are Academy blog posts, and some have no published article at all.\nFor the latter two categories every \"read the article first\" link was a\nlive 404 (reported from the What Is Real-World Value? quiz on\nflashy.academy).\n\nThe page now resolves the article's real home server-side — portal Learn\nif published there, the Academy blog otherwise — and passes the resolved\nURL to QuizClient. When no published article exists anywhere, the links\ndon't render and the copy adjusts, rather than pointing a learner at a\npage that isn't there.",
      "refs": {
        "commit": "25e20850c54a6e531bd5b56e0fe03fd5d9bb949d"
      },
      "digest": "ee4f8908f8baf77d996ff4ab0ca6b4c3b52360403de8dacb69aa06ecf16aedad"
    },
    {
      "id": "ship/claimyour.gold/7aa3f94f6068",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-19T21:08:40Z",
      "kind": "fix",
      "title": "Fix the robots resolution: the static file is the contract, robots.ts was the dead code",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The SEO foundation suite reads public/robots.txt directly and asserts\nits disallow set — the static file, with its 20+ rules, is the richer\nartifact and the test-enforced contract. The previous commit resolved\nthe shadowing the wrong way around by deleting it in favor of\nsrc/app/robots.ts (which carried only two disallows and, being\nshadowed, had never served). Restored the static file verbatim and\ndeleted robots.ts instead: same one-source outcome, the right survivor.\n\ntests/seo robots assertions pass locally; the suite's remaining local\nerror is the private @flashylabs/ledger registry package unavailable in\nthis environment — resolved on CI, as the prior run shows.",
      "refs": {
        "commit": "7aa3f94f606854afe572c9f4048fd8e77b73c4b7"
      },
      "digest": "305b4f02264c2d3db836007f73e3a2c0923aad6c5da93313c238c60857263cd7"
    },
    {
      "id": "ship/claimyour.gold/c5f2a1c9c3dd",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-19T20:57:03Z",
      "kind": "feature",
      "title": "Merge the group-mesh branch: Flashy Gold wording, group.json, llms.txt group map",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Content and machine-surface changes only: homepage and OG metadata off\nthe forbidden \"real gold\" phrasing per this repo's own copy rules, the\ncanonical RWV-anchored backing sentence, this property's group.json, the\nllms.txt group section, and play-for-gold wording. The robots\nmodify/delete conflict resolved the right way around: main's updated\nrobots.ts (with /api/ and /academy/admin/ disallows) kept, and the\nstatic public/robots.txt that was shadowing it removed so the route\nactually serves.",
      "refs": {
        "commit": "c5f2a1c9c3dd566a07bf2038ac3e20e7f6d5142e"
      },
      "digest": "4a425fc64c23d7c2a38bb5a011dd651d31855871df0e15292ddc0453b5701801"
    },
    {
      "id": "ship/claimyour.gold/4c87ea7d4d2f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-19T18:09:24-04:00",
      "kind": "feature",
      "title": "SHIP-0: sync TECHNICAL_ROADMAP.md to canonical v1.1 (#59)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "flashyos has carried v1.1 (2026-08-18) since it shipped; this copy sat\nat v1.0 (2026-07-14). One canonical document, byte-identical in every\nrepo that carries it — drift between copies is how two repos end up\nexecuting different plans.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "4c87ea7d4d2f106a7807f126b28a5a82a505b391",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/59"
      },
      "digest": "19b0a82fa8e2bb5284e4b03aceced80fdf6ce0297d2962bb6119ddbd8e65e93b"
    },
    {
      "id": "ship/claimyour.gold/d00127c8e99c",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-19T17:39:01Z",
      "kind": "other",
      "title": "Regenerate lockfile for @flashylabs/ledger",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "d00127c8e99c997a97f890f5e18c626201c63702"
      },
      "digest": "4d8c6208c6799eadb87e9ee3598f4c2fa245c503dfa5bbabfc91e4dce667ed65"
    },
    {
      "id": "ship/claimyour.gold/8127f7f9fc79",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-19T17:20:59Z",
      "kind": "release",
      "title": "CUT-2: install @flashylabs/ledger from GitHub Packages, retire vendor/",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The vendored copy existed only because the package had nowhere to be\npublished from (vendor/flashy-ledger/README.md documented this exact\nreplacement). @flashylabs/ledger@0.1.2 is now genuinely on GitHub\nPackages, so:\n\n- package.json: file:vendor/flashy-ledger -> @flashylabs/ledger@^0.1.2\n  (the scope is @flashylabs, not @flashy — GitHub Packages requires the\n  npm scope to match the owning account)\n- imports renamed in postEntry, ratifyUnrecorded, and the postEntry test\n- vendor/flashy-ledger deleted, along with the Dockerfile's two vendor\n  COPYs, the runtime symlink caveat, and eslint's vendor/** ignore —\n  which also makes lint a viable CI gate again\n- npm auth: repo .npmrc carries only the scope->registry mapping; the\n  token reaches the Docker build as a BuildKit secret (written, used,\n  and removed inside one RUN — no image layer ever holds it), pulled\n  from Secret Manager by cloudbuild.yaml, which is now the required\n  build path since --tag builds can't carry secrets\n- scripts/build-and-push.sh reads the token from ~/.npmrc for local\n  builds; scripts/audit-extraction.ts updated to assert the new name\n\npackage-lock.json is intentionally NOT regenerated in this commit: the\nsandbox this was authored in cannot authenticate to GitHub Packages.\nRun npm install with a read:packages token in ~/.npmrc and commit the\nlockfile before merging — npm ci fails until then, by design.\n\nTypecheck clean; ledger tests 20/20.",
      "refs": {
        "commit": "8127f7f9fc79f011da2569c377ce88d82559fb3e"
      },
      "digest": "4bc28f607f62fa13b95529f60b58a144208d14ffd2200f0c9f4186d4c45ab59d"
    },
    {
      "id": "ship/claimyour.gold/c3820a67d685",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-19T16:10:03-04:00",
      "kind": "feature",
      "title": "Merge pull request #58 from FlashyLabs/claude/node-22",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Run on Node 22 — Node 20 is end-of-life",
      "refs": {
        "commit": "c3820a67d685872591942e5fffa9a08ce206c6a7",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/58"
      },
      "digest": "2f5cf4dad21568daf3b0c68cdde59c71854ddfcc83abc795ddb065d9840eeb7f"
    },
    {
      "id": "ship/claimyour.gold/e0aff6ab2257",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-19T16:07:41-04:00",
      "kind": "feature",
      "title": "Merge pull request #57 from FlashyLabs/claude/seam-4-service-identity",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "SEAM-4 Phase 1: one gate for service-to-service calls",
      "refs": {
        "commit": "e0aff6ab2257b7fa0b3756098fd74eccee7b0684",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/57"
      },
      "digest": "d9a21075cdbc4bf20294091dbb6b7ea8b8dc1c1ae8905a512be39115e2a4c32d"
    },
    {
      "id": "ship/claimyour.gold/9a44c7d7e93f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-19T15:12:07-04:00",
      "kind": "feature",
      "title": "Merge pull request #56 from FlashyLabs/claude/seam-3-integer-money",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "SEAM-3 Phase A: integer shadow column for the gold balance",
      "refs": {
        "commit": "9a44c7d7e93fb189af4c06c015947c3ec8871226",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/56"
      },
      "digest": "603709ba7265aa595aefcafeb32babb2530505a39a039b8b371e1003493ef813"
    },
    {
      "id": "ship/claimyour.gold/2dc3c7d151e3",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-18T21:55:21Z",
      "kind": "feature",
      "title": "LEARN-5: expose a portal summary for Academy's progress page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "New GET /api/v1/internal/portal/summary?customerId=<id> — the reverse\nof LEARN-2, same x-internal-key/INTERNAL_SERVICE_KEY boundary. Three\nfields (goldBalance, crewName, activeQuestCount), shaped by the one\nplace that's going to render them: the wallet/quest strip LEARN-6 adds\nto Academy's /academy/progress page.\n\nactiveQuestCount is the live public quest catalogue minus this\ncustomer's completions — quests still available to them, not a raw\ncount of everything in the catalogue. Reuses\nlistActivePublicQuests/getQuestData/getCustomerCrewWithName rather than\na new read path against the same tables.\n\nLower priority than LEARN-2 through LEARN-4 per the roadmap's own\nordering — a hunter who came from claimyour.gold already has the\nwallet one tab away; this closes the gap for a hunter who discovers\nAcademy first.",
      "refs": {
        "commit": "2dc3c7d151e3cdd8abc0e186cc7386b6959e4edc"
      },
      "digest": "54e7efaa193652fcd83e19ec921f46215e8207974cbc8881f0cc20c56a7886f8"
    },
    {
      "id": "ship/claimyour.gold/f2317c31db30",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-18T21:52:20Z",
      "kind": "other",
      "title": "LEARN-4: /portal/learn — the full track/certificate picture",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "New page at /portal/learn: every in-progress track (with percent\ncomplete), every certificate earned (linking to its flashy.academy\nverification page), and the rest of the active catalogue to start next.\nCYG's own page rendering CYG's own copy of the data — not an embed of\nflashy.academy and not a redirect to it, per the reasoning already\nwritten down for why those two shortcuts lose (cross-origin cookie/CSP\nheadaches for the iframe path; a bounce that risks landing signed out\nfor the redirect path).\n\nPulls from flashy-academy's new GET /internal/academy/learn-detail\n(added alongside this commit). Reachable from the dashboard's \"Continue\nLearning\" card (\"See all\") and from GlobalHeader's existing Academy nav\nentry — no new top-level nav item.\n\nUnlike the dashboard card, this page IS the point of the visit, so a\nfailed fetch renders an explicit \"temporarily unavailable\" state with a\nlink out to flashy.academy directly, rather than silently rendering\nnothing the way the dashboard card does on the same failure.\n\nCloses out LEARN-2 through LEARN-4, the higher-priority half of \"Learn,\nBoth Directions\" per the roadmap's own ordering. LEARN-5/6 (the reverse\ndirection — wallet/quest data on Academy's own progress page) are next.",
      "refs": {
        "commit": "f2317c31db30d6e66554a88592dfd4fc48a74c96"
      },
      "digest": "62751738bd2114cce6e55fcb9d2fe2691beceecfc6df58ef1022411792fa5c9c"
    },
    {
      "id": "ship/claimyour.gold/375e2b69c716",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-18T21:46:56Z",
      "kind": "feature",
      "title": "LEARN-3: show Academy progress on the portal dashboard",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds a \"Continue Learning\" card to /portal/dashboard, the highest-\ntraffic page in the product — the fix for the acceptance-test finding\nthat a hunter signing in from flashy.academy lands on a portal that has\nnever heard of Academy.\n\nlearnSummaryClient.ts calls flashy-academy's new GET\n/internal/academy/summary (LEARN-2) rather than reading Academy's\nPrisma tables directly — SEAM-4 already exists to stop the reverse of\nthat (Academy declaring models it doesn't own), and a dashboard card\nreading Academy's schema directly would be the same mistake run in the\nopposite direction, one migration undoing the other with no compiler\nand no contract to catch a breaking change on either side. Named\nlearnSummaryClient rather than academySummaryClient specifically to\nstay clear of the WS-4 academy-coupling eslint guard (no-restricted-\nimports on @/services/academy*), which is right to flag it by pattern\neven though this file is exactly what that rule wants — an HTTP call\nout, not a direct model import.\n\nBest-effort, matching PortalLayout's existing pattern for the\nactivation banner: the client returns null on any failure (unset env\nvars, timeout, non-2xx, network error) and the card simply doesn't\nrender — a second product's downtime must never take the dashboard\ndown. The card itself only shows when summary.hasActivity is true, so\na hunter with no Academy history sees nothing, not a dead end.\n\nNeeds FLASHY_ACADEMY_API_URL configured in Secret Manager/Cloud Run\nenv — INTERNAL_SERVICE_KEY is already shared between the two services.\n\nPart of \"Learn, Both Directions.\" LEARN-4 (/portal/learn, the full\ntrack/certificate picture) is next.",
      "refs": {
        "commit": "375e2b69c716dcf6cb59ca642d447a3438c2c0ce"
      },
      "digest": "bd3a4d982123b8404c0e09090eca9f052fdf295c5ecdedecfe2fbe4cef2f0972"
    },
    {
      "id": "ship/claimyour.gold/c1bd2c9f13bd",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-18T19:40:41Z",
      "kind": "feature",
      "title": "Merge claude/sso-0000-redirect-fix: fix SSO redirect to 0.0.0.0, add flashyid_ prefix",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "c1bd2c9f13bd7db4ce01b3a7587b0cc5f0ea6af1"
      },
      "digest": "23035298db618197bc0be1fa87c873330cb8a6f83ea964d8a871c9cfc52a0ec1"
    },
    {
      "id": "ship/claimyour.gold/b55596ef8282",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-18T18:21:35Z",
      "kind": "feature",
      "title": "Merge claude/email-primary-signin-fix: fix the ID-4 email sign-in dead end",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "telegramId truthy checks treated the \"email-only:<email>\" placeholder as a\nreal Telegram identity, so email-only accounts never got a session and two\nTelegram-only side effects fired against an id Telegram never issued.",
      "refs": {
        "commit": "b55596ef8282e3cdbb7b23d2eca9a9182b35cb53"
      },
      "digest": "720ed3d08bd88f2d9506a228e9f7045c6482596b790dd406a215e9b7af4c7159"
    },
    {
      "id": "ship/claimyour.gold/3eed18f067b6",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-18T18:11:44Z",
      "kind": "feature",
      "title": "Merge claude/github-repo-setup-8w9e4m: bot command scopes, /portal/handoff",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Publishes all 21 bot commands across three Telegram scopes instead of 8, and\nadds /portal/handoff, the return leg for sign-in from flashy.academy.",
      "refs": {
        "commit": "3eed18f067b65ef0e0a78e4316a04fdaff3a115a"
      },
      "digest": "6b8bc3f3ad76be0b91eb1172c22793fab4a0fa0db132f8025a0433327cf340d0"
    },
    {
      "id": "ship/claimyour.gold/8c63430be8b7",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-18T15:19:33Z",
      "kind": "feature",
      "title": "Merge claude/cyg-machine-surfaces",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "8c63430be8b7e54543b38709551dbaf16da2b045"
      },
      "digest": "65eb58fc048c6f4fb0b6acc347793309e1426d3957059619afbe3615e8854c2a"
    },
    {
      "id": "ship/claimyour.gold/1e33d1520977",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-18T15:19:33Z",
      "kind": "feature",
      "title": "Merge claude/dockerfile-npm-ci-fails",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "1e33d1520977d2ed0e5b1a3b2345680209e23c56"
      },
      "digest": "816e6110fb26081e6d4c076e450e24f5415718addfdfaac6a5a4ba8c437e7378"
    },
    {
      "id": "ship/claimyour.gold/5c62cf3e4c37",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-18T12:43:44Z",
      "kind": "feature",
      "title": "Merge: run lint in CI so the ledger write guard is enforced",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Until this lands the gate applies to one branch only -- GitHub runs the\nworkflow file from the PR's own branch, so a PR cut from main would not\nhave run lint. Merging is what makes it apply to everything cut from here.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "5c62cf3e4c378041e10712b7bf20323fbdf06b94"
      },
      "digest": "bf5efc98a9e58bf45b111e94757c092e3ac8b39f517966f91c44c20bfd2f9531"
    },
    {
      "id": "ship/claimyour.gold/b4b82b6988d4",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-17T23:35:03+00:00",
      "kind": "feature",
      "title": "Add inline skills card to portal profile self view",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The logged-in profile previously only linked out to the public Hunter\nRecord; the authenticated self-view API (GET /api/v1/portal/hunter/skills)\nhad no UI consumer. The new card shows Hunter Level, all five skill bars\nwith XP progress toward the next level, and recent XP events — including\nnegative adjustments the public page never shows.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "b4b82b6988d451d5f05e2b9523c84cbb023caec6"
      },
      "digest": "05ed0760a03ae7b6e86d03e5c2c0f64b7155da1e0975e8ecf15581763aaafbf9"
    },
    {
      "id": "ship/claimyour.gold/4c2fc6ee36c2",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-17T20:58:52Z",
      "kind": "feature",
      "title": "Close the campaign queue so the notify script can exit",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "campaignQueue is a module-level `new Queue(...)`, so importing the script\nopens an ioredis connection whether or not it is used. Nothing closed it, so\nthe event loop never emptied and the process hung after all the work was done.\n\nAs a Cloud Run job that presents as \"0 / 1 complete\" until the task timeout,\nlong after every message has been enqueued — an execution that looks stuck, or\nfailed, while having fully succeeded.\n\nClosing the producer does not touch queued jobs: they live in Redis and the\nworker is a separate process.\n\nscripts/broadcast-leaderboard-apology.ts has the same defect and the same fix\nis needed there.",
      "refs": {
        "commit": "4c2fc6ee36c2a5ba789575602512dfd3c78a9286"
      },
      "digest": "21ead1ffad88e1c3358e025d744c960b07e6c3ddaefcbbdf979a6c51429a4165"
    },
    {
      "id": "ship/claimyour.gold/054bca6f1fa1",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-17T19:10:20Z",
      "kind": "other",
      "title": "Re-enqueue failed deliveries on resume, not just pending ones",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A delivery the worker already SENT must not be handed to it twice, but one\nthat FAILED is exactly what a resume is for. Filtering to PENDING alone would\nstrand those customers silently — the same class of bug as the interrupted run\nthis resume exists to repair.",
      "refs": {
        "commit": "054bca6f1fa18bbd58e0d70e48c81743ccc70a69"
      },
      "digest": "d2ff10d4fc09404affae3fb0880a7499701656bf446269bbb04d4a48099c5cdd"
    },
    {
      "id": "ship/claimyour.gold/6f3a3ec9a0ea",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-17T18:32:05Z",
      "kind": "infra",
      "title": "Make the drift notification resumable, and stop the admin job ageing",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Three fixes, all found by running the correction for real.\n\nRESUMABLE NOTIFICATION\n\nThe first live send was interrupted after the paid cohort's 31 in-app\nnotifications were written and before a single Telegram message was enqueued —\nRedis is unreachable from Cloud Shell, and the queue degrades to a warning\nrather than an error, so the script kept going. The recorded cohort never\nstarted.\n\nRe-running was the obvious fix and would have sent 31 people a second notice\nabout money. So the script now resumes instead: segment and campaign are looked\nup by a name carrying the correction id and reused, delivery rows are created\nonly where absent (MongoDB has no skipDuplicates, and the unique index on\ncampaignId+customerId would abort the whole batch on the first collision), only\nPENDING deliveries are enqueued, and an in-app notification is written only\nwhere that exact title is not already present.\n\nThe unavailable-queue warning now says how many deliveries were left PENDING\nand that a later run will pick them up, rather than implying rows were created\nand the work was done.\n\nTHE ADMIN JOB WAS NEVER REDEPLOYED\n\ndeploy-prod.yml applies Terraform with -target limited to the web and worker\nservices. flashy-admin-scripts takes the same var.image but was not in the\nlist, so it stayed on app:c976ba0 while the services moved on — every\nscripts/*.ts written since then failed through the job with\nERR_MODULE_NOT_FOUND. That is what killed the first reconciliation attempt this\nmorning, and it reads as a missing file with nothing pointing at the deploy\ntarget that actually caused it. A job has no traffic and no revisions, so\nadding it does not widen the canary's blast radius.\n\nDRIFT AND CHAIN BREAKS ARE DIFFERENT FINDINGS\n\nreconcile:gold printed \"Drift found. Do not begin migrating writers\" whenever\neither count was non-zero. After the correction, drift was zero and it still\nsaid that. They now report separately, and the chain-break line explains that\nthe `gold-drift-ratify:2026-08-17:",
      "refs": {
        "commit": "6f3a3ec9a0ea00ca0551575a35e24a4f28fe0228"
      },
      "digest": "46685384d1306746a524e548b6dac230f2ef97e2af4789914749ababee811257"
    },
    {
      "id": "ship/claimyour.gold/3178a0129b99",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-17T18:12:14Z",
      "kind": "fix",
      "title": "Correct the measured gold drift, and tell the people affected",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Implements the agreed policy: ratify up, correct down. Nobody who did nothing\nwrong ends up worse off.\n\n  wallet HIGHER than the books → the record is made true, balance untouched\n  wallet LOWER than the books  → the record is made true, then the shortfall\n                                 is actually paid\n\nWHY THIS IS TWO WRITES AND NOT ONE\n\nReconciliation measures `walletBalance - combinedExpected`. A postEntry credit\nraises the wallet AND the books by the same amount, so on its own it moves gold\nwithout closing the gap — the customer is paid and the drift survives intact,\nlooking on the next run like a fresh debt of the same size. Paying twice is the\nfailure mode, and it is not obvious from the outside.\n\nSo ratifyUnrecorded() writes the entry and deliberately does not touch the\nwallet: the gold already moved, what is missing is the record of it. Its entry\nlands on the current wallet balance and starts from what the books believed, so\nafter it posts the two agree and the history says when they stopped agreeing.\nOnly then does the short cohort get a real postEntry credit, which moves wallet\nand books in step and leaves them equal.\n\nEntries are ADJUSTMENT, not EARN_*. An EARN_* value would fold this bug into\nevery leaderboard and lifetime-earnings figure that reads the ledger.\n\nBoth scripts are read-only until --execute. The correction re-measures rather\nthan reading a saved report, because a report written hours ago describes\nbalances that have since moved. Keys are built from a fixed CORRECTION_ID, not\na timestamp, so re-running is a no-op.\n\nThe notification derives its recipients from the ledger entries the correction\nactually wrote, not from the reconciliation report — a customer whose\ncorrection failed is told nothing, rather than told about a payment that never\nlanded. Two cohorts get two messages: the paid cohort gets their own figure per\ndelivery; the recorded cohort is told plainly that their balance was always\ncorrect and has not changed. That message does ",
      "refs": {
        "commit": "3178a0129b992371344fe942c0b113e14e430e36"
      },
      "digest": "0dac417159a04f42a2f471fbfd0a0893471896a81f775292c475cb2bcf4dc76b"
    },
    {
      "id": "ship/claimyour.gold/3e6acc79cb34",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-17T17:48:53Z",
      "kind": "feature",
      "title": "Merge the vendored-ledger build fix",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Restores the ability to build the image at all. The deploy pipeline's npm ci\nwould have failed on the private git dependency exactly as the local one did.",
      "refs": {
        "commit": "3e6acc79cb34fc3c12a1dc0d032e7c3d05a5fb78"
      },
      "digest": "1380ed372618e8f499f5a2223253924fad9d42d2fc0582ffdbe116e73132aaca"
    },
    {
      "id": "ship/claimyour.gold/52bceadf5dbc",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-17T12:44:13Z",
      "kind": "feature",
      "title": "Merge origin/main into the ledger branch",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The branch was cut 2,390 commits ago and merged clean — no conflicts.\n\nOne thing the merge caught, which is the architectural guard doing\nprecisely its job. main added scripts/reconcile-pre-eligibility-quest-gold.ts,\na clawback for quest gold granted before eligibility checks existed. It\ndecremented Wallet.goldBalance directly and wrote reward_ledger — both\nbanned on this branch since the guard landed.\n\nMigrated rather than allowlisted, and it is better for it. The entry now\nlands in gold_ledger where every other movement lives, instead of the\nretired table where reconciliation would never see it. The wallet and the\nentry commit together. And it has an idempotency key derived from the\ncustomer, which it did not before: as written, a second run — after an\ninterrupted first, say — would have clawed the gold back twice, leaving\ntwo identical rows and no way to tell them apart.\n\n10,756 tests passing. Typecheck and lint clean.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "52bceadf5dbc735e5cc3f8b8436b21730c9ac969"
      },
      "digest": "449c6066ec4908a3bd215af6e9645237eb500bc7899e8ecc859b36f8b2aafc46"
    },
    {
      "id": "ship/claimyour.gold/cac601499fbf",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-16T18:51:57+00:00",
      "kind": "other",
      "title": "Operator runbook for the XP production launch",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The nine-step sequence only a human with production access can run: schema\npush, price seed, legacy migration with dry-run gate, first reconciliation\n(the launch gate), cron schedules, verification signing keys, the\nend-to-end Intelligence proof, the Academy SDK path-dependency decision,\nand the verification window that authorizes the XP-6 retirement.\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "cac601499fbf1cd171ecaa3e48b36544bd44b764"
      },
      "digest": "c6f8d8ab840eb0e71cd04d9ca8bd9b71dbc5271754b596d36eac9e1d5e6379dc"
    },
    {
      "id": "ship/claimyour.gold/4aae46d14df6",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-16T18:51:57+00:00",
      "kind": "infra",
      "title": "Carry the public handle across the portal bridge",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The Academy learner surface links the hunter's public record page, but the\nbridge verify response only carried userId and email. The handle now rides\nalong under the record's own visibility rule (public and not retired), so a\nprivate hunter's handle never crosses the bridge.\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "4aae46d14df6ff425f1da11e09d5b08411b2c91e"
      },
      "digest": "1c6532169837192bbd441c94e42bfc11ff19ae714077e9fa3f60e774ff2dca95"
    },
    {
      "id": "ship/claimyour.gold/42e4d9f9f9f4",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-16T18:49:14+00:00",
      "kind": "other",
      "title": "XP-10: signed record verification — the employer surface",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Make it worth something outside (execution review §4), implemented exactly\nper hunter-identity.v1.yaml (VerificationEnvelope / HunterAttestation /\nAttestedSkill / AttestedCertificate / VerificationKeysResponse — the spec\nis law):\n\n- GET /api/v1/public/hunters/[handle]/verify → { payload, signature, keyId,\n  algorithm: \"Ed25519\" }. The payload attests earned attainments only:\n  handle, hunterLevel, exactly five skills (skill+level, never raw XP),\n  certificate references with their own flashy.academy verifyUrl, issuedAt\n  now, expiresAt now+24h, audience \"public-verification\". Unknown and\n  private hunters are both 404, byte-identical — same rule as the record\n  route, which the service inherits by resolving through\n  getPublicHunterRecord.\n- Signature: Ed25519 (node:crypto) over the RFC 8785 canonical JSON of the\n  payload alone, base64url without padding. canonicalJson is a small local\n  helper (lexicographic key sort at every depth, UTF-8, no whitespace,\n  rejects anything JSON.stringify would silently drop) — no new deps.\n- GET /api/v1/public/hunters/verify-keys publishes the active key (raw\n  32-byte public key, base64url; createdAt derived from the YYYY-MM keyId\n  convention; retiredAt null). The static segment wins over the dynamic\n  [handle] sibling in Next routing, and [handle]/verify additionally\n  refuses \"verify-keys\" as a handle — the reserved word can never resolve\n  to a record.\n- Keys from env: XP_VERIFY_SIGNING_KEY (base64url raw 32-byte Ed25519\n  seed) + XP_VERIFY_KEY_ID. Missing or malformed → verify answers 503\n  SIGNING_UNAVAILABLE and verify-keys answers an empty list — never a\n  broken signature. Both vars documented in docs/runbook.md with a\n  node one-liner to mint a seed.\n- Tests do what a third-party verifier does: fetch verify-keys, rebuild\n  the public key, and check the signature with node:crypto verify() over\n  re-canonicalized payload bytes — plus a tamper case that must fail,\n  the 24h expiry arithmetic, both missing-key behaviors, th",
      "refs": {
        "commit": "42e4d9f9f9f43ce084ed522e8ef341e2caba3e18"
      },
      "digest": "55a9dac115a2f335b46e6fba3a16a68b8cdae9470ea42c01f710ac16778e5bb5"
    },
    {
      "id": "ship/claimyour.gold/c18e1613a434",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-16T18:44:49+00:00",
      "kind": "other",
      "title": "XP-9: level-up moments",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Make it felt (execution review §4): the record now announces itself. The\nwriter stays pure — skillXpService knows nothing of Telegram or badges;\nfeeders hand the AwardSkillXpResult they already receive to the new\nxpMomentsService, and everything downstream is fire-and-forget.\n\n- notify/xp.ts: notifySkillLevelUp on the existing Telegram notification\n  path (\"Your Strategy just hit level 4\"), linking the hunter's public\n  record. Bot surfaces stay read-only — notifications out, no XP-earning\n  bot actions (session-2 decision).\n- xpMomentsService.celebrateXpAward: no-op unless the award wrote a\n  level-up; sends the DM, and at levels 5/10 awards the new milestone\n  badges (skill-level-5 EPIC \"Specialist\", skill-level-10 LEGENDARY\n  \"Master of the Craft\" — once-ever via the HunterBadge unique). The badge\n  itself posts badge_earned (20 INS) through the normal ledger path with a\n  stable key, and the recursion that could cause is bounded by badge\n  idempotency and the level cap.\n- All eight feeders wired: duel_won, daily_mission_completed, streak_day,\n  redemption_completed, crew_war_win, referral_activated, the academy quiz\n  route (module/perfect/war/certificate), and /internal/hunter-engagement.\n- day3 re-engagement: identity-frame variant on the existing getVariant A/B\n  machinery (reengagement-frame-v1: gold | identity). The identity frame\n  defends the record — \"Your Instinct 6 is 2 days from safe\" — computed\n  from the 3–7-day lapse window, and falls back to the gold frame when the\n  hunter has no Instinct level to defend, so the claim is never hollow.\n- Tests assert user-visible outcomes: the DM fires exactly once on a level\n  boundary, never on mid-level or replayed awards; milestone badges land\n  once with the earning skill in metadata and a badge_earned event on the\n  ledger; both message frames render from real streak data.\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "c18e1613a4349e9219531cf9aec22de2af3ecbc8"
      },
      "digest": "bae46fbba94dd368557b478a11e4312cd15eb5a83020bc9f56c0fa83a887b6aa"
    },
    {
      "id": "ship/claimyour.gold/0dc7aa3f6476",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-16T18:38:30+00:00",
      "kind": "other",
      "title": "XP-8: anomaly baseline + visible admin",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The trustworthy-at-scale phase (execution review §4): the append-only XP log\ngets a nightly statistical conscience, and admin corrections become visible\nledger entries instead of silent grants.\n\n- XpAnomalyFlag model: one flag per (hunter, activity, UTC day), unique-keyed\n  so the scan is idempotent; OPEN → REVIEWED_LEGIT | REVIEWED_ACTIONED with\n  reviewer + note. Flags are evidence for a human, never a verdict — nothing\n  reads this table to punish (session-2 decision, restated in code comments).\n- xpAnomalyService.scanXpAnomalies: folds yesterday's EARN events per\n  (customerId, activity) and scores each hunter against the population's\n  per-activity median/MAD; robust z > 3.5 (ANOMALY_ROBUST_Z_THRESHOLD) flags.\n  MAD floored at 1 so uniform populations stay finite; populations under 5\n  hunters have no baseline and are never flagged.\n- xpAnomalyScanJob + POST /api/v1/cron/xp-anomaly-scan, mirroring the\n  xp-reconciliation cron exactly (x-admin-key; run daily 04:00 UTC, after\n  reconciliation).\n- Super-admin surface: GET /super/xp-anomalies (?status filter),\n  PATCH /super/xp-anomalies/[id] (review verdict, reviewer from session), and\n  POST /super/xp-adjustments → postXpAdjustment as kind ADJUSTMENT, activity\n  admin_adjustment, idempotencyKey admin-adjustment:<client uuid requestId>;\n  reason mandatory (400 when empty) and stored in event metadata, visible in\n  the hunter's own history.\n- Tests assert DB outcomes: the farmer is flagged and the normal population\n  is not; re-runs refresh numbers without duplicating or overwriting a human\n  verdict; the adjustment posts a visible ADJUSTMENT event carrying the\n  reason, dedupes on requestId, and writes nothing on validation failure.\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "0dc7aa3f647650df52b4cf7207cbf5a267f312b9"
      },
      "digest": "e1822b6f66a15ee73d39462fbcac8215945d23c5f961cdc48cf3164d64cd9df6"
    },
    {
      "id": "ship/claimyour.gold/74f9b99d9b18",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-16T18:25:11+00:00",
      "kind": "other",
      "title": "XP-7: the public Hunter Record page at /hunters/[handle]",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The shareable screen on the XP-4 API data — a server component that reads\ngetPublicHunterRecord directly (the same service the public API route\nuses; never fetches its own API):\n\n- five-axis skill radar as inline SVG (new pure helper src/lib/skillRadar.ts:\n  pentagon vertices from the five levels on a 1..10 scale, grid rings,\n  axis labels), Hunter Level (sum 5..50), per-skill level + progress bars,\n  verified certificates, streak summary\n- 'Claim your own record' CTA with utm_source=hunter_record,\n  utm_medium=share, utm_campaign=public_profile\n- generateMetadata share cards: title 'Hunter <handle> — Level <N>',\n  description from top skills, OG + Twitter tags\n- unknown and private handles render the identical not-found state,\n  mirroring the API's indistinguishable 404\n- portal profile self-view now links 'View public record' to the page\n- typography via the globals.css text vars; no raw font-size below\n  --text-body; rewards referred to as Flashy Gold; no audience-size claims\n\nTests cover the page's data pipeline: radar-ready shape (closed pentagon,\nvertices track levels) for a known public hunter, full pentagon at the\nlevel-1 floor, and the indistinguishable empty state for unknown, private,\nand retired handles.\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "74f9b99d9b185155fc1e5ad94b4413d69041fc18"
      },
      "digest": "099e8458bd7abab871ac75485cb70d1fdb0a6659e07301c77da5b2d16d06f622"
    },
    {
      "id": "ship/claimyour.gold/fa8871a9f0da",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-16T18:21:48+00:00",
      "kind": "other",
      "title": "XP-6 (additive): skill-gated quest visibility",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Quests gain an optional requiredSkills map (SkillKey -> min level 2..10),\nevaluated against the HunterSkill projection via skillXpService:\n\n- prisma: Quest.requiredSkills Json? (null = ungated, exact old behavior)\n- questQueryService.listQuestsWithStatus: skill-gated quests stay VISIBLE\n  but locked, extending the eligible/requirementLabel pattern with\n  structured skillLocks (skill, required vs current level, earnAt hint —\n  INTELLIGENCE points to flashy.academy, the adoption loop)\n- questVerification.verifyQuestEligibility: locked quests are not\n  claimable server-side on any path (portal/mini-app/partner-api) —\n  throws SKILL_REQUIREMENT_NOT_MET 403\n- admin create/update accepts requiredSkills, validated in the service\n  (assertValidRequiredSkills) and in the zod questBaseSchema\n- quest cache key bumped to v3 (shape gained requiredSkills)\n\nThe retirement half of XP-6 (hunterXpService shim, HunterProfile.xp,\nlegacy vocabularies) is deliberately untouched — gated on the production\nmigration window that has not run.\n\nTests assert database outcomes: a below-requirement hunter sees the lock\nwith the earnAt hint and no completion/ledger/wallet rows exist after a\nclaim attempt; an at-level hunter claims normally; ungated quests are\nbyte-for-byte pre-XP-6 behavior.\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "fa8871a9f0dae53c7b3d4b373ff909b3cd1e8b16"
      },
      "digest": "239de559046bcff7a0b10523bd36808f187025cf475770b8956718bae9de528d"
    },
    {
      "id": "ship/claimyour.gold/f27bbaeedd23",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T23:00:21Z",
      "kind": "other",
      "title": "Chain new ledger entries forward, using @flashy/ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The write half of the chain-forward decision. Every entry now links to the\nprevious one for its identity and asset, so editing any stored row breaks\nverification for that row and every row after it.\n\nForward only, deliberately. Rows written before this have previousHash and\nhash null, and that is the honest state — they were never chained, and\nclaiming otherwise would assert a tamper-evidence they do not have.\nBackfilling means rewriting years of entries strictly in order, an\nunresumable job against live money, for a guarantee about a past nobody\ncan act on. An identity's chain simply starts at its first entry after the\ncutover.\n\nhashEntry comes from the package rather than being reimplemented here. Its\nfield order is part of the format, and two implementations of \"the same\"\nhash is exactly how a chain stops verifying across services with nothing\nto point at. The digest is computed over minor units, matching what the\npackage's own adapters hash — hashing the float would make it depend on\nhow the value serialises.\n\ncreatedAt is now written explicitly instead of defaulting on the database.\nThe hash covers the timestamp, so hashing one instant and storing another\nwould fail verification on every entry, starting with the first.\n\nTHIS IS THE FIRST PRODUCTION CONSUMER OF @flashy/ledger\nTwo things had to change in the package before that was possible, both\npushed there: the mongodb peer accepted only ^6 while this repo is on ^7,\nso the install failed outright; and the package was ESM-only, which\nts-jest cannot transform, so importing it failed at parse time pointing at\nthe test file rather than the package. It now ships a CommonJS build too.\n\nOnly the pure domain is used here — hashEntry and minor. Storage stays\nPrisma. Postings do not move to the package until the entry formats are\nreconciled, and this is the step that begins reconciling them.\n\n10,654 tests passing. Seven new ones cover the chain, including that a\nreplay writes nothing and does not even read the head.\n\nCo",
      "refs": {
        "commit": "f27bbaeedd23edcc8580be98a08a01db94839a4b"
      },
      "digest": "b97e7014c93bb7ca247de6d8d46ec8b93093da184ff133d39e5670dd3aef5fb0"
    },
    {
      "id": "ship/claimyour.gold/cf0cf7e14d8a",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T22:39:23Z",
      "kind": "other",
      "title": "Resync the Terraform mirror, and say that it is one",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "flashy-infra gained three Cloud Run services on 2026-08-14 — flashy-academy,\nthe FlashyOS ops console, and the flashy.academy DNS mapping — while this\ncopy kept them out. That is the first drift between the two since the split,\nand this copy is what production applies from.\n\nNothing is at risk today: each service is gated on an image variable\ndefaulting to \"\", so none creates a resource. The hazard needs a sequence.\nSet academy_image and apply from flashy-infra, and the services exist in\nthat state. Then any later change under infra/terraform/** here triggers a\nfull untargeted apply from this copy — which sees resources in state that\nits configuration does not declare, and destroys them.\n\nA live service disappearing because two directories disagreed. So the copies\nare byte-identical again, and the README now leads with why that matters\nrather than leaving the next editor to find out.\n\nThe cutover is two edits — check out flashy-infra in the deploy job, repoint\nworking-directory — and needs INFRA_REPO_TOKEN, since GITHUB_TOKEN cannot\nread another private repository. There is no credential-free version, which\nis why this is a mirror rather than a deletion.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "cf0cf7e14d8ad0ed9015b27a1e81e1b20f464f30"
      },
      "digest": "b0c4cb09a7d36d3c7a5f965a3ccacc785efcec06b5de99700f30f3b9fb4c3e67"
    },
    {
      "id": "ship/claimyour.gold/47bf2747d30f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T22:13:31Z",
      "kind": "fix",
      "title": "Fix PDF ingest, and delete the type shim that hid it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "pdf-parse v2 exposes a PDFParse class and has no default export. The code\ncalled it the v1 way, so `(await import('pdf-parse')).default` was\nundefined and every PDF ingest threw \"not a function\".\n\nIt typechecked because src/types/pdf-parse.d.ts declared the v1 shape by\nhand. A `declare module` for a package that ships its own types does not\nsupplement them, it replaces them — so the compiler confidently described\nan API the runtime had not had since the v2 upgrade, and the only place\nthe truth showed up was a 500 on upload.\n\nDeleting the shim was the actual fix. The real types were correct and\npresent the whole time.\n\nThe parser now also releases the pdf.js worker, which the original never\ndid — one leaked per ingested document.\n\nFound while porting this subsystem to flashyos, which is where it now\nlives. This copy keeps serving /ops until that one is deployed, so it is\nworth fixing here rather than waiting.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "47bf2747d30f2571de5f16a99e2dcc0a055ec4e0"
      },
      "digest": "c71212b1c00cc63bebd18384b756d5df3956acc5e266e271a7544ae5547dddb6"
    },
    {
      "id": "ship/claimyour.gold/fcb8483b5b59",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T21:54:12+00:00",
      "kind": "other",
      "title": "Boardroom session 3: execution review, sharpened vision, XP-6..XP-10 roadmap",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Reviews the build against the XP-0..XP-6 roadmap phase by phase, answers\nthe agent-review-checklist questions in writing, and names the one claim\nnot being made (reconciliation green on real data — the production gate).\nSharpens the vision with what the build proved: value and identity now\nclear through one settlement fabric, and the XP ledger is the rehearsal\nfor the gold wallet's strangler swap. Next phase: XP-6 load-bearing\ngating, XP-7 the visible record page + SDK adoption, XP-8 anomaly\nbaseline, XP-9 level-up moments, XP-10 the employer surface.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "fcb8483b5b590e9f3e8de31ff917b1a469851b9c"
      },
      "digest": "e7b1419e6fc8ae048093679f5344c6f3583ec4a27856e83066e2ea5798695c93"
    },
    {
      "id": "ship/claimyour.gold/3e5a811401e3",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T21:52:33+00:00",
      "kind": "other",
      "title": "XP-1..XP-5: the Hunter Record's XP now settles on the flashy-ledger books",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Every XP movement lands as an append-only, hash-chained @flashy/ledger\nentry (XpEvent) with the HunterSkill projection updated in the same\ntransaction — the wallet post-mortem rule, enforced in the single writer\nskillXpService. Prices are data (XpActivityPrice), the level curve is\nconfig (XpLevelCurve), and a nightly reconciliation job folds the ledger\nagainst the projection and alerts on drift.\n\nIntelligence ships first: the quiz-submit route awards module/perfect/\ncertificate XP with entity-stable idempotency keys, and the\nhunter-engagement boundary is upgraded to v2 (server-side pricing, v1\ncompat preserved). Profile-less learners are auto-provisioned on first\nearn, closing the silent XP no-op. The other four skills get live\nfeeders: duels and war quizzes (STR), streaks and daily missions (INS),\nactivated referrals and crew war wins (INF), fulfilled redemptions (COM).\nPublic record at /api/v1/public/hunters/[handle]; portal self-view with\nevent history; legacy awardXp is a deprecated shim and HunterProfile.xp\nis frozen.\n\nMigration and seeding are scripts (seed-xp-prices, migrate-legacy-xp\n--dry-run supported); XP-1's exit criterion — reconciliation green on\nreal data — deliberately remains open until they run in production.\n\nTests: 10,518 pass (47 new XP tests including hash-chain verification\nwith @flashy/ledger's verifyChain), tsc clean, eslint clean.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "3e5a811401e329545477cc3e12d2fe261676b52a"
      },
      "digest": "f6a67293227469ae9c54da732a5606f159baeed369092e974beb0b0e3d4385a6"
    },
    {
      "id": "ship/claimyour.gold/31c605868b2a",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T19:58:19Z",
      "kind": "other",
      "title": "Empty the ledger allowlist — every gold path now posts through the primitive",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The last three files were parked on product decisions. Looked at properly,\neach carried a live money defect, and they were mirror images of one\nanother.\n\nwarBetService moved the wallet and wrote no entry — a silent write, gold\nleaving a balance with nothing recording it. Three more defects came with\nit. Settlement collected un-awaited promises and handed them to\nPromise.all, which is concurrency, not a transaction, so a partial failure\nleft some bets paid and settled and others neither. The balance check and\nthe decrement were separate statements, so two simultaneous bets could\nboth pass a check only one could afford. And if nobody backed the winning\ncrew, every bet settled as a loss and the entire pool ceased to exist —\ngold destroyed with no counterparty and no record. It now refunds.\n\npredictionMarketService had the opposite defect on both sides: a stake\nwrote a negative reward_ledger row and left the wallet untouched, and a\npayout wrote a positive one that was never paid. The market was complete,\nlive on three portal routes, and entirely notional. Its balance check\nsummed reward_ledger while every other spend check in the codebase reads\nwallet.goldBalance — and since reward_ledger's writers have moved away,\nthat sum was drifting toward zero, turning the affordability check into a\nrefusal for everyone.\n\ncrewSynergyService was not migrated. Its applyWarBonus wrote a\nreward_ledger row per member and never paid it, but the larger fact is\nthat nothing called it — the portal route reads the score and nothing\nelse, and the function's only callers were its own tests. Dead code\nwriting a phantom ledger, so it is deleted rather than fixed.\nReintroducing a synergy bonus is a product decision, and whoever makes it\nneeds to name the event that pays it: the old signature had no war id,\nwhich is why it could not have been made idempotent as written. The score\nitself is kept, and now reads gold_ledger instead of the draining\nreward_ledger — it had been drifting downward for rea",
      "refs": {
        "commit": "31c605868b2acb8285d5be009d334f55d4f22c95"
      },
      "digest": "aeb6815a495048e9ecec82864a37738af27ec50224a98064add029715347eee9"
    },
    {
      "id": "ship/claimyour.gold/1ccad8c43a0a",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T18:48:04Z",
      "kind": "other",
      "title": "Mock getFlashyGoldAssetId where the wallet module is mocked",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "An unmocked export is undefined, so calling it threw before the credit\nran — and the failure surfaced as \"expected 1 call, received 0\", which\npoints at the payout rather than at the mock.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "1ccad8c43a0a612f8b3ece5261b92163c1c6e998"
      },
      "digest": "fc07afbc1cf78641df82f328c4aa3d692bdf8a8b80c9dcaac526732a9490ab50"
    },
    {
      "id": "ship/claimyour.gold/41175856d9a9",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T18:45:31Z",
      "kind": "feature",
      "title": "Add the sponsored-quest boundary for flashy-academy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Academy owns the sponsorship and the job poster's funding pool; this app\nowns the quest catalogue. Neither reaches into the other's collections,\nso the handoff is an endpoint — the second one after\n/internal/wallet/credit, behind the same narrow x-internal-key.\n\nA replay returns the existing quest rather than failing on the unique\nslug. The caller has already been debited by the time this runs, so a\n500 here would send Academy down its refund path and hand back gold for\na hunt that exists and is live.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "41175856d9a9929e8e176e29cfc9cb07f9e759d9"
      },
      "digest": "935f95e77ae8aff3b83ff8977edff3524af6c9bd7aaf4f2af017ff6ad674db4c"
    },
    {
      "id": "ship/claimyour.gold/cd911ecca567",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T18:42:32+00:00",
      "kind": "other",
      "title": "Growth boardroom: Hunter Record identity, XP ledger architecture, adoption plan",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two boardroom artifacts. The growth brief convenes marketplace, credential,\nand ad-tech archetypes to audit the current growth machinery (mutable XP\nscalar with no event history, silent XP no-op for profile-less users, five\nparallel progression vocabularies, loops ending in manual steps, captured-\nbut-never-joined attribution) and lays out five self-closing adoption loops\nwith seven numbered laws.\n\nThe XP system architecture is the produced design: five skills\n(Intelligence, Strategy, Instinct, Influence, Commerce), an append-only\nXpEvent ledger with prices-as-data and idempotency keys (the gold ledger's\ndiscipline applied to experience, projection updated in the same\ntransaction — the exact lesson from the wallet credit bug), derived Hunter\nLevel replacing the scattered vocabularies, hunter-identity.v1 contract +\nSDK plan, scalar migration path, and an XP-0..XP-6 roadmap starting with\nIntelligence fed end-to-end by Flashy Academy.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "cd911ecca5675f36c58fcac6e8b6076661d96c46"
      },
      "digest": "d61a5039c842cb5aa35b21e12efde5f3d6c45438d5f351cb9e44c0a3bc3ddece"
    },
    {
      "id": "ship/claimyour.gold/26c149711645",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T18:30:08Z",
      "kind": "fix",
      "title": "Fix four payouts that could never land, and guard the class",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "GoldLedger.assetId is an @db.ObjectId. Four call sites passed a slug\ninstead — 'flashy-gold' (11 chars) or 'gold' (4) where Mongo demands 24\nhex — so Prisma rejected the write at runtime. The field is typed String,\nso nothing caught it at compile time.\n\nWhat each one cost:\n\n  shareQuestService, both tiers    The Redis NX reward guard is set\n                                   BEFORE the credit. The guard was\n                                   consumed, the credit threw, and the\n                                   payout could never be retried. Silent,\n                                   permanent, per-hunter loss — logged as\n                                   awarded.\n\n  duelChallengeService, both       Stake debits threw, so no staked duel\n  stakes                           could be accepted at all.\n\n  notificationOptInService         The 10 FG opt-in gift never landed.\n\nAll four now resolve through getFlashyGoldAssetId(), which reads the Asset\nrow once and caches it.\n\nThe lint rule is the actual fix. Three of these four were not in the\nreport that prompted the search — the rule found them. A slug in an\nObjectId field is invisible to the type checker and only fails in\nproduction, so it needs a guard that runs on every build rather than an\naudit that runs when someone remembers.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "26c149711645446988bcf144f0cd47b5d2465ac4"
      },
      "digest": "962437632c7529de17426edb03909867ed4ffb484af7c7ed34675c1a23f90f6f"
    },
    {
      "id": "ship/claimyour.gold/be53c8163c09",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-14T18:20:58+00:00",
      "kind": "other",
      "title": "Boardroom brief: ten-repo architecture audit and acceleration plan",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Answers the two commissioned questions directly — prizes are NOT pulled\nfrom flashy-gold (deliberately catalog-free by its own design) and\nsettlements are NOT on @flashy/ledger (unpublished, memory-only, zero\nconsumers). Verified first-hand along the way: creditWalletWithLedger\nnever updates Wallet.goldBalance, so every credit through the canonical\nhelper — including redemption refunds and the Academy seam — is\nunspendable and invisible to the user.\n\nLays out the target architecture (publish the @flashy/* packages, Mongo\nadapter for the ledger port, strangler swap of the wallet helpers,\ncontract-first prize surface via flashy-gold + a generated @flashy/sdk,\nreal Academy deployment, load-bearing FlashyOS governance) and a\nNow/30/60-90 acceleration sequence, findings ordered by consequence per\ndocs/agent-review-checklist.md.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01HpFGBPPDHnN7fKuVjWKKSv",
      "refs": {
        "commit": "be53c8163c097113937ec51681ed8020c77343e0"
      },
      "digest": "55a5fa5176a220be49aa9f95df8c253b3527ed20a95afb22199edf65db951e5d"
    },
    {
      "id": "ship/claimyour.gold/67210bbd6d84",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T18:11:51Z",
      "kind": "infra",
      "title": "Make \"is the extraction done?\" an executable check",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "That question has been answered several times by measuring the tree by hand,\nand hand measurement drifted twice: once when a `grep -v academy` filter\nsilently excluded Academy code living outside src/services/academy*, and once\nwhen an ESLint glob missed directories and reported 219 violations that were\nnot violations. Both times the number looked plausible.\n\nSo the answer stops being prose. Fourteen checks, each PASS or FAIL against\nthe working tree with the deciding number printed beside it, covering: Academy\nsource and models still present, non-Academy code importing Academy, the\nledger domain still here, whether either consumer declares the packages,\nwhether portalSession.ts still exists twice, whether flashy-gold serves an\nasset API, the legacy writer allowlist, and whether Terraform is still in this\nrepo.\n\nSource only — no database, no network, no credentials — so it can run on every\npull request.\n\nIt exits 1 today, reporting 0 passing and 14 failing. That is the correct\nanswer: the repos exist, the guardrails hold, and nothing has been extracted\nyet. The value is that the number can no longer quietly drift from the claim.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "67210bbd6d84eec97427e89532d5f64efa6fc9bb"
      },
      "digest": "0ec8c4636f66e5d1d752b5fb6b7c1703cca90841a0c144cd4da7bda1f6fb4eb1"
    },
    {
      "id": "ship/claimyour.gold/de82e2ca0985",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T17:47:25Z",
      "kind": "feature",
      "title": "Add an audit for which Academy tracks actually pay gold",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "\"All courses should provide gold prizes\" reads like a feature request and is\nnot one. The mechanism already exists and already runs through the ledger:\nacademyProgressService.issueCertificate credits track.goldReward on\ncertificate issuance, keyed academy-cert-{certId}, and debits the sponsor's\npool afterwards when the track is sponsored.\n\nThe open question is data — whether every track has a goldReward above zero —\nand nothing in the codebase can answer it. This script does.\n\nRead-only, so it is safe against production. It separates two failure modes\nthat look the same from outside: a live track with no prize set, and a live\ntrack with zero modules, which can never issue a certificate and therefore can\nnever pay whatever its goldReward says.\n\nSetting the amounts stays a separate, deliberate act rather than something a\nscript does on its own.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "de82e2ca0985e697191c99da19a94e47eeecbf68"
      },
      "digest": "86128beece2eb990b83f2566f4dbbf061bb4097bace96c61accc86dabc1e9a3c"
    },
    {
      "id": "ship/claimyour.gold/c03876d485d3",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T16:29:07Z",
      "kind": "feature",
      "title": "Close the two boundary holes: scripts/prisma, and Academy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two guards, both enforcing a boundary that was previously kept by memory.\n\nLEDGER GUARD NOW COVERS scripts/ AND prisma/\n\nThose directories sat outside the ledger write guard entirely, which is the\nonly reason direct balance writes survived there long after every service had\nbeen migrated off them. Four files were writing balances or ledger rows\ndirectly and nothing was stopping a fifth.\n\nThree are dev fixtures that create wallets rather than moving gold, and are\npermanently allowed. The fourth —\nprisma/migrate-transactions-to-ledger.ts — is a historical backfill that\nwrites gold_ledger rows with the pre-WS-1 shape, bypassing every invariant the\nledger now enforces. Re-running it against current data would reintroduce\nexactly the rows the Float-to-Int and sign-convention backfills exist to\nrepair. It is allowlisted with that warning attached and should be deleted\nonce those backfills land.\n\nACADEMY BOUNDARY GUARD\n\nNothing outside Academy may import an Academy service. The eleven files that\nalready do are the migration queue; each one has to become an HTTP call to\nflashy-academy or move there outright before 363 files can be deleted from\nthis repo. A twelfth would be one more.\n\nTwo measurement notes, because both were nearly wrong. 223 files import an\nAcademy service, but 212 of those are Academy's own — the coupling is 11, and\nthe first cut at this number was only correct by accident. And the ignore\nglobs have to cover directories as well as filenames, because Academy code\nlives under src/app/**/academy/** and src/jobs/academy* as well as\nsrc/services/academy*; the narrower version reported 219 false positives.\nA Next.js dynamic segment also needs its brackets escaped, or ESLint reads\n[slug] as a character class and the path never matches itself.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "c03876d485d39b7a0c36253401246db63383c9dd"
      },
      "digest": "4e263948476ea47f5bd918e1f1f47aee1c71eecb298e7179ee611c1e76c47856"
    },
    {
      "id": "ship/claimyour.gold/51015dc8b495",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T13:28:53Z",
      "kind": "other",
      "title": "Design the flashy.gold / flashy.network boundary",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "flashy.gold becomes the asset API; flashy.network holds the ledger. The split\nis right; this documents where exactly the line falls, because there is a way\nto draw it that recreates the defect WS-1 just finished fixing.\n\nAMS's central problem was never a missing ledger — it had three. The problem\nwas that the invariants lived in 110 call sites and the ledger was somewhere\nthings got written afterwards, sometimes. \"API layer\" plus \"ledger data\" can\nbe read as ledger-owns-correctness or ledger-owns-storage. The second is\ntoday's architecture with a network boundary through the middle of it, which\nmakes divergence permanent rather than merely likely, because the two halves\ncan no longer be fixed in one transaction.\n\nThe rule that falls out: flashy.gold holds no balances. Not a column, not a\ncache. It expresses intent and asks for balances; the ledger decides what is\nlegal and is the only thing that knows a number.\n\nThe main recommendation is to defer the network hop. @flashy/ledger's entire\nstorage surface is one interface, so the service boundary can be deferred\nwithout being designed around later: embed the package with a Mongo adapter\nfirst, so the invariants exist in one place for the first time, and swap in an\nHTTP adapter when a second consumer justifies the availability cost. Going\nstraight to a service means an outage in flashy.network becomes an outage in\nearning, spending and duels, paid before anything else consumes the ledger.\n\nAlso records that flashy.gold's API tier is a greenfield build — the repo is\n30 files of static site with no service tier — and that the money API should\nnot share a deployment with the marketing pages.\n\nExtraction plan updated: Academy shares one MongoDB, so its deletion is a code\nchange with no data migration, and the port must be a move rather than a fork.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "51015dc8b4951f8c2b3226b670a5140f11d99ba8"
      },
      "digest": "d6ff990e4d6671861bb34eec5fd9824812d33e76e0f4424071c4ebc350ad7898"
    },
    {
      "id": "ship/claimyour.gold/4228279983f8",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T12:46:22Z",
      "kind": "feature",
      "title": "Add the repo extraction assessment",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "What is actually required to move code into flashy-ledger, flashy-academy and\nflashy.gold and then delete it from here. Every figure in it was measured\nagainst the working tree rather than estimated.\n\nThe headline is that Academy and the ledger are barely coupled — three of 108\nAcademy services touch gold, and one model out of 58 is the join — so the two\nextractions are independent and can run in parallel.\n\nTwo questions in it are blocking and cannot be answered from the code: whether\nFlashyGoldAMS and flashy-academy share one MongoDB database or two, and\nwhether flashy.gold stays a marketing site or becomes the consumer product.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "4228279983f885b677a3d9b630e9e72368f34f14"
      },
      "digest": "a674e852fc0ccd40ce63c312ba2c4b15dd36b8140ed0903d3ec443b5e53e1a7d"
    },
    {
      "id": "ship/claimyour.gold/ba1993262bf0",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T12:42:02Z",
      "kind": "feature",
      "title": "Give the house an account, and stop the war wager minting gold",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two decisions, both about gold that was appearing or disappearing without a\ncounterparty.\n\nTHE HOUSE NOW HAS AN ACCOUNT\n\nduelBetting's 10% rake was subtracted from the prize pool and credited to\nnobody: losers were debited their full stake, winners shared 90% of it, and\nthe missing 10% stopped existing. It is platform revenue, so it is now posted\nto a real account and every settled duel sums to zero across its participants.\n\nsrc/ledger/houseAccount.ts is the honest workaround, not the design.\nWallet.customerId is a foreign key to Customer, so the current schema cannot\nexpress an account that is not a hunter — the house is therefore a reserved\nCustomer row (telegramId `system:house`, SUSPENDED so nothing can ever\nauthenticate as it). Because it IS a Customer row it would otherwise appear in\nevery ranking, so excludeHouse()/excludeHouseWallet() exist and the eight\nbalance-ordered queries now use them, including the circulating-gold total in\ngrandLedgerService and the emergency fund, which must never pay relief to the\nhouse. A first-class account type belongs in flashy-ledger, where an account\nis an id and a kind rather than a person; this file is what gets deleted when\nthe ledger moves out.\n\n1.8x IS NOW A CEILING, NOT A PROMISE\n\nwarWager paid every winner a flat 1.8x their own stake with no reference to\nthe losing pot, under a comment claiming \"house keeps 10% of losing pot\" that\nthe formula never implemented. Whenever the losing side staked less than 0.8x\nthe winning side, the difference was minted out of nothing — the system paid\nout gold nobody had wagered. Its existing test asserted exactly that case: a\n50 stake against 30 paid 90 when only 80 gold existed in the war.\n\nA wager pool can only pay what was staked into it. The house takes its 10% of\nthe losing pot, the remaining 90% is shared between winners in proportion to\nstake, no winner receives more than 1.8x or less than their stake back, and\nany surplus left after every winner hits the ceiling also goes to the",
      "refs": {
        "commit": "ba1993262bf049fa1ec2e393fd3cf9a404cbb274"
      },
      "digest": "969ed9e86cd1a41b558ecceb04eaa079526e7ba1f157e9203feb7f5aa6598cf9"
    },
    {
      "id": "ship/claimyour.gold/bd1002dd1141",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T12:29:09Z",
      "kind": "infra",
      "title": "Migrate the wagering services to postEntry — the last silent write",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Nine write sites across duelBettingCore, warScheduling and warWagerMutation.\nEvery workable file is now off the legacy allowlist; the three that remain are\nparked on product decisions, not on work.\n\nwarWagerMutationService.placeWager was the last silent write in the codebase.\nIt decremented the wallet and wrote no ledger row of any kind — not a\nreward_ledger row, not a gold_ledger row, nothing. Every crew war wager ever\nplaced took gold out of a hunter's balance with no record that it happened,\nwhich is exactly the class of defect reconciliation cannot tell apart from a\nbug or from theft. Its key uses the resulting total rather than the increment,\nbecause wagers accumulate: a hunter raising 10 to 25 is a distinct charge from\nthe first 10 and both must replay exactly once.\n\nduelBettingCore.placeBet and warScheduling.placePrediction both charged before\nthe row they were paying for existed — the bet and the prediction were created\nafter the money moved, so a failure in the create took the gold and left\nnothing behind. Both now create the row first inside a transaction and key the\ncharge to it. warScheduling was also the seventh service writing a literal\n`assetId: 'flashy-gold'`.\n\nTWO ECONOMIC ISSUES FOUND, NEITHER FIXED — both are product decisions:\n\n1. duelBetting's 10% rake is subtracted from the prize pool and credited to\n   nobody. Losers are debited their full stake; winners share 90% of it. The\n   remaining 10% is retained gold with no destination entry, so this duel's\n   entries will not sum to zero by exactly that amount. It needs a house\n   account.\n\n2. warWager pays winners a flat 1.8x their own stake regardless of the losing\n   pot. The comment above it claims \"house keeps 10% of losing pot\", but the\n   formula never reads the losing pot. When the losing side stakes less than\n   0.8x the winning side, the payout is unfunded and the economy mints the\n   difference.\n\nBoth are now visible on the ledger rather than hidden in wallet arithmetic,\nwhich is the point",
      "refs": {
        "commit": "bd1002dd114147fcbfcd216fe5f6b2b3d80b32b7"
      },
      "digest": "7e879771f7d05441b6b030cfcb8afe5bf800d19c79a6ac56536b20906040617c"
    },
    {
      "id": "ship/claimyour.gold/68812843ae37",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T06:03:13Z",
      "kind": "infra",
      "title": "Migrate gift cards, drops and reactivation credits to postEntry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Nine write sites across giftCard, surpriseDrop, inviteQuotaDm, reactivation,\nreferralCohort and referralRaceWeekly.\n\nFour of these were guarded by nothing but a Redis NX key. surpriseDrop is the\nclearest: when `redis` is null it substitutes the literal string 'OK' for the\nNX result, so with Redis absent every run of that job dropped gold to the same\nhunters again. referralCohort and the comeback bonus have the same shape.\nEach now carries the same identity as its Redis key, in a store that is always\nthere — Redis stays as the cheap first check, but it is no longer the only one.\n\nreactivationService.awardComebackCredit carried a docstring claiming the Redis\ncheck lives elsewhere \"so this function remains idempotent and testable\". It\nwas a bare `wallet.updateMany` increment with no guard of any kind, and its\nRedis key is written AFTER the credit, so a crash in between left the hunter\npaid and eligible to be paid again by the next run of the cron. The key now\nmakes that docstring true.\n\nreferralRaceWeekly's prize payout ran under `Promise.all` with no transaction\nand no key, in a weekly job with no dedup at all — a re-run of the week paid\nevery winner again.\n\ngiftCard needed restructuring rather than a substitution. Its charge happened\nbefore the card existed, so there was no id to key on; the code is now minted\nup front by newGiftCardCode() and both the charge and the card carry it. Its\nRedis-failure refund path was a bare wallet.updateMany plus a separate\nrewardLedger.create with independent .catch handlers, so a half-failed refund\nmoved gold with nothing recording it, and the ledger half swallowed its error\nentirely. That compensating entry is now keyed and idempotent, and a failed\nrefund is surfaced rather than dropped.\n\nBoth gift-card entries were also mislabelled by necessity: the debit was typed\nSHIELD_PURCHASE (\"closest available debit type\") and the credit\nREFERRAL_REFERRED_BONUS (\"closest credit type\") because reward_ledger's enum\nhas no gift type. gold_ledge",
      "refs": {
        "commit": "68812843ae37f4582d2c0507cdba3f60d7978bc5"
      },
      "digest": "a1be36b86fac63d0601b24934ffea0e66f2cfe3040a282a872704e7687585c8a"
    },
    {
      "id": "ship/claimyour.gold/7b60b2b35edf",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T05:48:00Z",
      "kind": "infra",
      "title": "Migrate quest, mission and co-activation payouts to postEntry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Six write sites across coActivation, collabQuest, d30Champion, dailyMission\nand questReward.\n\nThe quest payouts are the point of this batch. Three separate services paid\nfor quest completion — quests.ts (migrated earlier), collabQuestService and\nquestRewardService — each with its own reward row and its own wallet write,\nand none of them keyed. questCompletion carries a unique constraint on\n(customerId, questSlug), so the completion record already asserted a hunter\ncompletes a given quest once; the payouts beside it did not honour that. All\nthree now post under `quest:{customerId}:{slug}`, so a hunter is paid once for\na quest slug whichever of the three routes reaches it.\n\nquestRewardService also multiplied the quest reward by an arbitrary campaign\nmultiplier and stored the unrounded product. Rounded to the cent — gold is a\n2-decimal asset.\n\ndailyMissionService already had the right key and used it the wrong way: a\n`goldLedger.findUnique` check-then-act, then `wallet.update` and\n`goldLedger.create` as separate untransacted statements. The key it wrote\ncould only ever be recorded after the gold had already moved, so it documented\nthe payout rather than guarding it. Same key, now enforced by its uniqueness\nrather than by a read.\n\ncoActivation's gate was a `rewardLedger.findFirst` two concurrent activations\nboth pass. d30Champion was an array-form `$transaction` — which cannot express\na dependency between its statements — guarded only by a Redis NX key.\n\ndailyMissionService is the sixth service found writing a literal\n`assetId: 'flashy-gold'` instead of the Asset row's id. That constant is now\ndeleted.\n\nAlso fixed a test that asserted `$transaction` was called after a milestone\npayout. It only passed because the real postEntry happened to open one; it now\nasserts the payout.\n\nAllowlist 17 → 12.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "7b60b2b35edffc1a00dad559ac4fcd6c9d0f9354"
      },
      "digest": "341c17b722f1240aa6693fa13a2cab87863ac238824b84719b92bfdc599153c8"
    },
    {
      "id": "ship/claimyour.gold/ccdb3925633f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T05:34:20Z",
      "kind": "infra",
      "title": "Migrate the crew services to postEntry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Seven write sites across crewAlliance, crewBounty, crewRescue,\ncrewRecruitTournament and crewWarResolution.\n\ncrewWarResolution paid every member of a winning crew with two UNAWAITED\npromises — `void prisma.wallet.update(...)` and `void\nprisma.rewardLedger.create(...)` — racing each other, neither awaited by the\nresolver, both failure paths logging at warn and continuing. A war payout\ncould silently not happen and the only trace was a warn line. Awaited now, one\nkeyed entry per member, and a failure logs at error because it is money that\ndid not arrive. The inline `10` became CREW_WAR_WIN_BONUS.\n\ncrewBounty carried the second `Date.now()` idempotency key in the codebase:\n`recruit-bounty-stake-${captainCustomerId}-${Date.now()}`. Its stake also left\nthe captain's wallet BEFORE the bounty row was created — four statements, no\ntransaction — so a failure in the create charged them for nothing. The bounty\nis now created first inside a transaction and the stake keyed to it.\n\nAlso noted in crewBounty and left alone: the captain stakes rewardFg and\nreceives exactly rewardFg back on completion, so the stake round-trips and the\nbounty costs its poster nothing. Nobody who did the recruiting is paid\nanywhere in that file. That is a product question, not a ledger one, so the\nbehaviour is preserved — but it is why the completion is now typed as a\nreversal of the stake rather than as a prize. Both halves were previously\ntyped TRANSFER_OUT / TRANSFER_IN with no counterparty on either side.\n\ncrewAlliance wrote entries claiming `balanceBefore: 0, balanceAfter: 0`\nalongside a non-zero amount — not merely wrong but self-contradicting. Its\nidempotency key was already correct and is kept as-is.\n\ncrewRecruitTournament chained the wallet upsert off the reward row's promise,\nuntransacted, then swallowed the result in allSettled: a failure in the second\nhalf left a recorded win nobody was paid for, silently. Failures are now\ncounted and logged.\n\ncrewRescue's only guard against a double payout",
      "refs": {
        "commit": "ccdb3925633f54708726cafa12df8dde0b733097"
      },
      "digest": "069ba2f508fe7cafd513eab3a3cc646cb4b27a28cb78bf617afd3034b72df379"
    },
    {
      "id": "ship/claimyour.gold/b9373f22b963",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T05:17:28Z",
      "kind": "infra",
      "title": "Migrate the streak services to postEntry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Six write sites across streakClaim, streakRescueCore and streakShield.\n\nbuyStreakShield is the worst thing in this batch and possibly the worst key in\nthe codebase: its idempotency key was\n`streak-shield-${customerId}-${Date.now()}`. A key that differs on every\nretry is not a key — it is the absence of one, dressed up as its presence.\nThe rest of that function matched: a balance read, then `wallet.update`, then\n`goldLedger.create`, three statements with no transaction between them, so a\nfailure in the middle charged a hunter for a shield nothing recorded. Its\nentry also named the literal `assetId: 'flashy-gold'` rather than the Asset\nrow's id — the same bug apprenticeService had, so every row either service\nwrote points at an asset that does not exist. The shield row is now created\nfirst inside a transaction and the charge is keyed to it.\n\nclaimDailyStreak multiplied the tier gold by an arbitrary rush multiplier and\nwrote the unrounded product. Gold is a 2-decimal asset; the extra digits were\nnever payable. Rounded to the cent, and keyed one claim per hunter per UTC day\n— which is what the streakLastAt read inside the transaction was reaching for.\n\nstreakRescue's rescueBond upsert was already idempotent while the payout\nsitting beside it was not, so a retry re-created no bond and paid the rescued\nhunter a second time. Both now key off the same rescuer/rescued/week triple.\n\npurchaseStreakShield and giftStreakShield used a conditional `updateMany` with\na `gte` guard — a correct compare-and-swap, and the only two sites in this\nmigration that were genuinely safe against overdraft. They still had no key,\nso a retry charged twice for one shield. The purchase keys on the shield slot;\nthe gift creates its ShieldGift row first and keys on that.\n\nNoted while here, not fixed: there are two parallel shield systems in this\nfile — purchaseStreakShield/giftStreakShield drive a `customer.streakShields`\ncounter at SHIELD_COST, while buyStreakShield creates StreakShield rows with\ndur",
      "refs": {
        "commit": "b9373f22b9634a512265096b29ca592db05bb905"
      },
      "digest": "d2aa39f1559aaf3f11e6679093bfa5cc09b8bb0ac99c4f1e1df5ce6e21b31e95"
    },
    {
      "id": "ship/claimyour.gold/f14d457d8be4",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T05:09:29Z",
      "kind": "infra",
      "title": "Migrate the three bounty services to postEntry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Eight write sites across bountyCore, bountyResolution and bountyReward. Most\nwere already inside a transaction — what none of them had was a key, so every\nretry path in this subsystem could pay twice.\n\nThe two ungated ones are the notable finds. awardWelcomeBonus had no\nidempotency check of any kind: its only guard is a Redis read that says a\nbounty is active this week, which is not the same as saying this recruit was\nalready paid. awardMentorGold had none either. Both are invoked\nfire-and-forget from the first streak claim, so any retry of that path paid\nthem again. Keyed on the recruit now.\n\nbountyResolution's prize payout matters more than it looks: resolveSingleBounty\nsits inside a retry loop that re-enters on failure and logs MANUAL\nINTERVENTION REQUIRED when it gives up. A retry after a partially-applied\ntransaction had nothing stopping it paying a winner a second time. Each prize\nis keyed by placement.\n\npostBounty and contributeToBounty both did a read-then-decrement inside their\ntransaction. postEntry re-checks the balance where the gold actually moves, so\nthose reads are gone; InsufficientBalanceError maps back to the 402 the API\ncontract expects.\n\nRefunds share one key per bounty across both paths that issue them —\ncancellation and no-recruit resolution — because a stake comes back once,\nwhichever way the bounty ends.\n\nEntry type is REVERSE rather than a refund-specific type; the enum has\nREFUND_BOMB but nothing generic, and a returned stake is a reversal.\n\nAllowlist 28 → 25.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "f14d457d8be47d7e03f3e86c64c63df8431833a8"
      },
      "digest": "a55e523fcb60ee991d795829f05f0a6c9a0eb29859e8b22612b4c47d2d95011d"
    },
    {
      "id": "ship/claimyour.gold/1d01110a75dc",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T05:02:38Z",
      "kind": "infra",
      "title": "Migrate referral and activation payouts to postEntry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "referral.ts held three separate reward paths, all now on the primitive:\n\nactivateReferral paid the referred hunter and the referrer as two\nreward_ledger + wallet.upsert pairs. They were at least inside a transaction;\nwhat they lacked was a key, so the transaction's own idempotency rested\nentirely on the referral status flip above it. Each credit now carries\n`referral-referred:{referralId}` / `referral-referrer:{referralId}` and joins\nthat same transaction.\n\ngrantRushInviteBonus wrote its reward row and its wallet credit concurrently\nunder `Promise.all`, outside any transaction — either could land without the\nother, and the whole thing was gated by a `findFirst` check-then-act that two\nconcurrent activations both pass. Keyed on `rush-invite:{referralId}:{rushId}`.\n\ncheckAndGrantMilestones was well-formed apart from the guard against paying\ntwice living in a different table (milestoneGrant) from the payment.\n\nBoth bonus multipliers rounded to FOUR decimal places. Gold is a 2-decimal\nasset, so a Gold Rush multiplier landing on 14.375 wrote a balance whose last\ntwo digits were not payable — they accumulated as drift and postEntry rejects\nthem outright. Rounded to the cent at both multiplier sites.\n\nactivationService had the worse of the two problems. Its starter quest grant\nat least used questCompletion as a gate; the referral-source tier welcome\nbonus had no idempotency gate of any kind — not a completion row, not a grant\nrecord, nothing. It fires on every starter-quest grant, so any path that\nre-ran activation paid the welcome bonus again. Now one per hunter, keyed.\n\nFour test suites rewritten onto postEntry, including transaction mocks that\nexecute their callbacks rather than stubbing them away.\n\nAllowlist 30 → 28.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "1d01110a75dca8188d4f39f386e86faf8f7c08f5"
      },
      "digest": "128432e0c6fb8cf978ebe0f35afaed26da4489aeee1da27f67397432481de607"
    },
    {
      "id": "ship/claimyour.gold/df69312566d4",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T04:50:51Z",
      "kind": "infra",
      "title": "Migrate quest completion and apprentice milestones to postEntry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "quests.ts carried three copies of the same completion block — manual\ncompletion, page-visit completion and server auto-completion each had their\nown `questCompletion.create` + `rewardLedger.create` + `wallet.upsert`\ntransaction. Migrating the duplication three times would have preserved it, so\nthe three collapse into one `recordQuestCompletion` helper.\n\nThe reward now posts through postEntry keyed on `quest:{customerId}:{slug}`.\nThe old version had no key of its own: it leaned entirely on questCompletion's\nunique constraint aborting the transaction. That does stop a double-pay on\nretry, but it records nothing about the balance the credit moved from, and it\nmeans the guard against paying twice lives in a different table from the\npayment.\n\napprenticeService.rewardMilestone credited the mentor's wallet, stamped the\nmilestone and wrote the gold_ledger row as three separate awaits with no\ntransaction. A failure after the first paid the mentor without stamping the\nmilestone, so the `match[rewardField] !== null` check let the next run pay\nthem again — and the ledger row meant to catch that came last, making it the\nstatement most likely to be missing. That row also named a literal\n`assetId: 'flashy-gold'` rather than the Asset row's id, so every entry this\nservice wrote pointed at an asset that does not exist. The stamp and the\ncredit now share one transaction.\n\nNeither path had any test coverage. Quest completion — a live earn path on\nthree routes — now has 14 tests; rewardMilestone's existing tests were\nrewritten onto postEntry with a transaction mock that actually executes the\ncallback.\n\nAllowlist 32 → 30.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "df69312566d421bd1a33863b714a9bd364414390"
      },
      "digest": "ebca2764987017b74359a28ed145eef5e841bf61ab4335379fe32ad41e852a77"
    },
    {
      "id": "ship/claimyour.gold/b61c8c99f521",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T04:43:22Z",
      "kind": "infra",
      "title": "Migrate comeback bonus, streak challenge and crew hunt payouts to postEntry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Three more earn paths onto the ledger primitive. Each had a distinct way of\npaying gold without a durable record of having paid it.\n\ncomebackBonusService.maybeAwardComebackBonus moved the wallet with a bare\n`wallet.update` and then wrote the gold_ledger row as a separate statement,\noutside any transaction — a failure between the two credited gold that nothing\nrecorded. The row it wrote claimed `balanceBefore: 0, balanceAfter: amount`\nregardless of what the hunter actually held, so the audit column was fiction\neven when both statements landed. This function moves gold and had no test\ncoverage at all; it now has four.\n\nstreakChallengeService.resolveStreakChallenge wrote the reward_ledger row and\nupserted the wallet as two separate awaits, unkeyed. A failure between them\nrecorded a win nobody was paid for, and re-resolving an already-resolved\nchallenge paid the winner again.\n\ncrewHuntPartyMutationService.resolveParty batched the member status flip, the\nreward row and the wallet upsert into an array-form `$transaction`, which\ncannot express the dependency between them, and carried no idempotency key —\na re-run of the resolve job paid the same membership row twice. Converted to\nthe callback form with the tx threaded into postEntry, keyed on the membership\nrow. This service had no tests either; it now has seven covering the payout,\nthe threshold, the resolve race and per-member failure isolation.\n\nAllowlist 35 → 32.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "b61c8c99f521ec05024d0b13e68d53d17c9ac392"
      },
      "digest": "687611aa3968acc1278419b9635982d2646990b6dbb306d40fff4d59d940f2ac"
    },
    {
      "id": "ship/claimyour.gold/deba4289cf1a",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T04:34:40Z",
      "kind": "infra",
      "title": "Retire creditWallet — the last unrecorded balance write",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Migrated its three callers onto postEntry and deleted the function:\n\n  claimService         — partner points claimed for gold\n  redeemService        — partner points redeemed for gold\n  duelChallengeService — staked duel payout and both tie refunds\n\ncreditWallet incremented wallet.goldBalance with no ledger entry of any\nkind. The previous commit exposed it by taking lib/wallet.ts off the\nlegacy allowlist; this removes it.\n\nduelChallengeService is the one worth noting: both stakes are taken by\ndebitWalletWithLedger when a duel is accepted, and the payout went back\nout through creditWallet. So one side of every wager was recorded and\nthe other was invisible — the debit was in gold_ledger, the credit\nexisted only as a balance change. Reconciliation would read the loser as\ncorrect and the winner as unexplained surplus.\n\nEach caller had a natural key available and now uses one: the\ntransaction row for claims and redemptions, the duel id for stakes.\n\ntsc clean, eslint clean, 1213 suites / 10607 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "deba4289cf1a42ec172940d31c1219f2334b786b"
      },
      "digest": "17f368965b8bbc09017e2116b390fcd05a06d1cad93e1bb8601789f2a7c3d3bd"
    },
    {
      "id": "ship/claimyour.gold/298f34789d4e",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T04:23:13Z",
      "kind": "fix",
      "title": "Fix credits that were recorded but never paid, in lib/wallet",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 36 -> 35.\n\ncreditWalletWithLedger WROTE A LEDGER ROW AND NEVER TOUCHED THE WALLET.\n\nThere is no paired wallet write in the function, no caller performs one,\nno event listener does it, and nothing anywhere in the codebase\nrecomputes wallet.goldBalance from the ledger. Every credit through this\nhelper was recorded and never paid. Its callers are not marginal:\n\n  goldBombLifecycleService  — bomb claims\n  vaultService              — vault unlocks\n  shareQuestService         — share quest rewards\n  campaignWorker            — campaign payouts\n  redemptionMutationService — redemption refunds\n\nIts balanceBefore was computed from a gold_ledger aggregate while\ndebitWalletWithLedger read wallet.goldBalance, so the two halves of the\nsame file did not agree on what a balance was. The existing tests did not\ncatch it because they asserted the ledger row and the emitted event, and\nnever the balance.\n\nBoth helpers now go through postEntry, which writes the entry and moves\nthe balance in one transaction.\n\nSIGN CONVENTION\n───────────────\ndebitWalletWithLedger stored a POSITIVE amount while decrementing the\nwallet. That is the second of the two contradictory conventions named in\nledgerReconciliationService's header — the reason SUM(amount) is not a\nbalance. Callers still pass a positive number; the entry is negated on\nthe way in, so a debit is now a negative amount like every other debit.\n\nRemoving this file from the legacy allowlist also exposed creditWallet(),\na bare increment with no ledger entry, which the guard could not see\nwhile the whole file was exempt. Three callers remain — claimService,\nredeemService, duelChallengeService — each with a natural key available.\nExempted inline with those callers named, so the rest of wallet.ts stays\nguarded and the debt is discoverable rather than invisible.\n\ntsc clean, eslint clean, 1213 suites / 10610 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_",
      "refs": {
        "commit": "298f34789d4e5800fddcdc1c1bc28ef791a1e4d9"
      },
      "digest": "d2c90302a92098b34df6307f774959107bd1d4c5bdeb5e2f86754eb346a1bbe4"
    },
    {
      "id": "ship/claimyour.gold/4c2a92cc36bd",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T04:06:14Z",
      "kind": "infra",
      "title": "Migrate squad goal and slot bonus",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 38 -> 36.\n\nMigrated: squadGoal, slots. Both credited a hunter by writing the reward\nrow and the wallet as two independent operations, which is the shape\nthat produces a recorded payment nobody received.\n\n- squadGoal wrote the reward row first and the wallet second, wrapped in\n  Promise.allSettled. A member whose credit failed was recorded as paid\n  and silently dropped, with the rejection swallowed by allSettled. The\n  payout is now a single write per member, and a failure for one member\n  is logged rather than lost — without taking the rest of the crew down.\n\n- slots ran the reward row and the wallet credit CONCURRENTLY under\n  Promise.all, so either could succeed while the other failed: a recorded\n  bonus nobody received, or gold nothing accounted for. Its findFirst\n  idempotency check was also a check-then-act; the unique key settles it.\n\ntsc clean, eslint clean, 1213 suites / 10614 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "4c2a92cc36bd92290769afd066d3f1de985e1fad"
      },
      "digest": "b2d66fad9e58b19fff49697f30824c04c6bbd3d4ba1bfc90cf282c5115be4119"
    },
    {
      "id": "ship/claimyour.gold/4c809cbdb0f2",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T03:59:14Z",
      "kind": "infra",
      "title": "Migrate daily challenge, winback and crafting",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 41 -> 38.\n\nMigrated: dailyChallengeComplete, winback, craft.\n\n- dailyChallengeComplete used a bare wallet.update, which throws for a\n  hunter with no wallet row. The conditional update above it had already\n  marked the challenge completed, so the failure rolled that back — but\n  every retry hit the same missing wallet and failed the same way. The\n  existing test suite has a regression guard for exactly this\n  \"claimed but never paid\" shape; the wallet.update was still the way in.\n\n- winback checked idempotency with findFirst-then-write, then made three\n  separate writes with no transaction: wallet, ledger row, claimed flag.\n  A failure after the first left a hunter credited with nothing recording\n  it, or recorded and never marked claimed. All three now commit\n  together and the unique key settles the race.\n\n- craft deducted the gold cost and wrote its reward row inside a proper\n  transaction, but with no key and a balance check from the pre-flight\n  outside it. postEntry re-checks the balance where the gold actually\n  moves. Crafting has no natural id, so the key carries the moment the\n  craft ran — enough to make one call's retry idempotent without stopping\n  a hunter crafting the same recipe again.\n\ntsc clean, eslint clean, 1213 suites / 10614 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "4c809cbdb0f2041eb6901a65382a57cbed6ee727"
      },
      "digest": "9d36b18eff1cf557ef21e49e75cad975d6490017ed947076443c879d4b5c8a55"
    },
    {
      "id": "ship/claimyour.gold/ccdec9185dc7",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T03:28:43Z",
      "kind": "fix",
      "title": "Stop the migration silently shrinking what hunters are paid",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "No change to the legacy writer count — this fixes damage the migration\nitself was doing.\n\nTHE PROBLEM\n───────────\nWS-1 moves write paths off reward_ledger onto gold_ledger. But 65 read\nsites across ~50 files still ask reward_ledger \"how much has this hunter\nearned?\", and every one of them sees a smaller number each time a writer\nmoves across. Nothing errors. The numbers just quietly get smaller.\n\nFor a leaderboard that is cosmetic. Two of them decide money:\n\n  - milestoneService gates milestone bonuses on lifetime earnings. A\n    hunter whose earn paths had migrated stopped crossing thresholds and\n    silently stopped being paid. milestoneService pays through postEntry\n    now, so its own awards did not feed back either.\n\n  - referralCutService sums each recruit's weekly earnings to size the\n    referrer's cut. Recruits looked less productive than they were, so\n    referrers were paid less.\n\nBoth were actively degrading with every batch of this migration.\n\nTHE FIX\n───────\nNew src/ledger/earnings.ts: earningsByCustomer() and totalEarned(), which\nsum both ledgers over an optional window. Type exclusions translate\nacross because transactGoldAward writes the RewardType value straight\ninto sourceType, so `rewardType != X` and `sourceType != X` select the\nsame rows either side. When reward_ledger is retired, delete the legacy\nhalf of each query and these collapse to one groupBy.\n\nApplied to the two money-deciding readers. Two display readers were\nalready fixed the same way in earlier batches (seasonLeaderboard's GOLD\nboard, tieredReferralNightlyJob's weekly earnings).\n\nThe remaining ~60 read sites are analytics, feeds, digests and social\nproof. They are degrading too, and are worth a pass, but none of them\ndecides a payout.\n\ntsc clean, eslint clean, 1213 suites / 10614 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "ccdec9185dc7de111dcd0a0c055b47f98bca6933"
      },
      "digest": "9c25c5e8fa18013165dd62ed32033fcbd57be791f032031c9f92c2c43a681584"
    },
    {
      "id": "ship/claimyour.gold/57d397c6f786",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T02:56:59Z",
      "kind": "infra",
      "title": "Migrate recruitment drive, tiered referral and step quests",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 44 -> 41.\n\nMigrated: recruitmentDrive, tieredReferral, stepQuest.\n\n- recruitmentDrive keyed its ledger row on Date.now(), so it deduplicated\n  nothing, and read the balance / updated the wallet / wrote the row as\n  three separate statements with no transaction. Now keyed per drive and\n  referrer. That narrows previous behaviour, which paid on every recruit\n  — but previous behaviour was also unbounded and unrecorded, so the\n  narrowing is flagged in the code: if the bonus is meant to be per\n  recruit, the recruit's id belongs in the key.\n\n- tieredReferral had no idempotency at all, and the nightly job that\n  drives it guards itself with an in-memory lastRunDate. A redeploy on\n  the same day re-ran the job and paid every residual a second time.\n  Residuals are now keyed to the UTC day, tier and referrer.\n\n- stepQuest wrote reward_ledger + wallet inside a proper transaction but\n  with no key; the completion row is unique on customer/quest/step, so\n  the ledger key now matches it and the two guards agree.\n\nAlso fixed a second draining reader, the same defect found in\nseasonLeaderboard: tieredReferralNightlyJob computed each hunter's\nweekly earnings from reward_ledger alone — the table this migration is\nemptying. Residuals would have quietly shrunk as more of the economy\nmoved to gold_ledger, with nothing to indicate why. It now sums both.\n\ntsc clean, eslint clean, 1212 suites / 10603 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "57d397c6f78692b30fe93f79bdd6c770261ded61"
      },
      "digest": "cbab36490f50704b0c2e2a352664a0ddbe28c6480b20718c3bb489aa4ef928e8"
    },
    {
      "id": "ship/claimyour.gold/e81811ca77c7",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-13T01:57:29Z",
      "kind": "infra",
      "title": "Migrate cascade, crew merger and war prize pool",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 47 -> 44.\n\nMigrated: cascadeReward, crewMerger, crewWarPrizePool.\n\n- cascadeReward computed shares with toFixed(4) against an asset that has\n  two decimals, so an L2 bonus could be 0.1235 — an amount gold cannot\n  represent. Those sub-cent tails were being added to a Float wallet\n  where they could not be expressed, and the ledger rejects them\n  outright. Shares are now rounded to the asset's precision, so the\n  recorded amount and the moved amount are the same number.\n\n- cascadeReward also wrote the reward row and the wallet as two separate\n  awaits inside a try/catch that swallowed any failure into a warn\n  reading \"skipped (duplicate or error)\". A failed wallet write left a\n  reward row and no gold, logged as if nothing had gone wrong. Its\n  docstring called the referral its \"idempotency anchor\"; nothing\n  enforced that until now, so a retry paid the whole chain again.\n\n- crewMerger guarded itself with findFirst-then-write, a check-then-act\n  that two concurrent merges both passed. It also returned early when the\n  captain had no wallet row, silently denying the bonus to any captain\n  who had never held gold.\n\n- crewWarPrizePool used wallet.updateMany, so a winning member with no\n  wallet row was skipped and their share of the prize pool evaporated —\n  while the reward row still recorded them as paid.\n\ntsc clean, eslint clean, 1212 suites / 10602 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "e81811ca77c7b4e5b3a0de863af28674b138913c"
      },
      "digest": "5050494f6d59ef2a3307b742bfd5419dd77e00b12e61e439a7eb7e5418a32fc9"
    },
    {
      "id": "ship/claimyour.gold/7478fbc718e6",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T23:20:15Z",
      "kind": "infra",
      "title": "Migrate quest streak, signup milestone and redemption",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 50 -> 47.\n\nMigrated: questStreak, signupMilestone, inventoryRedemption.\n\n- questStreak read the balance, updated the wallet, then wrote the ledger\n  row as three separate statements with no transaction. The recorded\n  before/after pair could describe a balance that had already moved, and\n  a failure after the wallet write left the credit unrecorded.\n\n- signupMilestone used a bare wallet.update, which throws for any hunter\n  with no wallet row. That took the whole transaction down and left the\n  milestone ungranted — so the same hunter failed again on every later\n  run, permanently.\n\n- inventoryRedemption was the exception: its conditional\n  `updateMany ... where goldBalance >= price` was one of the few\n  genuinely correct debits in this codebase, checking and moving in a\n  single atomic statement. postEntry does the same check in the same\n  transaction and additionally records the movement, so nothing is lost.\n  The stock claim now runs first: the debit used to lead, so a hunter who\n  lost the race for the last unit had their gold taken and returned only\n  by the rollback. Correct, but it made statement ordering load-bearing\n  for no reason.\n\nThe redemption row is now written before the charge so the debit has a\nstable key to be idempotent on; the transaction rolls it back if the\ncharge fails.\n\ntsc clean, eslint clean, 1212 suites / 10601 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "7478fbc718e631ebb0634bd794016d67cac4fc78"
      },
      "digest": "a9eda77241a7383c28ef1c899a02279c788d0c247900f4fe28ee8663db3cac7c"
    },
    {
      "id": "ship/claimyour.gold/473ea54a573e",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T22:53:16Z",
      "kind": "infra",
      "title": "Migrate duel, golden invite and daily spin onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 53 -> 50.\n\nMigrated: hunterDuel, goldenInvite, dailySpin.\n\nDefects found and fixed:\n\n- hunterDuel never escrows either wager. challengeToDuel and acceptDuel\n  check the balance and then leave the gold in the wallet, so by the time\n  a duel resolves the loser may have spent it. The old code decremented\n  anyway: the wallet went negative and the ledger row asserted a\n  balanceAfter nobody held. The debit now carries allowNegative so the\n  debt is recorded rather than hidden — which is why this is two\n  postEntry calls rather than a postTransfer. Escrowing at accept time is\n  the real fix and is a design change, so it is flagged in the code\n  rather than made here.\n\n- hunterDuel also read both balances outside the transaction that moved\n  them.\n\n- goldenInvite credited the wallet and wrote the reward row as two\n  separate awaits with no transaction and no idempotency, so a failure\n  between them credited gold nothing recorded, and a retry credited a\n  second time.\n\n- dailySpin wrote wallet + reward_ledger in an array transaction. Its\n  spin row already had a unique constraint doing the race-guarding; the\n  ledger key now matches that same pair, so the two guards agree.\n\ntsc clean, eslint clean, 1212 suites / 10600 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "473ea54a573e02602b9b815469710bf1b82485fc"
      },
      "digest": "c821f3404c9465406b14dda6297992eebbe4b3ad0846e23de6adb4b6d419e1ef"
    },
    {
      "id": "ship/claimyour.gold/0210e798ccde",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T22:38:39Z",
      "kind": "other",
      "title": "Pay the remaining recorded-but-never-paid rewards",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 59 -> 53.\n\nMigrated: allianceRaid, bridgeNodeMission, chainTournament, churnRescue,\ncityRecruit, referralSprint.\n\nThis closes the class found in the previous batch. Of the 13 services\nthat wrote a reward_ledger row and never touched a wallet, 11 never read\nthose rows back — the row was not a shadow balance, just a record of a\npayment that did not happen. All 11 are now migrated:\n\n  alliance raid spoils        both captains recorded, neither paid\n  bridge node mission bonus   recorded, never paid\n  chain tournament prize      champion recorded, never paid\n  churn rescue bonus          recorded, never paid\n  city recruit race pot       top recruiters recorded, none paid\n  referral sprint prizes      ranks 1-3 recorded, none paid\n  (plus the five in cdc9bef)\n\nThe two that DO read reward_ledger back as a balance are still excluded\nand still need a decision — predictionMarketService and\ncrewSynergyService. Those are shadow economies, not bugs, and unifying\nthem changes what the features cost users.\n\ntsc clean, eslint clean, 1212 suites / 10600 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "0210e798ccdea52a18605d270f21ae7c82d851b7"
      },
      "digest": "823261a5d7e5cc77fad5b8419cbd037a46b0113570f602de63a237dda0291734"
    },
    {
      "id": "ship/claimyour.gold/cdc9bef06c24",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T21:49:01Z",
      "kind": "other",
      "title": "Pay the rewards that were only ever recorded",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 64 -> 59.\n\nMigrated: streakSupercharge, cityRivalry, seasonLeaderboard,\nsocialAmplifier, inviteChallenge.\n\nREWARDS THAT WERE NEVER PAID\n────────────────────────────\n13 services write a reward_ledger row and never touch a wallet. 11 of\nthem never read those rows back either, so the row is not a shadow\nbalance — it is simply a record of a payment that did not happen. Five\nare fixed here:\n\n- streakSupercharge.purchaseShield recorded a NEGATIVE reward row and\n  debited nothing, so streak shields were free.\n- streakSupercharge streak-milestone bonuses: recorded, never paid.\n- cityRivalry catch-up bonus: every hunter in the trailing city recorded\n  as paid, none of them paid.\n- seasonLeaderboard season rewards: top-10 winners recorded as paid,\n  none of them paid.\n- socialAmplifier share-conversion bonus and inviteChallenge completion\n  bonus (both parties): same.\n\nTHE LEADERBOARD THAT WAS DRAINING\n─────────────────────────────────\nseasonLeaderboard's GOLD board scored hunters off SUM(reward_ledger) —\nthe very table this migration is emptying. Left alone, hunters would\nhave silently scored lower each season as more of the economy moved to\ngold_ledger. It now sums both tables, so seasons straddling the\nmigration are scored whole. The reward_ledger half can be dropped once\nthat table is retired.\n\nTwo of the 13 are NOT included and need a decision, because they read\nreward_ledger back as a balance rather than as a record:\n\n- predictionMarketService has a private getBalance() that sums\n  reward_ledger.amount. It checks affordability against that, stakes\n  against that, and pays winnings into it. The wallet is never involved.\n  It is a self-contained shadow economy — a fourth balance. Unifying it\n  makes predictions start costing real gold, which is a product change.\n- crewSynergyService aggregates reward_ledger the same way.\n\ntsc clean, eslint clean, 1212 suites / 10600 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Sessio",
      "refs": {
        "commit": "cdc9bef06c2473f596cfc95fdc03526bcf5db45e"
      },
      "digest": "5a1c5ed48aefdd9b0d40c90e76fd6896858b27b5da23d218cea4936b8a68b332"
    },
    {
      "id": "ship/claimyour.gold/3a09ad231314",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T21:36:07Z",
      "kind": "infra",
      "title": "Retire the reward_ledger award path onto postEntry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 67 -> 64.\n\ngoldTransactionService was the shared primitive behind four earn paths\n(milestone, referral weekly cut, referral chain bonus, referral race\nprize). It wrote reward_ledger + wallet itself, which is precisely the\nsecond parallel ledger reconciliation has to guess between. It now posts\nthrough postEntry, so those four paths land in gold_ledger with one sign\nconvention and real atomicity.\n\nIts idempotencyKey parameter was optional AND ignored — the doc said\n\"the caller is responsible for deduplication\", so the parameter looked\nlike protection while providing none. It is now required, and all four\ncallers supply a key derived from the event:\n\n  milestone:<customer>:<slug>\n  referral-cut:<referrer>:<weekKey>\n  chain-bonus:<trigger>:<ancestor>\n  referral-race:<raceId>\n\nTwo of those callers guarded themselves with a check-then-act that races\nwith itself (referralCut's findFirst, referralChainBonus's\nCHAIN_BONUS_TRIGGER lookup outside the transaction). Those races are now\nsettled by the unique key rather than by luck.\n\nAlso fixed, and the worst of this batch:\n\n- crewRecruitmentXpService.resolveWeeklyRecruitmentWar wrote a\n  reward_ledger row per member of the winning crew and NEVER TOUCHED A\n  WALLET. The crew was recorded as paid 50 FG each and received nothing.\n  It also had no idempotency, so re-running rewrote the rows.\n\nreferralChainBonusService keeps one rewardLedger.create behind an inline\nguard exemption: it is a zero-amount marker recording that a hunter's\nthreshold crossing has been processed, so the ancestor walk can\nshort-circuit. No gold moves through it.\n\ntsc clean, eslint clean, 1212 suites / 10598 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "3a09ad231314693a6a4f6f99bffa3cbc5f60803b"
      },
      "digest": "326eed85670d0c3cc5f0b330794cbf73050f18d6fd1debc24a7bbc31e3d0467a"
    },
    {
      "id": "ship/claimyour.gold/e5418058425f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T19:34:08Z",
      "kind": "fix",
      "title": "Fix retirement mint; migrate riddle and both retirement paths",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 70 -> 67.\n\nMigrated: retirementService, retirementLegacyService, dailyRiddle.\n\nTHE MINT\n────────\nretirementService distributed ten percent of a retiring hunter's balance\nto their crewmates and NEVER DEBITED THE RETIREE. Every retirement minted\nthat ten percent — the crew was paid and the retiree kept their gold.\nIt is a transfer, so both paths now go through postTransfer and the two\nsides commit together.\n\nTHE DUPLICATE\n─────────────\nretirementService and retirementLegacyService are competing\nimplementations of the same feature, both live, behind two separate\nroutes:\n\n  /api/v1/portal/retire      -> retirementService      (minted)\n  /api/portal/retire/legacy  -> retirementLegacyService (transferred)\n\nThey already shared an idempotency key, which is the only reason a\nhunter hitting both endpoints was not paid out twice. That shared key is\npreserved deliberately and documented in both files: whichever runs\nfirst wins, the other is a no-op. Which of the two should survive is a\nproduct decision, not a cleanup, so both are left in place.\n\nAlso fixed:\n\n- retirementService reported `perMember * crewMembers.length` as the\n  amount distributed, counting members it had skipped for having no\n  wallet row, so it claimed to have moved gold it had not.\n\n- retirementLegacyService appended the retiree's debit to its operation\n  array behind an `as never` cast to get it past the type checker, and\n  every credit claimed balanceBefore 0 / balanceAfter share.\n\n- dailyRiddle keyed its prize on hunter-and-day rather than the day, so\n  a second solver could be paid for the same riddle if the winnerId\n  guard were ever bypassed. Its ledger row also claimed balanceBefore 0.\n\ntsc clean, eslint clean, 1212 suites / 10595 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "e5418058425f1aa67df266c3b999b4d595528dc1"
      },
      "digest": "91fba70a174fa61ab2bb0a331d765a7941cb9207207765855bfe126d43194652"
    },
    {
      "id": "ship/claimyour.gold/0226fd51093f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T19:21:56Z",
      "kind": "infra",
      "title": "Migrate four hand-rolled ledger writers; refresh reconciliation doc",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 74 -> 70.\n\nMigrated: crewMergerLegacy, crewTreasuryRaffle, weeklyLeaguePayout,\ndebtForgiveness. All four wrote a ledger row already — just a wrong one.\n\nDefects found and fixed:\n\n- crewTreasuryRaffle keyed its entry on Date.now(), so it deduplicated\n  nothing, and drew its winner with Math.random(). This picks who gets\n  paid, so it now uses randomInt from crypto, as the city lottery draw\n  does. Its balanceBefore was also read outside the transaction.\n\n- crewMergerLegacy recorded balanceBefore 0 / balanceAfter 30 for every\n  captain regardless of what they held.\n\n- weeklyLeaguePayout wrote reward_ledger plus a bare wallet.update, which\n  throws for any winner with no wallet row — that took the whole\n  transaction down and left them unpaid AND unmarked, so the next run\n  retried and failed again.\n\n- debtForgiveness read the nominator's balanceBefore outside the\n  transaction that moved it.\n\nNoted, not changed: the treasury raffle takes 100 FG from the crew\ntreasury and pays 80 to the winner. The 20 FG difference is burned. That\nis existing behaviour and presumably an intended rake, but it was\ninvisible until both sides went through the ledger.\n\nAlso refreshed the ledgerReconciliationService header, which still\ndescribed 61 silent writers and named services migrated weeks ago. The\nderivation is unchanged and still correct; what changed is how to read\nthe output, which the comment now explains: drift from activity before\nthe migration is permanently ambiguous, drift after it is a real defect.\n\ntsc clean, eslint clean, 1212 suites / 10592 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "0226fd51093f273e75b05ac164e12b7890fb4aef"
      },
      "digest": "a48d5e5ee6c5dfa1048dcd00bad0bc145de426615593837a2c7c8c55f20ffddb"
    },
    {
      "id": "ship/claimyour.gold/a1ad53859dbf",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T19:01:14Z",
      "kind": "infra",
      "title": "Migrate party quest and bounty board onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 76 -> 74; silent writers 3 -> 1 (warBet only).\n\nMigrated: partyQuest, bountyBoard — the two largest files in the queue.\n\nDefects found and fixed:\n\n- partyQuest credited its reward with a fire-and-forget\n  `void prisma.wallet.update(...)` whose failure was swallowed into a\n  warn, under a comment calling it \"not critical path\". wallet.update\n  throws for any hunter with no wallet row, so hunters without one were\n  never paid at all and nothing surfaced it. The member was also marked\n  done in redis BEFORE the credit, so a failed payout locked them out of\n  the window permanently. The payout is now awaited and keyed, and the\n  done-mark only happens once the gold has landed.\n\n- bountyBoard could pay the same bounty twice. claimBounty removed the\n  ZSET member and credited unconditionally, so two simultaneous claimers\n  were each paid the full reward; a cancel racing a claim did the same.\n  ZREM now decides the winner — it returns the number of members actually\n  removed, so exactly one caller proceeds.\n\n- postBounty debited the poster and then wrote to redis, so a redis\n  failure took the gold and left no bounty to claim, cancel or expire it\n  back. The order is inverted and a failed charge takes the bounty back\n  off the board.\n\ntsc clean, eslint clean, 1212 suites / 10589 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "a1ad53859dbf5becc5e72e22b8a58f0e29a92ee8"
      },
      "digest": "d46c6acfe77904133bceabde2568a874737091cf9bc2af92bb37905f2d9f1e87"
    },
    {
      "id": "ship/claimyour.gold/655cdabd6268",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T18:50:02Z",
      "kind": "infra",
      "title": "Migrate lottery, rivalry and prestige spend onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 79 -> 76; silent writers 6 -> 3.\n\nMigrated: cityLottery, hunterRivalry, economySpend.\n\nDefects found and fixed:\n\n- economySpend charged the hunter, wrote the purchase record and granted\n  the buff as three separate awaits with no transaction between them. A\n  failure after the debit took up to 1000 FG (LEGEND_SPOTLIGHT) and\n  delivered nothing. It also had no idempotency, so a double-click was\n  two purchases. The two buff-granting branches were near-identical\n  copies; they now share one table.\n\n- cityLottery checked the balance outside the transaction that spent it,\n  and discarded a cityFund read it never used. The fund decrement was\n  written as `prizePool - cityShare`, which is just the winner's prize\n  said the long way round.\n\n- hunterRivalry paid the winner with an unrecorded wallet upsert.\n\nNoted, not changed — it decides what the feature means, not how it is\nwritten: hunterRivalry picks its winner on total wallet balance, not on\nwhat either hunter earned that week. The wealthier hunter therefore wins\nregardless of activity, while the losing DM tells them they were\n\"outearned\". gold_ledger can now answer the weekly-earnings version.\n\nAdded tests/services/hunterRivalryService.test.ts — it had none.\n\nwarBet is deliberately left on the list; its re-charge behaviour is still\nan open product question.\n\ntsc clean, eslint clean, 1212 suites / 10584 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "655cdabd6268dfd674e4bd6674e2f3ae3e9c7300"
      },
      "digest": "b75f44ad13f35c03183e7537ccadcf89ec7e69ea4f0e83de3a6c546d6c08ebf0"
    },
    {
      "id": "ship/claimyour.gold/4641654d4c2d",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T18:27:29Z",
      "kind": "infra",
      "title": "Migrate five faction and pass paths onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 84 -> 79; silent writers 11 -> 6.\n\nMigrated: factionWarTribunal, factionWar, subscriptionPass, mentorTip,\ncrewEmbassy.\n\nDefects found and fixed:\n\n- subscriptionPass charged 500 FG and granted the pass as two separate\n  awaits with no transaction at all. A failure between them took the\n  gold and gave the hunter nothing. This is the largest single charge in\n  the codebase and it had no atomicity whatsoever.\n\n- factionWarTribunal resolved the tribunal and paid the redistribution\n  in separate writes, so a failure in the payout loop left the tribunal\n  RESOLVED with nobody paid and the status guard blocking any retry. Its\n  overturn path had no test at all; the suite passed because it never\n  reached the money.\n\n- factionWar paid the winning faction with Promise.all over unrecorded\n  wallet upserts. The weekKey guard stops a second run but did nothing\n  for a run that died part way through.\n\n- crewEmbassy and mentorTip both checked the balance outside the write\n  that spent it.\n\nNoted, not changed: mentorTip is a burn, not a transfer — the 5 FG\nleaves the mentor and reaches nobody. That is existing behaviour;\nrecording it through the ledger only makes it visible.\n\ntsc clean, eslint clean, 1211 suites / 10570 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "4641654d4c2dc821f1b497fe3ce1685ec9094e43"
      },
      "digest": "f401b65d986a92e6277e71403e33178d3adb0549fd1e771595870ef223c6d1a2"
    },
    {
      "id": "ship/claimyour.gold/f4a7b3b27c96",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T18:14:25Z",
      "kind": "infra",
      "title": "Migrate five more silent paths onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 89 -> 84; silent writers 16 -> 11.\n\nMigrated: socialShare, seasonalBounty, secretMission, streakRecovery,\nmentorCohort.\n\nDefects found and fixed:\n\n- mentorCohort's captain bonus paid cohorts.length * 20 on every call\n  with nothing recording it, so calling it twice paid the captain twice\n  over for the same cohorts. Now keyed per cohort, so each completed\n  cohort is worth exactly one bonus however often the function runs,\n  while cohorts completing later in the week still pay out.\n\n- streakRecovery had no idempotency: two clicks both read the redis\n  window and both charged 30 FG. Keyed on the open recovery row. Its\n  balance check also ran outside the transaction that spent the gold.\n\n- socialShare used wallet.update, which throws outright for a referrer\n  with no wallet row — that took the whole conversion down with it.\n\n- seasonalBounty wrote the claim row and the reward separately, so a\n  failure between them recorded a claim that paid nothing and the unique\n  constraint then barred that hunter from the bounty for good. Its\n  maxClaimers check was also a count taken before the create; the count\n  now happens inside the transaction, which narrows but does not close\n  the race. A slot-index unique constraint would settle it properly —\n  that is a schema change, noted in the code rather than done here.\n\n- secretMission wrote the completion and the reward as an array\n  transaction with no ledger row.\n\nAdded tests/services/socialShareService.test.ts — it had none.\n\ntsc clean, eslint clean, 1211 suites / 10562 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "f4a7b3b27c96c0e190705ab5b376a8573c833e46"
      },
      "digest": "962735fe162c2ea52c8721cfb73a8ce556d2d13ff19363e94061dbd100600365"
    },
    {
      "id": "ship/claimyour.gold/b4cdb354c45e",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T17:39:28Z",
      "kind": "infra",
      "title": "Migrate five untested minting jobs onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 94 -> 89; silent writers 21 -> 16.\n\nMigrated: goldFountain, crewMilestone, mentorshipGraduation,\nprestigeReset, cityTreasuryRedist. All five minted gold, none had a\nsingle test, and none recorded anything.\n\nDefects found and fixed:\n\n- cityTreasuryRedist had no idempotency of any kind. A second run took\n  another tenth of every crew treasury and paid every eligible hunter a\n  second share. Draining the treasuries and paying the hunters were also\n  separate writes, so a failure between them took the gold out of the\n  treasuries and gave it to nobody. Now keyed per day and atomic.\n\n- prestigeReset pays 200 FG to each of the top three monthly. Nothing\n  marked the job as done, so a second run paid all three again. Keyed to\n  the month.\n\n- crewMilestone wrote the milestone row before paying anyone and outside\n  any transaction, so a failure in the payout loop left the crew recorded\n  as paid and permanently unpayable.\n\n- mentorshipGraduation set its redis flag before writing anything, so a\n  failed payout left the mentor marked as graduated and never paid.\n\n- crewMilestone, cityTreasuryRedist and goldFountain all used\n  wallet.updateMany, which matches existing wallet rows only — hunters\n  without one were skipped entirely.\n\nFound, not fixed — both change who gets paid, so they are decisions\nrather than cleanups:\n\n- goldFountain's eligibility is placeholder logic that reached\n  production. `estimatedEarn` is the member count times 50, not anything\n  the crew earned, so every crew of 10 or more clears the 500 FG/day\n  threshold every day regardless of activity and is paid for it. The\n  original comment says a dedicated EarnEvent table would answer this;\n  gold_ledger now can.\n\n- crewMilestone's thresholds are named WAR_WIN_MILESTONES but the query\n  counts wars COMPLETED with the crew on either side — played, not won.\n\ntsc clean, eslint clean, 1210 suites / 10549 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: ",
      "refs": {
        "commit": "b4cdb354c45e56a0585f8a3f5abcf26421b12b1a"
      },
      "digest": "898e5a2dc961c83f4eb733e518bb51241798dfb88aa4bfe46ce26129b60a635c"
    },
    {
      "id": "ship/claimyour.gold/2cab09322ead",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T17:29:16Z",
      "kind": "infra",
      "title": "Migrate five silent spend and mint paths onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 99 -> 94; silent writers 26 -> 21.\n\nMigrated: crewSpy, goldRain, spyNetwork, retirementVault, streakFreeze.\nAll five moved a wallet with no ledger row at all.\n\nDefects found and fixed:\n\n- goldRain mass-credits every hunter active in the last 48h. It used\n  wallet.updateMany, which matches existing wallet rows only, so any\n  hunter without one was silently rained past. Its 24h cooldown was a\n  redis read followed by a later write, so two triggers could both pass\n  the check, and a rain that failed part way left the cooldown open for a\n  retry that paid the hunters it had already reached a second time. The\n  cooldown is now claimed atomically with SET NX before anyone is paid.\n\n- crewSpy debited 25 FG before gathering the report, so any failure below\n  took the gold and returned nothing. The charge now happens after the\n  report is assembled and is keyed per captain and war, matching the\n  intent the cache key already expressed.\n\n- retirementVault pays back double what was locked. That 100% return over\n  180 days is designed, but it minted the matching half with no ledger\n  row, so it was invisible to every inflation measure the city has. It is\n  now recorded under its own source type.\n\n- spyNetwork and streakFreeze both checked the balance outside the\n  transaction that spent it, so two requests landing together could both\n  pass and take the hunter negative. The check now happens inside\n  postEntry against the balance at the moment the gold moves.\n\nAdded tests/services/spyNetworkService.test.ts — it had none despite\ncharging 50 FG per deployment.\n\ntsc clean, eslint clean, 1205 suites / 10516 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "2cab09322ead34e4ecb94d210789e1a802027cda"
      },
      "digest": "8baaac925e98f85627eedddc233f76c25e50b507b759018cde277ff12492d3d8"
    },
    {
      "id": "ship/claimyour.gold/26334dbb4b64",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T16:38:53Z",
      "kind": "infra",
      "title": "Migrate six more write paths onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 105 -> 99.\n\nMigrated: factionDefection, portalShare, hunterComebackArc,\nprestigeTitle, cityOracle. wealthMilestone is exempted inline instead —\nit touches lifetimeFgEarned only, never a balance.\n\nDefects found and fixed:\n\n- factionDefection keyed its ledger row on Date.now(), so every retry was\n  a fresh 25 FG charge rather than a no-op, and the balance check ran\n  outside the transaction.\n\n- prestigeTitle keyed on the customer id alone. A hunter could be charged\n  for exactly one title ever; the second purchase collided on the unique\n  constraint and took the whole transaction down with it. Now keyed on\n  the title, so each new title is paid for and returning to one already\n  bought is free. Setting the title you already hold is rejected.\n\n- portalShare enforced its 3-per-day cap with a count taken before an\n  unkeyed write, so two shares landing together both read the same count\n  and both paid. The reward is now keyed on the slot it fills, so a race\n  resolves on the unique constraint and the loser is told it was not\n  rewarded. Pre-migration reward_ledger rows still count toward the cap.\n\n- cityOracle wrote balanceBefore 0 / balanceAfter 15 on every winner's\n  ledger row regardless of what they held, and resolved the oracle in a\n  separate write from the payouts.\n\n- hunterComebackArc made three separate writes; a failure after the arc\n  row was stamped reset the cooldown without paying, and the hunter had\n  to miss another three days for another chance at it.\n\nFound, not fixed: nothing calls creditAndCheckMilestones and nothing else\nwrites lifetimeFgEarned, so that column is zero for every hunter. The\nfour wealth badges never fire, the VIP whale gate in goldVaultVipService\nnever opens, and the lifetime-earned totals in cityCensusService and\ncityAgeService are always zero. Wiring it into the earn path is a\ndecision about where it belongs, so it is documented rather than guessed.\n\ntsc clean, eslint clean, 1204 suites / 10496 tests passing.\n",
      "refs": {
        "commit": "26334dbb4b6487c05bd0b48cfd62aa7be7473e2e"
      },
      "digest": "316997b4cb9e90228bd79eb24ac25e9beceef73065e8ee151b44c0c509f64115"
    },
    {
      "id": "ship/claimyour.gold/618289d303f6",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T16:28:16Z",
      "kind": "infra",
      "title": "Migrate five more silent minting paths onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy writer allowlist 110 -> 105.\n\nMigrated: crewWarChest, crewWarStreak, goldenTicket, ahaMoment,\nhunterPledge. Every one of these credited a wallet with no ledger entry,\nso reconciliation could not tell the gold apart from an error.\n\nDefects found and fixed along the way:\n\n- crewWarChest paid a flat 10 FG per member regardless of what the chest\n  held: a 100 FG chest with 50 members paid out 500. Payouts are now\n  capped at what the chest can cover and the chest is decremented by\n  exactly what was paid, in the same transaction. contributeToWarChest\n  credited the chest with no matching debit, so the chest itself was a\n  mint; it now takes a contributorId and debits that wallet.\n\n- crewWarStreak used wallet.updateMany, which silently skipped members\n  with no wallet row yet — the newest recruits never got paid.\n\n- goldenTicket wrote the ticket row and the gold separately: a failure\n  between them recorded a ticket that paid nothing, and the unique\n  constraint then barred that hunter from the draw for good. Its shuffle\n  was sort(() => 0.5 - Math.random()), not a valid comparator, which\n  biased the draw hard toward the head of the list.\n\n- ahaMoment set its redis dedup flag before writing anything, so a failed\n  payout left the hunter permanently marked as already paid.\n\n- hunterPledge marked a pledge FULFILLED and paid in separate writes; a\n  failure between them meant the status guard skipped it forever after.\n\nAlso fixed a silently-passing test: inflationShieldService stubbed\n$transaction so the callback never ran, and the suite asserted a\ncollected total that no hunter had actually paid. Swept the rest of the\nsuite for the same pattern; this was the last one.\n\ntsc clean, eslint clean, 1204 suites / 10487 tests passing.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "618289d303f68df54cff4c02df2ab766e3245faf"
      },
      "digest": "e6b476cdd6d1fc0f6219253292f8da0e8104b98b32bd772ae620ad1cddc600eb"
    },
    {
      "id": "ship/claimyour.gold/bd5a18ca163c",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T16:07:40Z",
      "kind": "infra",
      "title": "Migrate auction house, emergency fund, burn, ritual and levy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy list 115 to 110. Suites 1201 to 1202, tests 10451 to 10455.\n\nTwo more services credited or debited in a loop with no idempotency, so a\nre-run of the job paid or taxed everyone a second time. Both are now keyed:\nthe emergency fund by event and hunter, the inflation levy by hunter and\nday. The levy also skips a hunter whose balance moved between the scan and\nthe write rather than aborting the run for everybody else, matching the\ncity tithe.\n\ncrewRitualService wrote the completion row and the reward as two\nunsynchronised writes. A failure between them recorded the completion and\npaid nothing, and the unique constraint then blocked the hunter from ever\nretrying. Both now commit together.\n\nAdded a test suite for emergencyFundService, which had none despite\ndistributing the entire city fund. It asserts the two properties worth\nguarding: only the poorer half is paid, and the fund is debited by exactly\nwhat was paid out.\n\nA silently-passing test found and fixed: auctionHouseService's prisma mock\nstubbed $transaction as a bare jest.fn(), so the callback never ran and the\ntest asserted nothing about the work inside it. It now executes the\ntransaction body.\n\nNOTED, NOT CHANGED: auctionHouseService never refunds the bidder it\noutbids, unlike auctionService which does. The two auction implementations\ndisagree; that asymmetry is now visible on the ledger.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "bd5a18ca163c7e26fa8f654aaf08297b4f72bbe6"
      },
      "digest": "f1b820b0b4e0e8910f01371155ec6da4bfa0bab8d97ea439be8ec384b7b25593"
    },
    {
      "id": "ship/claimyour.gold/73d59e544934",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T15:56:47Z",
      "kind": "infra",
      "title": "Migrate four more silent writers onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy list 119 to 115.\n\n  - bountyClaim: the claim payout is now keyed on the bounty.\n  - crewSponsorship: each member's share is keyed on the sponsorship row\n    and the member, so a retried sponsorship pays each of them once.\n  - fgInheritance: the beneficiary payout is recorded.\n  - streakSacrifice: the reward is keyed by hunter and day, matching the\n    30-day cooldown that already limits it.\n\nbountyClaimService set the bounty to CLAIMED and paid the claimer as two\nunsynchronised writes. A failure between them marked the bounty claimed\nand paid nobody. Both now commit together.\n\ncrewSponsorshipService credited every member in a loop with no\nidempotency and no record written first; a retry paid the whole crew\nagain. The sponsorship row is now created first so its id keys each\nmember's credit.\n\nFLAGGED, NOT CHANGED: fgInheritanceService.executeInheritance credits the\nbeneficiary but never debits the owner, so executing an inheritance\ncreates 20% of the owner's balance out of nothing rather than moving it.\nWhether an inheritance should transfer or mint is a product decision.\nThis migration only makes it visible — it will now appear in\nreconciliation as a credit with no matching debit, which is precisely\nwhat it is.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "73d59e54493484920cf202a180c321fadb973365"
      },
      "digest": "5448e1961090aa6bc3ef956ffefce3dafbebe855402ea9a3606d1c6ed8b185d4"
    },
    {
      "id": "ship/claimyour.gold/ad11809dc716",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T15:43:56Z",
      "kind": "infra",
      "title": "Migrate gifts, treasury, black market and crew shares onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy list 123 to 119. Suites 1200 to 1201, tests 10446 to 10451.\n\ngoldGiftService had two separate gift functions, sendGoldGift and\nsendGift, both moving gold between wallets with no entry on either side.\nBoth now use postTransfer, keyed on the gift row.\n\n  - crewTreasury: a donation debits the member into the crew treasury.\n  - blackMarket: claiming a deal debits the cost, keyed by deal and\n    customer, matching the unique constraint that already limits one\n    claim each.\n  - crewExchange: buying shares debits the buyer, keyed on the share\n    transaction row.\n\nsendGift checked the sender's balance outside its transaction, so the\nread could go stale before the debit landed. Both gift paths now check\ninside.\n\nAdded a test suite for crewExchangeService, which had none despite\ncharging real money. It covers the case worth guarding: that the buyer is\ncharged price times quantity rather than the unit price.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "ad11809dc716fa67a2e99299ab4380b74e795d53"
      },
      "digest": "a96d25b858850248c5ab61d337932663bd4ae090ce6eeab8970a5683d94c87eb"
    },
    {
      "id": "ship/claimyour.gold/f8df98f4120e",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T14:03:21Z",
      "kind": "infra",
      "title": "Migrate duel stakes, vault, and two bounty services onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy list 127 to 123. Suites 1198 to 1200, tests 10431 to 10446.\n\n  - duelStake: stake is a debit, the pool payout a credit to the winner.\n  - goldVault: locking debits, unlocking credits principal plus bonus.\n  - hunterBounty and crewRivalBounty: the reward escrows from the poster\n    and is credited to the claimant, or refunded if nobody claims.\n\nBugs fixed:\n\n  - hunterBountyService.placeBounty debited the poster BEFORE creating\n    the bounty and outside any transaction, so a failed create took their\n    stake and left no bounty.\n  - crewRivalBountyService.resolveExpiredBounties paid out and updated\n    status as separate awaits. A failure between them paid a bounty that\n    stayed ACTIVE, and the next sweep paid it again. Both now commit\n    together, and the payout is keyed so a replay cannot double-pay.\n\nAdded tests for fgGiftService and goldVaultService, which had none at all\ndespite both moving money. Writing them caught a real defect in my own\nwork: the vault test asserted the wrong argument order for unlockVault.\n\nTwo pre-existing economic behaviours are now flagged in comments rather\nthan silently changed, because both are product decisions:\n\n  - Changing a war bet charges the new amount again instead of refunding\n    the difference.\n  - A milestone race pays twice the stake but only the challenger stakes,\n    so each resolution mints one stake of new gold.\n\nSwept for the negative-balance wallet upsert found in three services\nearlier: zero remain.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "f8df98f4120e41a28354887b65bd334fcc1b9980"
      },
      "digest": "43ffa81015a7ecb59ddeede98fa72f7d523ccfdd7eb1348b7cfcba7ed69c62f5"
    },
    {
      "id": "ship/claimyour.gold/db7e6d4b9a08",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T05:34:57Z",
      "kind": "infra",
      "title": "Migrate loan, bounty, race and auction onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy list 131 to 127.\n\nAll four escrow or mint against a pool rather than moving gold between\npeople, so they post single entries:\n\n  - fgLoan: issuance credits the borrower from the city fund, repayment\n    debits them back into it.\n  - recruitBounty: the reward is escrowed from the poster on posting and\n    credited to the claimant on completion.\n  - milestoneRace: the challenger's stake is a debit, the prize a credit.\n  - auction: a bid escrows from the bidder and refunds whoever it outbid.\n\nmilestoneRaceService.challengeToRace charged its stake with the same\nunchecked upsert seen in crewHeist and hunterTradingPost, creating a\nchallenger's wallet holding a negative balance. Third instance of an\nidentical copy-paste; worth a sweep once the migration is further along.\n\nEvery payout is now keyed on the row that caused it, so a retried claim,\nresolution or refund pays exactly once. Previously none of them had any\nidempotency.\n\nauctionService keeps the guarantee its conditional updateMany provided:\npostEntry reads and checks the balance inside the same transaction and\nrefuses to go negative, so the overspend race stays closed. The tracked\nnote about needing an optimistic lock on the top bid is preserved, since\nthat redesign is still outstanding.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "db7e6d4b9a08f3c743c684671e3219270a0c4d98"
      },
      "digest": "a27cea947bd9d44c92acab1174e978401d4d09cd413fe6ee81ce61e1db351270"
    },
    {
      "id": "ship/claimyour.gold/096d331ae0b3",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T05:23:19Z",
      "kind": "infra",
      "title": "Migrate four more balance writers onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legacy list 135 to 131.\n\nhunterSponsorship is a true transfer and uses postTransfer. The other\nthree move gold against pools rather than between people, so they post\nsingle entries:\n\n  - warBetSettlement: a stake is a debit to the pool, a payout a credit\n    from it.\n  - cityTax: the weekly tithe debits each hunter into the city fund, and\n    distribution credits it back out.\n  - crewHeist: the launch fee is a debit, member rewards are credits.\n\nBugs fixed by the move:\n\n  - crewHeistService.launchHeist charged the fee with an unchecked upsert\n    that would create a captain's wallet holding a negative balance, the\n    same defect found earlier in hunterTradingPost.\n  - The weekly tithe had no idempotency at all; re-running the job taxed\n    everyone again. It is now keyed by hunter and week.\n  - Heist rewards are keyed per member per heist, so a retried completion\n    cannot pay twice.\n  - The tithe now skips a hunter whose balance moved between the scan and\n    the write instead of failing the whole run.\n\nTests assert the ledger boundary rather than prisma internals, and the\nwar bet suite now resets its mocks between cases — an unconsumed\nmockRejectedValueOnce was leaking into the following test.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "096d331ae0b30bf10663b6890bdeac451f3fb8be"
      },
      "digest": "93844a6d6bcf70b148b9e6f853502d4d557565ddeeb8c84a2824f62e6fb4058c"
    },
    {
      "id": "ship/claimyour.gold/3539df502ce0",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T05:01:48Z",
      "kind": "infra",
      "title": "Migrate four transfer services onto the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds postTransfer(): a movement between two identities is a matched debit\nand credit that commit together, never a pair of balance edits. Most of\nthe unrecorded write paths in this repo have that shape, so this is the\nprimitive the remaining transfer migrations need.\n\nMigrated fgGift, fgTip, tipJar and hunterTradingPost. Legacy list 139 to\n135; the guard now holds all four permanently.\n\nTwo real bugs fixed as a side effect of the move:\n\n  - tipJarService ran two wallet updates outside any transaction. If the\n    second failed the sender lost gold the recipient never received.\n  - hunterTradingPostService.buyListing had no funds check whatsoever and\n    would create a buyer wallet holding a negative balance. The ledger\n    refuses to overdraw, and the sale now commits with the payment or not\n    at all.\n\nBalance checks move inside the transaction in all four, closing the\ncheck-then-write races the previous separate reads allowed.\n\nService tests now mock the ledger boundary rather than prisma internals,\nwhich is what they should have been asserting.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "3539df502ce0c99f5337776304cab9eaf849f949"
      },
      "digest": "a4c2dca026aa34f44dec55ad1daa061e7dc19900b0ff9364ed2721eb88905df4"
    },
    {
      "id": "ship/claimyour.gold/79557a40b164",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T04:23:37Z",
      "kind": "feature",
      "title": "Add postEntry() and a CI guard against direct balance writes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "postEntry() is the one primitive gold moves through. It fixes the three\ndefects reconciliation surfaced in production:\n\n  - One sign convention. amount is signed, always; 185 rows currently\n    disagree with their own balance movement.\n  - No silent wallet writes. Entry and wallet update share a transaction;\n    61 services currently move a wallet with no entry at all.\n  - Exact arithmetic. Balances fold in integer minor units, so 0.1 + 0.2\n    is 0.3 rather than 0.30000000000000004.\n\nEntries are append-only and idempotent per key, and a balance is a fold\nover them — the properties that make a later move to flashy.network a\nchange of storage engine rather than a rewrite.\n\nThe ESLint guard bans direct goldLedger/rewardLedger/wallet writes. The\n139 files that already do this are exempted through\neslint.ledger-legacy.mjs, which is the migration queue: delete a line as\neach file moves onto postEntry() and the guard holds it there. Verified\nboth ways — a new violation errors, a legacy file stays clean.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "79557a40b164f55cb78f3c11a10a61fed7b2364d"
      },
      "digest": "1c8b461e935299d9b186e1729ba173c22159bda63666588937260b8248a8e7a7"
    },
    {
      "id": "ship/claimyour.gold/30bb7e64f826",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T03:59:15Z",
      "kind": "fix",
      "title": "Fix netDrift summing the wrong figure, and emit the full work list",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The first corrected production run reported over-credited 6,732 and\nunder-credited 1,002 — which must net to +5,730 — alongside a net of\n-57,450. The totals contradicted each other because accumulate() still\nadded row.drift (the gold_ledger staleness figure) into netDrift while\nevery other total had moved to combinedDrift.\n\nAdds an invariant test asserting net == over - under and abs == over +\nunder, which is what would have caught this.\n\nAlso adds report.affected: every customer with unrecorded movement, not\njust the top 25. Correction and notification both need the whole set, and\nworstCases is now a slice of it. Sorting moved out of the accumulate loop\nto the end, so it is O(n log n) rather than a re-sort per affected row.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "30bb7e64f82600f7102fcf69067015c5146daaa2"
      },
      "digest": "6e983944c137b9fb53877dc9c0e7e5686ce7c746a179507d6b85e4eb954591ca"
    },
    {
      "id": "ship/claimyour.gold/6c19e638dccb",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T03:33:06Z",
      "kind": "docs",
      "title": "Write the report with --out instead of a shell redirect",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "`npm run reconcile:gold -- --json > drift-baseline.json` produces a file\nthat will not parse: npm prints its own banner to stdout, so the redirect\ncaptures \"> flashy@0.1.1 reconcile:gold\" ahead of the JSON.\n\nAdds --out <path>, which writes the report from inside the script and\nprints the human summary as well. The redirect, and the whole class of\nstdout-pollution problem it invites, is no longer part of the workflow.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "6c19e638dccb76abd487b593f64a2f24f9982627"
      },
      "digest": "6b842f6d89b3677a8bfcf183d41b958a6cfcedf340a481f52bc0d8ffe3887a03"
    },
    {
      "id": "ship/claimyour.gold/edcee485357e",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T02:54:40Z",
      "kind": "other",
      "title": "Measure wallet against both ledgers, not gold_ledger alone",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The first production run reported 82,497 gold of \"drift\", including five\ncustomers apparently short ~14,000 each. That reading was wrong, and the\ntool was asking the wrong question.\n\ngold_ledger.balanceAfter is a snapshot of the wallet at the moment of that\nwrite. When a customer's later activity runs through reward_ledger instead\n— which in production is most activity, 603 of 874 customers have no\ngold_ledger entries at all — the snapshot stays at an old high-water mark\nwhile the wallet moves on. Comparing the two measures how stale\ngold_ledger is, not whether anyone lost gold.\n\nAdds combinedDrift: wallet minus (gold_ledger deltas + reward_ledger sum).\nThat is the question worth asking — did gold move with nothing recording\nit — and status is now derived from it. The gold_ledger-only figure is\nkept as a coverage signal and reported as customersLedgerStale, clearly\nlabelled as not harm.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "edcee485357ed6b913bf1aca2dadda5a2e4fba90"
      },
      "digest": "c26e947c39c88d83cfd60cb52714a02d0edb22a4f60d3e98df2380797ee6d47c"
    },
    {
      "id": "ship/claimyour.gold/c2e66c348e4e",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T02:46:48Z",
      "kind": "other",
      "title": "Separate missing wallet rows from balance drift",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A first run against a live database surfaced a customer with ledger\nentries and no wallet row at all. The reconciler read the absent wallet\nas a zero balance and filed it under \"wallet lower than ledger\", which\nconflates two different problems: gold that is shown incorrectly, and\ngold that has nowhere to be shown.\n\nAdds a MISSING_WALLET status and a hasWallet flag. The drift figure is\nunchanged — those customers are still owed what the ledger says — but the\nremedy differs, so ops can now tell \"create the wallet\" apart from\n\"correct the number\" without reading individual rows.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "c2e66c348e4e831ea6d0811c0b18914959eeb3d2"
      },
      "digest": "ed451152db917d585c1dbb0bcca2d4b4f7211792ac5caf03bbdd2403191cb018"
    },
    {
      "id": "ship/claimyour.gold/ab1e797fe1d5",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-12T01:02:09Z",
      "kind": "feature",
      "title": "Add read-only gold ledger reconciliation",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Step 1 of the ledger consolidation: measure how far the wallet balances\nand the gold ledger have drifted apart, before any writer is migrated.\n\nDeliberately does not sum gold_ledger.amount. That column carries two\ncontradictory sign conventions — factionDefection/hunterDuel/prestigeTitle\nwrite debits negative, while debitWalletWithLedger writes them positive and\ndecrements the wallet — so SUM(amount) is two conventions added together.\nEvery figure is derived from balanceAfter - balanceBefore, which each row\nstates about itself. The amount column is read only to count the\ndisagreements.\n\nReports four signals per customer: wallet vs the ledger's own final\nbalance, continuity of the balanceBefore/balanceAfter chain, sign-convention\nanomalies, and balances with no entries to explain them. Over-credited and\nunder-credited populations are counted separately, since only the second is\nowed anything.\n\nRead-only throughout; safe to run against production.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "ab1e797fe1d561f294b9f33f66acabc58fb23118"
      },
      "digest": "8e442a4cd699b51647f107644a866c6ba96723a57c4d7379d29d586c4f5d0ad4"
    },
    {
      "id": "ship/claimyour.gold/c4eaf369d7c4",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-11T23:32:14Z",
      "kind": "feature",
      "title": "Merge main into claude/audit-real-world-value-pages-xkwcxz",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "c4eaf369d7c4224146c530d060e434815f3352b5"
      },
      "digest": "3415fd47038787597979a1cca5a7f6e3286abc736d1bca3f3a0e98c3695f04ca"
    },
    {
      "id": "ship/claimyour.gold/5c212da2788e",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-11T23:17:14Z",
      "kind": "infra",
      "title": "Update footer test for the new Programs/Directory columns",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The Ecosystem column heading moved to a bottom strip; the test now\nchecks for the new Programs/Directory column headings instead.",
      "refs": {
        "commit": "5c212da2788ed90c1e37d7a459f12d63c94142a0"
      },
      "digest": "a60a81b9776222518c4fdbe17c08bd092af1b7e6df129c241410ba3e8e24928f"
    },
    {
      "id": "ship/claimyour.gold/9f0c619e5242",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-11T23:14:41Z",
      "kind": "feature",
      "title": "Add Academy Programs mega-menu and institutional footer directory",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Navbar: Programs mega-menu (all 5 published pillars + top tracks), a\n\"For\" audience dropdown, and a Resources dropdown, replacing the single\norphaned \"Learn\" link. Also fixes the mobile hamburger menu being\nmissing entirely for unauthenticated public visitors.\n\nFooter: adds a Programs column (mirrors nav) and a Directory column\nlinking the SEO-matrix audience pages and comparison pages that were\npreviously unreachable from any internal link. Ecosystem cross-brand\nlinks move to a dedicated bottom strip; flashy.academy is dropped from\nit since it now has real internal navigation instead of an outbound link.\n\nNew src/lib/academyNav.ts holds the shared static nav/footer data\n(pillars, audiences, resources, ecosystem links).",
      "refs": {
        "commit": "9f0c619e52427bc274b94bc78e7ff96231d0880c"
      },
      "digest": "858f0580ab4dcb14a17c9fb667244de9b63773a7b724dd40efc4352c5ab1978a"
    },
    {
      "id": "ship/claimyour.gold/e017e6948c6f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-11T19:47:04Z",
      "kind": "other",
      "title": "Gitignore the scratchpad working directory",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Session-local working files (e.g. artifact source HTML authored for a\npublished Artifact) don't belong committed to the app repo.",
      "refs": {
        "commit": "e017e6948c6fa22c14f04ce9a5dd9e60e2c7ee22"
      },
      "digest": "5e8a900a3c6cfd5092e16bea37d81bb134cc60be1f4fded6ebd17967a2e66c4e"
    },
    {
      "id": "ship/claimyour.gold/a39cd300ae6e",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-11T16:38:37Z",
      "kind": "feature",
      "title": "Add boardroom brief: leveled, multi-step quest progression system",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Synthesizes an expert panel (game design, backend architecture, growth\neconomy) into a single decisive plan for hunter levels + months-long\nLEGENDARY multi-step quests, built on the QuestStep/QuestStepCompletion/\nminLevel/maxLevel scaffolding that already exists in schema but was never\nwired up. Covers architecture, worked example quest chains, how it\nrespects the 1-10 GOLD per-action ceiling, fixes for the two live quest\nbugs found this session, and a phased rollout plan starting with one\nsmall non-legendary pilot chain before any level model ships.\n\nPlanning document only — no code changes.",
      "refs": {
        "commit": "a39cd300ae6ebf3d50dc6fe3bc5a9dd4bbb0eede"
      },
      "digest": "fe34edde136eb20c10f6447d1733b44b79fc5d465cdeb432c829732fc80b0a69"
    },
    {
      "id": "ship/claimyour.gold/c73314d11a87",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-11T15:46:22Z",
      "kind": "fix",
      "title": "Fix gold leaderboard excluding customers with no HunterProfile row",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "fetchTopGold() and the rank-count query both filtered on\ncustomer: { hunterProfile: { retiredAt: null } }. Prisma's nested to-one\nrelation filter requires the related row to EXIST to match — but\nHunterProfile is only created lazily (first quest completion, profile\nedit, legend-tier checks, etc.), never at signup. Any customer without one\nwas silently excluded from the leaderboard entirely, which is most\ncustomers — the \"Global\" leaderboard was showing almost nobody but\nwhoever happened to already have a profile.\n\nWidened both filters to\n`OR: [{ hunterProfile: null }, { hunterProfile: { retiredAt: null } }]` —\nstill excludes explicitly-retired hunters, but no longer requires a\nprofile to exist in the first place.\n\nAlso:\n- Added invalidateGoldLeaderboardCache() + a script to clear the 5-minute\n  Redis cache immediately after this ships, instead of waiting out the TTL.\n- Added --username support to the earlier daily-challenge diagnostic\n  script, so it can be run with a Telegram handle instead of hunting down\n  a numeric telegramId.",
      "refs": {
        "commit": "c73314d11a87edb5e85079afc55b946019940d18"
      },
      "digest": "9bb8616a28b2a09ea472b630d9d461dbfb3282f208afc7d950b9a0115ebe152f"
    },
    {
      "id": "ship/claimyour.gold/ec55fc94eb87",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-11T15:26:05Z",
      "kind": "feature",
      "title": "Add read-only diagnostic for daily-challenge claimed-but-unpaid records",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Finds DailyChallenge rows with completedAt set but no matching\nRewardLedger DAILY_CHALLENGE entry — the exact stuck state the\ncompleteChallenge() atomicity fix (AlreadyClaimedError, single\ninteractive transaction) prevents going forward, but doesn't retroactively\nrepair. Supports scanning a date window or a single customer by\ntelegramId, to check specific user reports against real data instead of\nguessing whether they're owed gold or already got it.",
      "refs": {
        "commit": "ec55fc94eb8729be02f8400b069140625aeec413"
      },
      "digest": "1446cc8a9ff3290fb148952b8a248ab55540a273577305ed628511a2c5481bb0"
    },
    {
      "id": "ship/claimyour.gold/80a1b29848f3",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-11T13:03:44Z",
      "kind": "feature",
      "title": "Add script to force-clear the stale quest-list Redis cache",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "listQuestsWithStatus() caches active quests for 5 minutes\n(questCrudService.QUEST_CACHE_KEY). The quest reward seed scripts write\ndirectly to the database via Prisma with no knowledge of this cache, so\nrunning a seed to change reward values (e.g. capping rewards to 1-10 FG)\ndoesn't invalidate it — anyone who loaded the quests page shortly before\nthe seed ran keeps seeing stale values for up to 5 minutes after.\n\nAdmin-UI quest edits already call invalidateQuestCache() themselves; this\ngives the same one-off scripts in this repo a way to do it manually after\na raw seed-script run.",
      "refs": {
        "commit": "80a1b29848f36a8596ce17cf276b24787578e86f"
      },
      "digest": "21331e00c1005f18845632847c3e723330ea964ba51ec494d28331abd1dc82a4"
    },
    {
      "id": "ship/claimyour.gold/5b6c38e54114",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-10T21:33:07Z",
      "kind": "other",
      "title": "Recolor favicon lightning bolt to brand green",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Same isolated bolt glyph as before, hue-shifted from gold to the\nbrand green token (--color-green: #6ec880) via HSV hue remap —\npreserves the black outline, white highlight, and 3D shading, only\nthe fill hue changes. Regenerates favicon.png, favicon.svg, and\nfavicon.ico.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01KD4SdUjARsDLcNPfpoDM5Y",
      "refs": {
        "commit": "5b6c38e5411491316d8778f40f7fd3ecac696059"
      },
      "digest": "b543355e4184b95ee0016f2f0e44e8f2b8304590bcc10e1f93ade3fae47b80d6"
    },
    {
      "id": "ship/claimyour.gold/be40ef3e61f9",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-10T21:18:24Z",
      "kind": "infra",
      "title": "Replace favicon with the Flashy lightning bolt from the wordmark",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Extracted the bolt glyph from public/flashy.svg (the \"FLASHY\" wordmark,\nwhere the bolt substitutes for the S), isolated it cleanly from the\nsurrounding letters, and composited it centered on the app's brand\nbackground (#0a0806, matching --background and manifest.webmanifest)\nat generous padding so it stays legible down to 16px and safely inside\nthe maskable-icon safe zone for PWA installs.\n\nRegenerates all three favicon touchpoints referenced by\nsrc/app/layout.tsx and manifest.webmanifest: public/favicon.png\n(512x512, used for both the <link> icon and apple-touch-icon),\npublic/favicon.svg (same image re-embedded), and src/app/favicon.ico\n(proper multi-resolution ICO: 16/32/48/64/128/256, unlike before).\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01KD4SdUjARsDLcNPfpoDM5Y",
      "refs": {
        "commit": "be40ef3e61f94338475af20a011e667422f9da4d"
      },
      "digest": "ef6a88ea155263a4d42bc9f6c8e382c3b82d815a753a675484073ac394cdec88"
    },
    {
      "id": "ship/claimyour.gold/8aa23fa114e9",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-10T19:30:17Z",
      "kind": "feature",
      "title": "Merge claude/atlas-deep-analytics-1zvdpg into main",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Dedupe WAU/MAU implementation: analyticsPageHelpers now delegates to the service-layer usersAnalyticsService instead of maintaining a duplicate copy.",
      "refs": {
        "commit": "8aa23fa114e94fb2c0544d4567f8c870b79bc761"
      },
      "digest": "f5e74966bcac2bc522149b1cb9e0d4c7f1cd10f1ec4172b9a0efc38c06e1de6e"
    },
    {
      "id": "ship/claimyour.gold/a99bd06c18b6",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-10T19:20:41Z",
      "kind": "feature",
      "title": "Merge claude/atlas-deep-analytics-1zvdpg into main",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Fix flat WAU/MAU growth chart and add missing activity-stream categories (gold spent, streak claimed, streak shield used, academy course completed).",
      "refs": {
        "commit": "a99bd06c18b61d0ebedb7243ba6325b6beffcbc2"
      },
      "digest": "f73a0a5e07702dab441067b843aee1e9c878327cfdde2c7cdd188dea05667f4e"
    },
    {
      "id": "ship/claimyour.gold/471228564283",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-10T17:34:52Z",
      "kind": "fix",
      "title": "Fix silent bounty-payout failures and academy streak race conditions",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two correctness bugs from the audit, both real payout/data-loss risks:\n\n1. resolveCrewBounties (src/services/bountyResolutionService.ts) caught\n   per-bounty failures with only a log.warn and moved on — if the payout\n   transaction threw (e.g. transient DB error), the bounty stayed ACTIVE\n   forever with no retry and no alert, silently never paying its winners.\n   Now failures schedule a 'retry-resolve-bounty' job (up to 3 attempts,\n   backing off 5/10/15 min) via a new crewHuntQueue job type, and\n   exhausted retries log at error level with a clear \"MANUAL INTERVENTION\n   REQUIRED\" marker instead of vanishing into a warn log.\n\n2. academyStreakService's recordLearningActivity/addStreakShields did a\n   plain read-then-write against Redis — two concurrent calls for the\n   same user (two tabs, a shield purchase racing a quiz submit) could\n   both read the same \"before\" state and the later write would silently\n   clobber the earlier one. A transient Redis read error during that\n   window also silently reset a real streak to a fabricated empty state.\n   Both functions now run as single atomic Lua scripts (eval), so a\n   concurrent call can't be lost and a Redis error can't corrupt data —\n   the eval either fully applies or nothing is written at all.\n\nAdded test coverage for both: bounty retry scheduling/give-up-after-max,\nand the streak race/failure-doesn't-corrupt-storage behavior.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01KD4SdUjARsDLcNPfpoDM5Y",
      "refs": {
        "commit": "471228564283552017748e03d6c08fe50e5e5f2c"
      },
      "digest": "d1e0f7eac11702f88822f65df44f892b91bf4b591cbbfa62c37c048cd690fe5d"
    },
    {
      "id": "ship/claimyour.gold/6224a298c77f",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-10T16:52:32Z",
      "kind": "other",
      "title": "Cap website quest rewards at 1-10 Flashy Gold; lower daily spin to 0.25-2 FG",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- prisma/seeds/quests.ts: rescaled all 100 quest rewardGold values from a\n  2.5-5000 range down to 1-10, tiered by relative rarity/effort so ordering\n  is preserved (COMMON quests near the bottom, LEGENDARY near the top).\n  Updated the stale header comment describing the old \"airline-tier\"\n  100-10000+ model. rewardGold is already in the seed's upsert `update`\n  block, so re-running the seed patches existing production rows too.\n- src/lib/spinSlots.ts: daily spin range changed from 1-15 FG (15 slots)\n  to 0.25-2 FG (8 slots, 0.25 increments).\n- src/services/dailySpinService.ts: WEIGHTS was still hardcoded to 15\n  entries after the SPIN_SLOTS resize — left alone, rollSpin() could\n  return an index past the new 8-slot array and read undefined, crashing\n  every spin. Trimmed to 8 entries, same \"favor smaller amounts\" shape.\n- Updated dailySpinService.test.ts's range/slotIndex assertions to derive\n  expectations from SPIN_SLOTS instead of the old hardcoded 1-15 range.",
      "refs": {
        "commit": "6224a298c77f054515db0f79eddac06364aff605"
      },
      "digest": "b79a5b1982fc5eb1e916acb5b2fc47348638d5e4a7bd8a48e1836d138645fb73"
    },
    {
      "id": "ship/claimyour.gold/1d68866fd550",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-10T16:09:16Z",
      "kind": "other",
      "title": "Cap per-quiz Academy gold rewards at 1-10 Flashy Gold",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Individual quiz-module rewards (AcademyModule.goldReward, awarded once on\nfirst pass via submitQuizAttempt) ranged from 50-150 FG — rescaled to a\n2/4/6/10 tier by difficulty level so every quiz now pays out within a\n1-10 FG range. Track-level completion bonuses (AcademyTrack.goldReward)\nare unaffected — those are a separate reward for finishing an entire\ntrack, not \"per quiz.\"\n\nEach seed script's upsert already includes goldReward in its `update`\nblock, so re-running these seeds (prisma/seed-academy-tracks.ts and the\nper-track seed files) will correct already-existing module rows in\nproduction, not just apply to future inserts.",
      "refs": {
        "commit": "1d68866fd5500a7ffcbf5f619ffe46c9a7ceafe8"
      },
      "digest": "67b835ac3a1475496b2d49d6815864d6d4c5655cde37d4390412d6785e3039b3"
    },
    {
      "id": "ship/claimyour.gold/90a72c1a8628",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-10T15:55:54Z",
      "kind": "fix",
      "title": "Fix daily-rotating quests permanently locked out after their first-ever completion",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "daily-streak-check-in (isActive, live) and two inactive quests\n(daily-quest-binge, daily-social-share) were seeded with maxCompletions: 1\ndespite being rotationType: 'DAILY' — meant to be completed by every user,\nevery day. maxCompletions is a GLOBAL cap on total completions of that\nslug across all users (claimQuestReward's capacity check has no customerId\nfilter), not a per-user/per-day cap. The first person to ever complete\ndaily-streak-check-in used up the only slot; every other user since —\nand that same user on every later day — has been getting\nQUEST_CAPACITY_REACHED (\"This hunt has reached its limit\").\n\n- Fixed maxCompletions to null (unlimited) for all three quests in the seed.\n- The seed script's upsert never updates maxCompletions on existing rows\n  (only `create` sets it), so re-running the seed alone would not fix the\n  already-broken production quest. Added\n  scripts/fix-daily-quest-max-completions.ts (dry-run by default) to patch\n  the live row directly.",
      "refs": {
        "commit": "90a72c1a8628c6c7e82d413d43f0c1b342d23055"
      },
      "digest": "67224dbf2e0d05c80f1ae438ca4b1c1672db7d264719e77d2569e4dbb62ba5e5"
    },
    {
      "id": "ship/claimyour.gold/02cc45b4a251",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-07T19:23:41Z",
      "kind": "feature",
      "title": "Add jsdom/RTL component-test harness and cover the new academy UI",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "This repo had no component-testing setup (Jest was node-only, no\njsdom/@testing-library). Splits jest.config.ts into a 'node' project\n(existing *.test.ts service/logic tests, unchanged) and a new 'jsdom'\nproject (*.test.tsx) using @testing-library/react + jest-dom +\nuser-event, with a lightweight framer-motion mock (tests/mocks) so\nanimated components render and settle synchronously instead of\ndepending on real transition timing.\n\nAdds full interaction coverage for everything shipped this session:\nInteractiveWalkthrough (answer gating, scoring, step advance, restart,\ncustom diagram slot), both labs end-to-end (RWA wallet transfer, ETF\ncreation/redemption — every question, full walkthrough), and\nAcademyStreakBadge (no session, invalid session, zero streak, best-N\ndisplay, at-risk ring, shield count in title).\n\nIgnores the local coverage/ output directory.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01KD4SdUjARsDLcNPfpoDM5Y",
      "refs": {
        "commit": "02cc45b4a251f835ee1cc66f900c21dbe2acaa36"
      },
      "digest": "a2f3bd00aa1412f4ee40095bc28ad3f5e5f004d4e7087b28dcb7570fe1a21b28"
    },
    {
      "id": "ship/claimyour.gold/105fe593c5ac",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-07T18:48:14Z",
      "kind": "feature",
      "title": "Publish RWA/ETF content, generalize interactive lesson engine, ship streak fixes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Legal/compliance signed off on the RWA and ETF academy content\n(docs/compliance-review-rwa-etf.md updated to reflect it): both tracks\nand their articles flip to isPublished: true, and are linked from the\nDisruptive Technology and Finance pillars respectively.\n\nExtracts the RWA wallet-transfer prototype into a reusable\nInteractiveWalkthrough engine (step state, quiz gating, scoring) and\nadds a second walkthrough on it — ETF creation/redemption arbitrage —\nto prove it generalizes. Both labs now live under a discoverable\n/academy/lab index instead of an unlisted single page, cross-linked\nfrom their companion lesson articles.\n\nShips both round-3 streak recommendations: academyStreakService now\ntracks bestCount (survives resets, backfilled for existing records),\nand AcademyStreakBadge shows \"best N\" once a reset has happened and an\namber at-risk ring once a day has passed without today's activity\nbeing recorded — surfacing the stakes before the reminder jobs would\notherwise be the first signal.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01KD4SdUjARsDLcNPfpoDM5Y",
      "refs": {
        "commit": "105fe593c5ac9c9173fdd94c5f91779c8d0527b4"
      },
      "digest": "2a03a87d4e9e79b03ec8d1a26886bee6310b12ade7b445316391de240064d88c"
    },
    {
      "id": "ship/claimyour.gold/bb4990ba6b06",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-07T18:22:59Z",
      "kind": "feature",
      "title": "Add interactive wallet-transfer lesson prototype for format comparison",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "One interactive module (round-3 boardroom recommendation): a step-through\nwalkthrough of how a tokenized real-world asset moves between two wallets,\nwith inline animated diagram and per-step check-for-understanding. Lives\nat /academy/lab/rwa-wallet-transfer, noindex and unlinked from nav, to\nvalidate the format against article+quiz before building a reusable\ninteractive system. Same compliance posture as the RWA track — no\nspecific token or issuer named.\n\nVerified in a real browser: step advance, answer gating, and the token\nanimation all work end-to-end.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01KD4SdUjARsDLcNPfpoDM5Y",
      "refs": {
        "commit": "bb4990ba6b06ef38a8989d10f0b098296da9cd34"
      },
      "digest": "682ff8fb2601c8b493f94f4b03709908347abf0cf633b847b352ad1b94671efa"
    },
    {
      "id": "ship/claimyour.gold/55d204ac0aa6",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-07T17:50:58Z",
      "kind": "other",
      "title": "Draft RWA and ETF academy tracks; compliance and streak review notes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds two compliance-gated (isPublished: false) content triads following\nthe existing finance-track seed pattern: Real-World Asset Tokenization\nunder Disruptive Technology, and How ETFs Work under Finance. Neither\nis wired into a pillar's linkedTrackSlugs and neither publishes until\nlegal/compliance signs off (docs/compliance-review-rwa-etf.md).\n\nAlso documents the round-3 boardroom finding on streak-break\nconsequences (docs/streak-consequence-review.md): the ambient streak\nbadge is mostly cosmetic today beyond the implicit gold-tier reset.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01KD4SdUjARsDLcNPfpoDM5Y",
      "refs": {
        "commit": "55d204ac0aa6d8e0de0cb88fd770f18f6da5729b"
      },
      "digest": "f4dc1b12dafaadb1db9807519dd4f3e36cb3b69bdf675c073c3c2b098a3860ad"
    },
    {
      "id": "ship/claimyour.gold/4257ca3572e4",
      "repo": "repo/claimyour.gold",
      "at": "2026-08-06T18:51:40Z",
      "kind": "fix",
      "title": "Fix daily-challenge claim being marked done without gold ever awarded",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "completeChallenge() previously set completedAt via a standalone updateMany\ncall, then ran the gold-award transaction (wallet credit, ledger entry,\nstreak update) separately. If that second step failed for any reason (a\ntransient DB error, a timeout), completedAt was already permanently\ncommitted with no gold ever awarded — every future attempt then correctly\nreturned \"already_claimed\" with nothing to show for it.\n\nThe claim guard and every reward write now run inside a single interactive\ntransaction, so either everything commits together or nothing does.",
      "refs": {
        "commit": "4257ca3572e437a0f4e04d875fc70d4df5a6e868"
      },
      "digest": "f3290fe9badaa5e80549fcb322371001a8bb487085a5d3ff07d9a364b48257b1"
    },
    {
      "id": "ship/claimyour.gold/5d41bfd83a73",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T22:59:33Z",
      "kind": "fix",
      "title": "Fix canary-check.sh summing per-bucket latency means instead of averaging",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "fetch_sum() used the same \"sum every point\" logic for both request\ncounts (correct) and mean latency (wrong) — a 300s window returns\nseveral time-series points (~1/minute), so summing their per-bucket\nmeans inflated the reported latency by roughly the bucket count\ninstead of producing an overall mean.\n\nThis just caused a live false-positive rollback: the latest prod\ndeploy (9bd05ed3, the daily-challenge crash fix) reported\nmean_latency_ms=5838 against a 3000ms threshold and was auto-rolled\nback, even though error_requests=0. A synthetic reproduction with the\nreal payload shape confirms the failure mode: the old code summed\n5 per-minute means (~1200ms each) to ~6030ms; the fix weights each\nbucket's mean by its sample count and correctly returns ~1199ms.\n\nEvery canary deploy with a multi-bucket window has likely had this\nsame latency figure inflated, not just tonight's — the gate may have\nbeen silently generating false-positive rollbacks all along.",
      "refs": {
        "commit": "5d41bfd83a7339079de7452b69c4e7b62c1a1a1d"
      },
      "digest": "87ba3a7ee1cca116dfbfceb6492f7d63ab64d2daa42d1e5d514218a7fa821d7a"
    },
    {
      "id": "ship/claimyour.gold/57f57ca3d54d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T22:26:08Z",
      "kind": "fix",
      "title": "Fix root cause of the daily-challenge \"Something went wrong\" crash",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two bugs compounded into a full-page crash:\n\n1. apiError() serialises `error` as an object ({message, httpStatus,\n   code}), not a string. DailyChallengeWidget (and 8 other components)\n   did setError(body.error ?? fallback) and rendered {error} directly —\n   passing that object into JSX throws (\"Objects are not valid as a\n   React child\", React error #31). A completely normal 400 like\n   \"Already claimed today\" (e.g. after claiming via the Telegram bot)\n   crashed the widget instead of showing the message.\n\n2. ErrorBoundary.tsx — which exists specifically to contain exactly\n   that kind of render error — called the server-only `logger` from\n   componentDidCatch. Calling it client-side throws \"serverEnv accessed\n   from the browser\" (production-env.ts's runtime guard), which crashed\n   the boundary itself and escalated the error past its local fallback\n   to the top-level (portal)/error.tsx page. This means every\n   ErrorBoundary-wrapped section in the app has been silently unable to\n   show its local \"Unable to load X\" fallback — any render error inside\n   one has been producing a full white-screen crash instead.\n\nFixes:\n- New src/lib/apiErrorMessage.ts:extractApiErrorMessage() safely reads\n  .message from either an apiError()-object or a plain string. Applied\n  everywhere the same setError(body.error ?? fallback) + {error}\n  pattern existed (DailyChallengeWidget, DailySpinWheel,\n  StreakFreezeCard, WarPredictionPanel, EmpireMap, CrewBountySection,\n  CrewHub, ChallengeFriendButton, NewWorkflowModal).\n- ErrorBoundary now reports via Sentry.captureException (client-safe,\n  no-ops without NEXT_PUBLIC_SENTRY_DSN) instead of the server-only\n  logger.\n\nVerified with a full local `next build` (matching the Dockerfile's\nbuild-time env) — compiles clean end to end.",
      "refs": {
        "commit": "57f57ca3d54de80cefd2dee07dee8c5ac1b8e4cf"
      },
      "digest": "2ff7d5f199de577ab9ea2da919e75c2a2163fe58bf9ce70873f4c7df922899de"
    },
    {
      "id": "ship/claimyour.gold/5e4210a0e5b1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T21:59:35Z",
      "kind": "infra",
      "title": "Prune low-usage nav items to dormant; consolidate duplicate referral entries",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Removes six barely-used Earn-section links (Airdrop, Auction House,\nBlack Market, Trophy Vault, Hall of Fame, Gold Filter) and the Blog\nlink from the account/mobile menu, and consolidates three overlapping\nreferral nav entries (Referral Empire, Recruit Hunters, Referral\nReceipt) down to just Recruit Hunters. Routes and backends are left\nfully intact — this only removes the nav links, per product decision\nto keep the features dormant rather than delete them.\n\nDocumented in docs/masterredesignroadmap.md as Phase 11.",
      "refs": {
        "commit": "5e4210a0e5b1c6b69ae810eddde96be3ee73e668"
      },
      "digest": "843574c60bd4413be8f54c8b77766e2d062a727edd990f65c2751faa6d9534ee"
    },
    {
      "id": "ship/claimyour.gold/66a560c1b5be",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T21:27:38Z",
      "kind": "fix",
      "title": "Fix production build broken since this session's daily-spin fix",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Every deploy since the earlier \"payout-correctness\" commit has been\nfailing at the Docker build step (confirmed via GitHub Actions logs) —\nnone of today's fixes actually reached production despite merging\ncleanly. Root cause: DailySpinWheel.tsx (a client component) imported\nSPIN_SLOTS from dailySpinService.ts, a server-only file. Adding\nupdateWeeklyGold() there pulled in divisionCoreService -> crewHuntQueue\n-> BullMQ -> the Node-only `worker_threads` module into the browser\nbundle, which Next.js can't resolve (\"Module not found: worker_threads\").\n\nMoved SPIN_SLOTS into a new zero-dependency src/lib/spinSlots.ts so the\nclient component no longer touches server-only code at all. Verified\nwith a full local `next build` (matching the Dockerfile's build-time\nenv vars) — compiles clean end to end, including /telegram-app/spin.",
      "refs": {
        "commit": "66a560c1b5beb67571aaaf89f235873c156d8126"
      },
      "digest": "f3b0c84ccd8a922792604f41187104753c54235cf480ce71c4392198243a2da5"
    },
    {
      "id": "ship/claimyour.gold/6c12d57bbc22",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T21:11:54Z",
      "kind": "infra",
      "title": "Bump flashy-app memory to 1Gi and add multi-platform promotion sharing",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "flashy-app was hitting its 512Mi Cloud Run memory ceiling under current\nproduction traffic (logged: \"Memory limit of 512 MiB exceeded with\n564 MiB used\"), causing recurring dropped DB/Redis connections\n(ETIMEDOUT) that surfaced to users as generic \"Something went wrong\"\ncrashes on random pages, including daily challenges. Bumped to 1Gi.\n\nAlso adds explicit Telegram/X/LinkedIn/WhatsApp share links to the\ndivision promotion banner — it previously only offered the native\nWeb Share API (mobile-only) with a silent clipboard-copy fallback on\ndesktop, with no way to pick a specific platform.",
      "refs": {
        "commit": "6c12d57bbc2263bb081a72b774ec39e26826294d"
      },
      "digest": "cead6338049f8e94852385fbbf7c7a1b72700ef7852d3f10fa493fb63cb66e53"
    },
    {
      "id": "ship/claimyour.gold/a9887a3263b3",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T21:04:06Z",
      "kind": "fix",
      "title": "Fix weekly-gold backfill leaving stale nonzero balances untouched",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "computeWeeklyTotals() only returns customers with a qualifying credit\nentry this week, so the write loop never visited anyone whose true\ntotal is 0 (no credits, or only debits/excluded entry types) — their\nexisting weeklyGold, however stale or wrong, was left untouched. This\nis why re-running the corrected backfill didn't clear the corrupted\nADMIN_DEBIT-derived values for the affected users: they had zero\nqualifying credits this week, so the loop skipped them entirely.\n\nNow explicitly resets weeklyGold=0 for any DivisionMembership row this\nweek that isn't in the freshly computed totals.",
      "refs": {
        "commit": "a9887a3263b3af6206e999657e044bf01983bb91"
      },
      "digest": "802537dcdc964ed30602d4e3a2c7fea2d3f431bb5fa20c717d48b128ed72a439"
    },
    {
      "id": "ship/claimyour.gold/449b6620245e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T17:12:13Z",
      "kind": "fix",
      "title": "Fix llms.txt to conform to the llmstxt.org spec",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Bullets under H2 sections must be markdown links with absolute URLs\n(- [Title](https://...): description) — ours were plain relative paths\nwith no link syntax, which fails spec-conformant parsers. Also dropped\nthe \"Authenticated Areas\" exclusion list, which has no recognized\nmeaning in llms.txt (that's robots.txt's job, and robots.txt already\ncovers it) and moved prose into the free-text section.",
      "refs": {
        "commit": "449b6620245e0acc74bb33d64b8c35923eb53d09"
      },
      "digest": "3d495dd0f070f551f93ea4c453a6f21d40d6ffc3b8c360040b57f923a5f9801b"
    },
    {
      "id": "ship/claimyour.gold/382d697e9d61",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T17:05:46Z",
      "kind": "fix",
      "title": "Fix gift-claim 404 on View Wallet and missing weekly-gold credit",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The Telegram gift-claim confirmation linked to /telegram-app/wallet,\nwhich doesn't exist (404) — the mini-app's balance view lives at\n/dashboard. Fixed the button and the shared MINI_APP_ROUTES.wallet\nmapping it's built from.\n\nclaimGift() also never called updateWeeklyGold(), so gift-card gold\ncredited the wallet but silently didn't count toward the weekly/\ndivision leaderboard — same gap already fixed this session for daily\nspin. Now wired in.",
      "refs": {
        "commit": "382d697e9d614f8558206d7868f221628b4d6f31"
      },
      "digest": "1e4fdd423515531a3cba2131bbc4b99a7928907a51596d9a71c3dd39144de84e"
    },
    {
      "id": "ship/claimyour.gold/9eb90db6bfdf",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T15:13:58Z",
      "kind": "feature",
      "title": "Let gift cards be created for any amount, not just a fixed 50 FG",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds an amount input to the gift-card portal page and threads a\nvalidated amount (1-5000 FG) through sendGift() and the create route,\ninstead of the previous hardcoded GIFT_AMOUNT = 50.",
      "refs": {
        "commit": "9eb90db6bfdf844feae53a64fdfed407180a443a"
      },
      "digest": "25f92eb12a853d59d4bce3430ab86527f4622f5d4ec25fb85e1721ebc678f70e"
    },
    {
      "id": "ship/claimyour.gold/0950d22f9076",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-31T15:08:30Z",
      "kind": "fix",
      "title": "Fix payout-correctness gaps in bombs, gifts, daily spin, and quest gating",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Settle pending gold-bomb claims for new customers created via One-Tap\n  Telegram Login, not just the email-verification signup path — bomb\n  payouts were silently never issued for that path.\n- Make gift-card claiming atomic (Redis SET NX lock) so a double-click or\n  duplicate Telegram webhook retry can no longer double-credit gold.\n- Daily spin now writes a RewardLedger row and updates weekly leaderboard\n  gold like every other reward path, instead of only crediting the wallet.\n- TELEGRAM_JOIN quest verification now fails closed instead of silently\n  granting the claim when Telegram config is missing or the API errors.",
      "refs": {
        "commit": "0950d22f90762f63f086e69a12b32c1a8f028eb2"
      },
      "digest": "bbc8cc67bf7f4f6497ab496374bdfa3aac6e90ddba73b779de16293d1d94995d"
    },
    {
      "id": "ship/claimyour.gold/59bb664a9c7a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-30T21:16:12Z",
      "kind": "fix",
      "title": "Fix new-customer creation crashing on customers_username_key collision",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Customer.username and Customer.handle are String? @unique on a non-sparse\nMongoDB index. No live signup code path set either field, so every\nprisma.customer.create() omitted them — and since the index isn't\nsparse, every customer missing the field collides on the same indexed\n\"missing field\" slot after the first one claims it.\n\nA one-time historical backfill gave all pre-existing customers unique\nhunter-<id>/handle-<id> placeholders, but was never wired into the live\nsignup flow. The single customer created after that backfill\n(2026-07-29T23:20:25 UTC) claimed the one remaining free slot — every\nsignup since has failed at customer creation with \"Unique constraint\nfailed on the constraint: customers_username_key\", surfacing to users as\na generic verification-error page with no visible cause.\n\nFixed all six customer-creation call sites (customerService.ts x2,\ntelegramAuthService.ts, customerImportService.ts, emailSignupService.ts,\ndevBypassAuthService.ts, pointsSyncService.ts) to always set\nusername/handle to a telegramId-derived placeholder, which is guaranteed\nunique since telegramId itself is a unique column.\n\nAlso adds two read-only diagnostic scripts used to trace the crash\n(diagnose-recent-customer.ts, diagnose-username-index.ts).",
      "refs": {
        "commit": "59bb664a9c7a39bf475702ac5c52e09f63a148a6"
      },
      "digest": "b95e925a0122360f1f550c45c4feb5abe6f2ee29d7b3ee251c74d59aa6e82aa5"
    },
    {
      "id": "ship/claimyour.gold/de47df8d7104",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-30T19:18:41Z",
      "kind": "infra",
      "title": "Raise wallet debit transaction timeout; add email-verification diagnostics",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- debitWalletWithLedger's interactive transaction now uses a 20s timeout\n  instead of Prisma's 5s default, which was too tight for the wallet\n  read + update + ledger create path under load. Codifies a fix already\n  hand-applied in production so it survives a fresh checkout.\n- Added two read-only diagnostic scripts (diagnose-email-verification.ts,\n  diagnose-verification-volume.ts) for tracing individual verification\n  token issues and overall token volume.",
      "refs": {
        "commit": "de47df8d710485cd824196b5f121329c0636ce7c"
      },
      "digest": "4864df3c9074ed18947cb2e5aea22e190daa41cf9c59b798e3a696769588d417"
    },
    {
      "id": "ship/claimyour.gold/2b0f163d9160",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-30T18:18:03Z",
      "kind": "infra",
      "title": "Wire gift-card deep links to actually claim the gift",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Telegram /start gift_<code>: prompts sign-up if the sender isn't a\n  customer yet, otherwise calls claimGift directly and confirms with the\n  amount and sender's username.\n- Portal fallback /portal?gift=<code>: redirects to\n  /portal/gift-card?code=<code>&autoClaim=1, which the gift-card client\n  now auto-submits via handleClaim on mount instead of requiring the user\n  to retype the code.\n\nBoth entry points previously landed the user on a page/prompt without\nactually claiming anything.",
      "refs": {
        "commit": "2b0f163d916052ab8e80aae54b880c8c0f26f4aa"
      },
      "digest": "2c83aa5d3fed7e2f86aa1294eca264f148939c9698afc24e37488fe29a1ca021"
    },
    {
      "id": "ship/claimyour.gold/cbf0e7a79cc6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-30T16:15:42Z",
      "kind": "feature",
      "title": "Add cloudbuild.yaml as a fallback build path",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Builds and pushes the app image entirely inside GCP via Cloud Build, for\nwhen a local Docker push from Cloud Shell (or any machine) can't reach\nArtifact Registry reliably. Same Dockerfile and build-args as\nscripts/build-and-push.sh, no local Docker daemon/network involved.",
      "refs": {
        "commit": "cbf0e7a79cc627fb8a9209b137da76ac5196621e"
      },
      "digest": "5b5ac3a93df2412aaf6273e6a29ae391efb2fdb3bc2fa8c26ea3da073a2ef6e0"
    },
    {
      "id": "ship/claimyour.gold/57a5890220ba",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-30T15:21:37Z",
      "kind": "fix",
      "title": "Fix GoldLedger debit/credit miscount in weekly backfill; add ops tooling for Redis-independent script execution",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- backfill-weekly-gold.ts was summing GoldLedger amount > 0 as \"credits\",\n  but GoldLedger stores every entry as a positive magnitude regardless of\n  direction — only entryType distinguishes credits from debits. Now\n  filters by an explicit list of credit entryTypes instead.\n- Added diagnose-weekly-gold-cluster.ts (read-only) and\n  flush-campaign-deliveries.ts (bypasses BullMQ/Redis to directly dispatch\n  stuck PENDING campaign deliveries via the Telegram Bot API).\n- Added a flashy-admin-scripts Cloud Run Job (Terraform module + envs)\n  giving one-off admin scripts the same VPC path to Memorystore/Atlas as\n  the deployed app, instead of running from an operator's Cloud\n  Shell/laptop with no route to either.\n- Dockerfile now includes scripts/ in the runtime image so the job can run\n  them via `npx tsx`.",
      "refs": {
        "commit": "57a5890220ba403fefb3eb3e2f0e034749cc0cb1"
      },
      "digest": "97229de395ab191c6920d0e55576a6c506a3b62861969c96277f8a8362d229a2"
    },
    {
      "id": "ship/claimyour.gold/d08b15044564",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-30T14:13:16Z",
      "kind": "feature",
      "title": "Add leaderboard apology broadcast script",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "One-off ops script to notify hunters, via Telegram DM and an in-app\nnotification, that this week's weekly/division leaderboard undercounted\ngold and has been corrected. Reuses the existing delivery-tracked\nbroadcast infrastructure (Segment + UserCampaign + UserCampaignDelivery +\ncampaignQueue).",
      "refs": {
        "commit": "d08b15044564b1a8940c3cfe54ede64cd611ed68"
      },
      "digest": "86aa657e1d23d17feafb5830e8189fc156bdf0d871360949dd0b2968f153f66b"
    },
    {
      "id": "ship/claimyour.gold/266d83d5eabb",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-29T18:05:44Z",
      "kind": "fix",
      "title": "Fix daily-challenge claims blocked by rate limiter fail-closed on Redis errors",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Root cause of zero daily-challenge completions since 2026-07-24: the\nshared apiRateLimit (fail-closed by design, used by 78 routes including\nmoney-touching ones) was also gating the daily-challenge claim route, and\nRedis has been intermittently unreachable since that date. Every claim\nattempt during a Redis blip got denied outright.\n\n- rateLimit.ts's check() helper was swallowing every Redis error and\n  always returning success:false, which meant the fail-open catch blocks\n  already written for pollTokenRateLimit/oauthInitRateLimit/\n  referralAssociateRateLimit/publicBountyContextRateLimit could never\n  actually fire. check() now rethrows genuine infra errors so each\n  limiter's own documented policy applies.\n- Added a dedicated dailyChallengeRateLimit (fails open — a Redis blip\n  shouldn't block a once-a-day, low-value claim) and switched the\n  daily-challenge route to it instead of the shared apiRateLimit, which\n  stays fail-closed for the other 77 routes it guards.\n\nRedis itself is still unstable and needs infra attention independent of\nthis fix — this makes the low-stakes claim path resilient to it, not a\nfix for Redis.",
      "refs": {
        "commit": "266d83d5eabb22d6a968526318a6b32dbae3527d"
      },
      "digest": "1260669a3b5c115bc25cd04e934985913586e3cebf1ac6923a43c5c5d784e978"
    },
    {
      "id": "ship/claimyour.gold/e33375b15fce",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-29T17:22:08Z",
      "kind": "other",
      "title": "Halve all quest completion rewards",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Flat 50% cut across every quest's rewardGold, applied to future\ncompletions only — no retroactive adjustment to gold already paid on\nexisting completions.",
      "refs": {
        "commit": "e33375b15fce190a87985a5d85c1291bdde41c66"
      },
      "digest": "753f5c47e9626c78d1bd81de905b9ef938a4457ff3e3305b2f6cb6e41f2a463c"
    },
    {
      "id": "ship/claimyour.gold/009d001b909e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-29T17:01:44Z",
      "kind": "feature",
      "title": "Add real verification for WAR_WIN, CLAIM_COUNT, LEADERBOARD_RANK, and crew-role quests",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Following up on the quest-exploit incident: builds real eligibility checks\nfor the three quest types that were previously fail-closed with no\nimplemented check, plus reclassifies crew-captain/council-seat-holder from\nMANUAL to CREW_JOIN with a metadata.role discriminator so they get a real\ncheck too instead of remaining permanently disabled.\n\n- WAR_WIN: counts resolved CrewWar wins for the customer's current crew\n- CLAIM_COUNT: uses HunterProfile.totalQuestsCompleted\n- LEADERBOARD_RANK: computed live from HunterProfile.totalGoldClaimed rank\n- CREW_JOIN role:captain / role:council: Crew.captainId / CouncilMember\n\nRe-enables 16 previously isActive:false quests now that each has a real,\nnon-bypassable gate. All other still-unverified types (CRAFT_ITEM,\nBUILD_STRUCTURE, RAID_SUCCESS, DEFEND_SUCCESS, ALLIANCE_FORMED,\nSOCIAL_PROOF, PARTY_SIZE_N, SEASON_RANK) remain fail-closed and disabled.",
      "refs": {
        "commit": "009d001b909eccb573e3652497e2cb234310ed70"
      },
      "digest": "834eeb829c255ea63bb7a49d972ab341ac62a439837849be87900a25b524bcb9"
    },
    {
      "id": "ship/claimyour.gold/f3f70d1ca554",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-29T13:49:55Z",
      "kind": "infra",
      "title": "Wire main gold-earning paths into weekly division leaderboard",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "updateWeeklyGold() was only ever called from the daily challenge\ncompletion path, so quest claims, referral rewards (referrer/referred/\nmilestone/rush-invite bonuses), streak claims, and gold bomb claims\nnever updated DivisionMembership.weeklyGold — leaving the weekly/\ndivision leaderboard empty for most real gold earned. Wire those paths\nin, and add a dry-run-by-default backfill script to recompute this\nweek's totals from RewardLedger/GoldLedger for hunters who earned gold\nbefore the fix landed.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01Mv4TKyDp7eyX74EAv36iRM",
      "refs": {
        "commit": "f3f70d1ca554c05c0e61c265b55dcbac7fbe9ffd"
      },
      "digest": "195f1cf46fb42a6e4354e06db4c77cb04f9b16ed0296f8d291a8c4f39b3a90c6"
    },
    {
      "id": "ship/claimyour.gold/e81a9507c1ec",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-27T22:08:29Z",
      "kind": "infra",
      "title": "Bump version to force a fresh Cloud Run revision",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The previous deploy attempts reused the same commit SHA, so Cloud Run\ndeduped the image and never actually created a new revision to canary-test.",
      "refs": {
        "commit": "e81a9507c1ec1ca904ea5fbbdfa4ca549cd30fac"
      },
      "digest": "866ca101175a85425f2d4a6dda998316d84b51cf25f2626d5cbb7e2bc5c1f2b1"
    },
    {
      "id": "ship/claimyour.gold/21532185d3c4",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-27T15:09:36Z",
      "kind": "fix",
      "title": "Fix announcements quest Telegram link, upgrade churn-risk email design",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- join-flashy-announcements quest now points at the real @FlashyOfficialHQ\n  channel (same fix already applied to the other two Telegram-join quests)\n- Redesign the medium-risk churn email with a proper branded table layout,\n  urgency-driven headline/subject, and a stronger CTA",
      "refs": {
        "commit": "21532185d3c4d6b2f27596c1f79858c9cf0302ec"
      },
      "digest": "1f13509ec1a8ed6dc6eacbe4d323d1922332acb835c908b9600338d5dd290db6"
    },
    {
      "id": "ship/claimyour.gold/4f196b4eeba6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-25T18:03:49Z",
      "kind": "fix",
      "title": "Fix quest claim errors always showing generic \"Claim failed (400)\"",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "apiError() nests the error message/code under `error`, not top-level, but\nthe portal quests page read `json.message` at the top level (always\nundefined), so every claim failure surfaced as the generic \"Claim failed\n(400)\" regardless of the actual reason (not a member, misconfigured quest,\netc). The mini-app quests page already read `error.message` correctly —\nthis brings the portal page in line with it.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01Mv4TKyDp7eyX74EAv36iRM",
      "refs": {
        "commit": "4f196b4eeba623e59992a87e31f3235da2f60be2"
      },
      "digest": "695be37bcd82406c5444bae9ce7f5c705a8675b1bc4f13248844d0a1e8aee963"
    },
    {
      "id": "ship/claimyour.gold/d2ee93dd6446",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-25T17:58:11Z",
      "kind": "fix",
      "title": "Fix Daily Spin NaN countdown, missing wheel-result fields, route drift",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "getDailySpinStatus() only returned nextSpinAt when canSpin was false, so\na first-time visitor's initial status had no date at all — new Date(undefined)\nproduced an Invalid Date, and the post-spin countdown (computed from that\nsame stale prop) rendered \"Next spin in ~NaNh\". nextSpinAt is now always\ncomputed and returned, and the wheel keeps its own state updated from the\nPOST response instead of trusting the pre-spin prop.\n\nexecuteDailySpin() only ever returned {amount}, while DailySpinWheel.tsx\nexpected {slotIndex, amount, emoji, label, newBalance} to drive its landing\nanimation and result screen — slotIndex being undefined broke the wheel's\ntarget-angle math. The service now returns the full shape.\n\nAlso closed the actual double-spin race: the old code did a findUnique\ncheck then a separate create, leaving a window for two concurrent requests\nto both pass the check. It now attempts the create directly and translates\nthe resulting P2002 unique-constraint violation into a clean\nALREADY_SPUN_TODAY, both in executeDailySpin and its claimDailySpin alias.\n\nFinally, consolidated the two divergent route trees — the portal and\nmini-app spin pages both called the legacy /api/portal/daily-spin (raw\nJSON) for status while the wheel POSTed to /api/v1/portal/daily-spin\n(enveloped) to claim, which is exactly the kind of drift that produced\nthese bugs. Both pages now use the v1 route for both, and the now-fully-\nunused legacy route is deleted.",
      "refs": {
        "commit": "d2ee93dd644673f40b1194f8373beaaa2a50276c"
      },
      "digest": "08521cf21329f419ec3b1459b8e84a432c6c7719619c7f3f95efea61a9a3ba9a"
    },
    {
      "id": "ship/claimyour.gold/566ea90568ce",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-25T16:33:37Z",
      "kind": "other",
      "title": "Isolate Daily Challenge widget behind an error boundary",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "User reported the whole portal crashing to the generic error page while\nclaiming a daily challenge. Couldn't pin down a single guaranteed root\ncause after tracing every field the claim-success render path touches\n(all already had safe fallbacks) — so this makes the failure mode safe\nregardless: DailyChallengeWidget and ChallengeHistoryCalendar are now\nwrapped in ErrorBoundary, so a render error there shows a small inline\n\"try again\" card instead of taking down the entire challenges page.\nAlso hardened CelebrationOverlay's badgesEarned access with an\nArray.isArray guard as defense-in-depth.",
      "refs": {
        "commit": "566ea90568ce115393fc2e325f488354d507ba41"
      },
      "digest": "f9c8745a5c281155c2197bbee9b2124998ece03fcc0dd6eec6bceaca9d0aeaa5"
    },
    {
      "id": "ship/claimyour.gold/e1863174154e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-25T15:25:04Z",
      "kind": "infra",
      "title": "Point the news and community quests at @FlashyOfficialHQ",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Both quests' Telegram channel handle didn't match the actual live\nchannel. The announcement quest also gets an explicit inviteUrl\npointing at the pinned announcement post (message 20) instead of the\nbare channel link.\n\nEditing this file doesn't change production data by itself — the\nseed-quests.yml GitHub Actions workflow (manual, upsert-by-slug, safe\nto re-run) needs to run to apply it.",
      "refs": {
        "commit": "e1863174154eec043ccbc75fac55e1d94bdd1aae"
      },
      "digest": "8ff985aee0a23a3d4537e8c34f5c3cfb916c93f1b8bf43d89b5d648f96924fed"
    },
    {
      "id": "ship/claimyour.gold/f8fee66f6bf9",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-25T15:06:17Z",
      "kind": "fix",
      "title": "Fix Telegram-join quests missing their join link; quest board improvements",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Join Channel button never rendered for TELEGRAM_JOIN quests because the\nfrontend only read metadata.inviteUrl, while seed data (and the backend\nverifier) store the channel under metadata.telegramChannel — so users\nhad no way to actually join before hitting Claim, and always got\nNOT_A_MEMBER. safeInviteUrl() now derives a t.me link from\ntelegramChannel when inviteUrl is absent, in both the portal and\nmini-app quest pages. Also logs Telegram's rejection reason when\ngetChatMember returns ok:false, so a misconfigured/non-admin bot is\ndistinguishable from a real non-member going forward.\n\nQuest board: unlocked (claimable) quests now sort above locked ones in\nboth the portal and mini-app quest lists, with a \"Locked — keep playing\nto unlock\" section below; added category filter chips (Community,\nExplore, Referrals, Streak, Crew, Partner). Unlock requirements were\nalready shown per-card — this just makes them easier to find.\n\nAlso adds scripts/clawback-ungated-quest-gold.ts (dry-run by default,\nnot yet executed) for the 2026-07-24 quest-exploit gold recovery.",
      "refs": {
        "commit": "f8fee66f6bf9d1421c33d71b5d662180b64c6273"
      },
      "digest": "4f239ff2eb967994241cf3bfac7b105d3967d8e53101fe901097a43eb2c9cff7"
    },
    {
      "id": "ship/claimyour.gold/3824bb5a83ea",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-25T14:45:00Z",
      "kind": "feature",
      "title": "Add boardroom brief: quest exploit gold recovery and notification plan",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "3824bb5a83eadf87f26dafacc9b5d499c74ba176"
      },
      "digest": "98cc05df6a6099a4b69b1d7a1c119072015b92f4df45cf2ab29b780692a6d66d"
    },
    {
      "id": "ship/claimyour.gold/e16e6da598e6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-25T14:36:43Z",
      "kind": "feature",
      "title": "Add incident doc: quest exploit gate audit + clawback query",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "e16e6da598e6d0b89bb9bd675fc60c6685d3ecaf"
      },
      "digest": "97e64d60e893c8176bd606d410348bc746e8ae57335786a5db1330006baba42a"
    },
    {
      "id": "ship/claimyour.gold/428035fef5e9",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-24T13:21:01Z",
      "kind": "infra",
      "title": "retry prod deploy — prior canary rollback was a latency-threshold cold-start false positive, not a code regression (zero errors, all smoke t",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "428035fef5e961e46fc0af9db64b72d838d91cd8"
      },
      "digest": "9744dfe9247a9e0dd4939331f40f06f140df7a8f7fd03543f18768cf995ddb0d"
    },
    {
      "id": "ship/claimyour.gold/a22803fc817a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-24T11:21:41Z",
      "kind": "fix",
      "title": "Fix package-lock.json drift blocking npm ci in the deploy pipeline",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "package-lock.json was missing next-intl's @swc/helpers@0.5.23 entry,\nso `npm ci` failed with EUSAGE in the Deploy prod workflow — this is\nwhat silently blocked today's Deploy prod run (and is why production\nhas been running last week's build this whole time, missing the quest\neligibility and Daily Challenges fixes). Cherry-picked the one-line\nlockfile fix already present on claude/discussion-topic-3ij0ol.",
      "refs": {
        "commit": "a22803fc817ad512a1a2b1a739d5ec1517e7994a"
      },
      "digest": "7c58d93e2a09f7ee0e748b4bef4b56458e97a27e3762830af74ea4cad78a80e6"
    },
    {
      "id": "ship/claimyour.gold/12313536a98a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-22T19:48:00Z",
      "kind": "feature",
      "title": "Close quest eligibility gap: fail closed for unverified quest types",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "verifyQuestEligibility() only had a real check for 6 of 20 QuestType\nvalues; the other 14 (MANUAL, CRAFT_ITEM, RAID_SUCCESS, WAR_WIN,\nCLAIM_COUNT, LEADERBOARD_RANK, CREW_JOIN, etc.) fell through to an\nunconditional pass, so any active quest of those types could be claimed\nvia the API with zero proof of completion.\n\nAdds a real CREW_JOIN check (crewMember.findUnique) since it was the\none exploitable type actually seeded isActive:true, and flips the\ndefault case from silently granting the reward to throwing\nQUEST_MISCONFIGURED — every other ungated type must now either get a\nreal check or stay isActive:false, matching how the quest catalog is\nalready supposed to be curated. computeQuestEligibility's preview gets\nthe matching fail-closed default so quest cards show locked instead of\nclaim-then-fail.",
      "refs": {
        "commit": "12313536a98a9f5407d08e5edcf88dba8a9bdb8c"
      },
      "digest": "9c2f22b82246eedb513c6e5e7d2dee07f38e2e53236ecd3ec24bc211d6b92f9f"
    },
    {
      "id": "ship/claimyour.gold/19faa9b4bc8f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-22T13:18:31Z",
      "kind": "fix",
      "title": "Fix Daily Challenges double-credit race with an atomic claim guard",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "completedAt was checked before the reward-granting transaction but the\nactual write had no conditional guard, so two near-simultaneous claim\nrequests could both pass the check and both grant gold + streak credit.\nAdds an atomic updateMany(where: { completedAt: null }) claim guard\nbefore the transaction, mirroring the pattern already proven in Gold\nBomb's own claim path — a count of 0 means another request already won\nthe race, so this one returns already_claimed instead of double-paying.",
      "refs": {
        "commit": "19faa9b4bc8f071f084ac37825f85cdfef1afd5f"
      },
      "digest": "8d2ef0dd707469ce4c51f47d5851ac55a271ae176e9aa3662c468c64c5f76d25"
    },
    {
      "id": "ship/claimyour.gold/e7bcd84b0ce3",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-22T13:00:16Z",
      "kind": "feature",
      "title": "Add earn-systems audit follow-up (2026-07-22)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Re-verifies every gating path across Quests, Daily Challenges, Daily\nSpin, Gold Bomb, Duels, and Raids/Bounty against current code. Confirms\nthe previously-flagged Daily Challenges double-credit race and Daily\nSpin bugs were never actually fixed, and finds a new major gap: quest\neligibility verification only covers 6 of 20 QuestType values, plus new\nconcurrency races in duel bet settlement and bounty claiming.",
      "refs": {
        "commit": "e7bcd84b0ce3b1f482784a95aa8881a81e18778d"
      },
      "digest": "065fc92fed28f9debea5257ca4f2da1d1291d70289fe5836af238bfeda934120"
    },
    {
      "id": "ship/claimyour.gold/b0e1fa2734be",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-21T23:52:09Z",
      "kind": "other",
      "title": "Track daily challenges, rivalries, and bounties in the activity stream",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The unified activity stream only tracked 15 event types and was missing\ndaily challenges, rival resolutions, and bounty settlements entirely.\nAdds fetchDailyChallengeEvents (DailyChallenge.completedAt), fetchRivalEvents\n(HunterRival, status RESOLVED), and fetchBountyEvents (BountyBoard, CLAIMED\nor REFUNDED) following the existing per-category fetcher pattern, and wires\ntheir labels/colors into the super-admin activity-stream page.",
      "refs": {
        "commit": "b0e1fa2734be1aabb54bf4b0c8c73e9a80ecb846"
      },
      "digest": "62a799fb02ff7da697d72912056cc6358856a02a6a6ab7da12cb0ba103d6f028"
    },
    {
      "id": "ship/claimyour.gold/9edc493a1f48",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-21T22:09:08Z",
      "kind": "infra",
      "title": "CI trigger verification (Actions was re-enabled) — no code changes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "9edc493a1f48a701a01e3b67f8655e3ccc94ab7c"
      },
      "digest": "3aa42cc8f0f5eae4b5f84fcbf8481f147ab8e294be81a3194e169b1632f1792f"
    },
    {
      "id": "ship/claimyour.gold/2903c84141ac",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-21T20:42:00Z",
      "kind": "feature",
      "title": "Add Earn systems audit: Gold Bomb, Quests, Daily Challenges, Daily Spin, Raids/Bounty",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "2903c84141ac14b552b32b8919811447e34a2fab"
      },
      "digest": "0e511905460cb2825c0a3c861cbc45c29919c23e3bb39736e14fe4d9360568f7"
    },
    {
      "id": "ship/claimyour.gold/28188ee1c83d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-21T20:12:43Z",
      "kind": "fix",
      "title": "Fix settlePendingBombClaim: null-bomb guard, single referral/activation per user",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Ported by hand from origin/claude/funny-noether-75ghqx (the raw branch\nalso rewrites the bomb pages we already hand-fixed this session, so it\nisn't merged directly — just this isolated backend fix).\n\nFour real bugs in settlePendingBombClaim (moved to\ngoldBombActivationService.ts in an earlier refactor, same bugs\ncarried over): accessed pending.bomb.hunterId with no guard against a\nnull/orphaned bomb relation; referral association, bomb-origin\ntracking, and the activation-bonus job were all fired once per pending\nclaim instead of once per new customer, so a user with multiple\npending bomb claims from onboarding could get duplicate referral\ncredit and duplicate activation-bonus jobs enqueued.",
      "refs": {
        "commit": "28188ee1c83d0781ddf18a83e49c603681750b4c"
      },
      "digest": "76742e1f081816c7b5dfdc4ab96654ce1a4b3ae00ba638f448902b6699e30b4a"
    },
    {
      "id": "ship/claimyour.gold/9f4297811082",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-21T15:50:37Z",
      "kind": "other",
      "title": "Enforce real quest eligibility checks before payout, closing the partner-api exploit",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Quest tiering (Common -> Legendary) was purely decorative: claimQuestReward()\nonly checked isActive/expiry/capacity/dedup, never the quest's actual\ntype-specific requirement (streak length, gold earned, referral count,\nPoints balance, Telegram membership, hunter level). Any user could claim\nany Legendary quest instantly via the normal claim API with zero real\nprogress. Worse, the partner-api completion route had no verification\nlayer at all — any partner could mint any reward, including Legendary\nbadge items, for any customer they named.\n\nAdds verifyQuestEligibility() (src/lib/questVerification.ts) — a single,\ntype-based gate dispatching on Quest.type + metadata.targetCount, called\nfrom claimQuestReward() itself so every caller (portal, mini-app,\npartner-api) is covered by one fix instead of three. Also fixes the\nTELEGRAM_JOIN membership check reading metadata.chatId when seed data\nactually stores metadata.telegramChannel, and removes the dead\nslug-keyed verifier map whose three registered slugs matched none of\nthe 68 real quest slugs (the portal route's \"verification\" step was a\nsilent no-op for the entire catalog).\n\ntests/api/partner-quest-gating-integration.test.ts is a regression test\nthat exercises the real (unmocked) claimQuestReward + verifyQuestEligibility\nchain through the partner-api route and proves a LEGENDARY quest can no\nlonger be claimed by a customer who doesn't meet its requirement.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01K7gaDqS6RwwtjF2ieTPK5t",
      "refs": {
        "commit": "9f4297811082d137aae993c74416db9f518dd1a3"
      },
      "digest": "958ac07960ccc7b8285d2ccf9b92778dc2489797b327a249798f325e009ae8aa"
    },
    {
      "id": "ship/claimyour.gold/e473785c8a81",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-21T15:32:34Z",
      "kind": "fix",
      "title": "Fix Gold Bomb sharing and registration bugs",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Public bomb-explosion page: remove \"Drop your own bomb\" — a stranger\n  clicking a shared bomb link has no FG to arm one, so it only diluted\n  the single real conversion goal. \"Join Claim Your Gold\" is now the\n  sole, primary CTA.\n- Fix that same join link: it built ?start=<code>, but the bot's\n  /start handler only recognizes the referral deep-link format with a\n  literal ref_ prefix (REF_START_PREFIX). Without it, /start fell\n  through to a generic welcome message with no portal registration\n  link at all — exactly why clicking \"Join\" started the bot but never\n  got anyone registered.\n- Mini App \"Drop in a Group\" button called switchInlineQuery with an\n  empty query and no fallback, so it silently no-oped outside full\n  Telegram inline-mode support and couldn't reference the specific\n  bomb anyway. The arm API already returns a real bombId/shareUrl —\n  now captured and shared via openTelegramLink/t.me/share/url, the\n  same universal approach BombShareModal already used correctly.\n- Roadmap: scoped configurable bomb duration as a Phase 10 follow-up\n  (currently fixed 60 minutes) per product discussion.",
      "refs": {
        "commit": "e473785c8a81641d1353d91ab8ee8dc9a08f9318"
      },
      "digest": "9b6bbc0af4d2d05d5e01458c6ba0f52666e1db3c6509bf0ad4bb49cfd8a5b82b"
    },
    {
      "id": "ship/claimyour.gold/b6ee0d61765d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-21T15:17:50Z",
      "kind": "fix",
      "title": "Fix Gold Bomb 404 link and 60-second/60-minute expiry mismatch",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Dashboard re-entry CTAs (ReEntryBanner, PersonaWarEntryCard) linked to\n/portal/bomb, which 404s — the real route is /portal/bomb/new.\n\nSeparately, every bomb-related surface (arm page, mini-app bomb page,\nTelegram DM/inline-query share text, BombShareModal) said \"60 seconds\"\nwhen the actual backend TTL (BOMB_TTL_MS in goldBombLifecycleService)\nis 3,600,000ms — 60 minutes. BombShareModal's countdown timer was the\nworst offender: it counted down from a hardcoded 60 real seconds and\nshowed \"Window closed\" a full 59 minutes before the bomb actually\nexpired, almost certainly suppressing shares/taps during most of the\nreal claim window. Countdown now runs off the real 3600-second TTL and\ndisplays as mm:ss.",
      "refs": {
        "commit": "b6ee0d61765d58153cfaa02ff615f1671180ece2"
      },
      "digest": "a726c81ccff6c8e33f0dcb9efea949b40eff907c52501f049a23446db41a9fd8"
    },
    {
      "id": "ship/claimyour.gold/cfb41b83df5d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-20T21:26:43Z",
      "kind": "other",
      "title": "Civilization architecture: City sub-nav, Crew tabs, cross-links, City Lore, Tournament",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Implements the docs/civilization-architecture-2026-07-20.md plan:\n\n- CitySubNav: shared sub-nav across all 6 City pages (Overview, Politics,\n  Governor, Council, Treasury, Rivalry, Lore) so they're always one tap\n  from each other instead of only reachable by direct URL.\n- CrewProfileTabs: converts the crew profile page from a 349-line\n  endless scroll into Overview / Crew HQ tabs, matching the pattern\n  already proven on Wars/Room. No backend changes — same services,\n  same data, just organized into tabs.\n- CivilizationStrip: persistent cross-link (City/Crew/Wars/Legacy)\n  added to all four domains so a user can jump between them without\n  losing their place.\n- City Lore (net new page): Monuments, Chronicle, Constitution, Census,\n  Pulse — wires up 5 already-built, previously-unused services\n  (cityMonumentService, cityChronicleService, cityConstitutionService,\n  cityCensusService, cityPulseService) that had zero UI anywhere.\n- Tournament bracket (net new tab in Wars/Room): new read-only\n  /api/portal/war-room/tournament route + TournamentBracket component,\n  wiring up crewTournamentService.getTournamentStandings() which also\n  had zero UI. \"War Betting\" intentionally NOT built this pass — found\n  three separate, ambiguously-named bet services (warBetService,\n  warWagerService already live as the Wager tab, warBetSettlementService\n  backing an unused route) and building against the wrong one would be\n  worse than flagging it for a product decision first.",
      "refs": {
        "commit": "cfb41b83df5db65a65587ec63211aab0942547bb"
      },
      "digest": "c004b8b5162edbfb3df8459522c5c61ef0e486f0f8e3b6b29c540e8eb532cf75"
    },
    {
      "id": "ship/claimyour.gold/ad47f5afc248",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-20T21:11:54Z",
      "kind": "feature",
      "title": "Add deep civilization-layer architecture (City/Crew/Wars/Legacy)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Documents three verified, concrete navigation breaks found by reading\nthe actual pages: city/page.tsx links to only 1 of its 5 sibling\npages, crew/[crewId]/page.tsx stacks 9+ features into one 349-line\nendless scroll with zero in-page nav, while wars/room/page.tsx already\nproves the right pattern (a real Tab array + tab bar). Proposes\nreplicating that pattern into City and Crew, adding a shared\nCivilizationStrip cross-link component across all four domains, and\nslots the City Lore gap in as a tabbed page matching the same pattern.",
      "refs": {
        "commit": "ad47f5afc2485f160e072a3b806e9ebb0a94a247"
      },
      "digest": "5c035931f3dd6fcabd15f3d2f7132fead8b54e6474afce4d208c4355b4697880"
    },
    {
      "id": "ship/claimyour.gold/b77dbe5bfc79",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-20T18:31:16Z",
      "kind": "feature",
      "title": "Add unified information architecture doc",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Full 387-page inventory across every surface (Portal, Super Admin,\nMini App, Academy, Client/Partner Portal, public marketing/content,\nshare pages), anchored to the real live 6-tab BottomTabBar taxonomy\n(Home/Earn/World/Crew/Compete/Profile) rather than a new one. Maps\nevery Phase 8/9 gap page onto a tab and gives Desktop Portal, the new\nMobile App, the Telegram Mini App, and the Telegram Bot one shared\nproduct graph instead of four drifting taxonomies.",
      "refs": {
        "commit": "b77dbe5bfc791490f5beb7515587bb4f7b74ec0f"
      },
      "digest": "b7dce7f33cceab929aeb70ae3ee5d806695b4fa3c67060afe2dc9d71dd3663a8"
    },
    {
      "id": "ship/claimyour.gold/aa7b05877aa8",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-20T18:05:48Z",
      "kind": "other",
      "title": "Phase 9: full 51-file mockup audit, backend-chain verification",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Corrects two Phase 8 assumptions: Partner Co-Marketing's existing\nservice/route is an unrelated read-only feature (no real campaign\nbackend exists), and AcademyTeamDomain is an orphaned Prisma model\nnever read by the team dashboard service. Confirms Client/Partner\nPortal and Super Admin gaps are tokenization-only with zero backend\nrisk, and extracts a concrete nav/breakpoint/state spec that unblocks\nstarting the Mobile App track.",
      "refs": {
        "commit": "aa7b05877aa82b73b1217a6d67fc341e8d3447ae"
      },
      "digest": "e780ef6005145e32a8ec7f73027b5eaaca60f203b9f3c3c57a8267c5893699ca"
    },
    {
      "id": "ship/claimyour.gold/e35a8cdfa037",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-20T18:00:01Z",
      "kind": "other",
      "title": "Phase 8: tokenize remaining raw-Tailwind/hex portal pages",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replaces stock Tailwind yellow-* classes and duplicated raw gold hex\nvalues with the existing --gold/--gold-hi/--gold-mid/--gold-deep tokens\nand .ink-gold gradient-text class across friends, hunter profile,\nwar-prediction form, quests list, and two settings pages. Leaves\nlegitimate non-gold colors untouched (WhatsApp/Telegram brand colors,\nquest-rarity tier colors, semantic status colors).",
      "refs": {
        "commit": "e35a8cdfa037ca228882fbc47349f65aa6889ed4"
      },
      "digest": "1e2b2ab27a9b815f5757b5d4c8cda0c04763c1faedf1a79addd2dfb568bf284e"
    },
    {
      "id": "ship/claimyour.gold/9422c9d93e8b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-20T17:49:20Z",
      "kind": "feature",
      "title": "Add Phase 8 mockup audit findings and design brief for remaining gaps",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Cross-referenced the 2026-07-20 design handoff zip against current main:\nonly 31 of 85 named mockups were actually present. Documents confirmed\nUI gaps (Mobile App track, City Lore, Retention surfaces, Round 2\ndesktop pages, War Tournament/Betting, tokenization cleanup) and lists\nexactly which mockups are still needed from the design team.",
      "refs": {
        "commit": "9422c9d93e8b7c836eed789df77c509297c6e7e1"
      },
      "digest": "7f45c4b26d23dfbaa559dbe677324ad02768ff16bea3d1c46f4edc4706d74460"
    },
    {
      "id": "ship/claimyour.gold/a7b20b34ffe8",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-20T12:52:16Z",
      "kind": "feature",
      "title": "Add explicit free-tier trust designation (Workstream 2, Phase A)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds AcademyTrack.isFreeFoundational — a permanent \"free forever, no\nstrings\" designation distinct from a track simply having no sponsor\ntoday. Set on \"Foundations of Flashy Gold\". Surfaces as a dedicated\ntrust strip on the Academy homepage plus a badge on the track card,\nper the Khan Academy lens from the boardroom roadmap: the free tier\nshould be an explicit product designation, not just implied by the\nabsence of a sponsor.",
      "refs": {
        "commit": "a7b20b34ffe87533a7526d72323b0ec358b82cd3"
      },
      "digest": "ae056f3f7813177e548015d8e106cad0631818a0c50cf30de3e06172cae58a49"
    },
    {
      "id": "ship/claimyour.gold/319e92f77cef",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T19:08:17Z",
      "kind": "feature",
      "title": "Add branch cleanup plan (archive-then-delete, 71 stale branches)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Ready-to-run script + full branch inventory. Could not execute from this\nenvironment (git writes are org-scoped to the working branch; tag pushes\nand branch deletes return 403). A maintainer runs the script; every\ndeleted branch is archived as a tag first, so deletion is reversible.\nProtects main/production/open-PR branches; leaves flashy-academy and all\nambiguous branches untouched.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017zgkFQpZtJVXjDnKBZDCuo\n(cherry picked from commit 04bc6476d9aff729a0b5f4b82dc58ac5507bfa82)",
      "refs": {
        "commit": "319e92f77cefb6cfe6b3ec533ebee2bf59230ed4"
      },
      "digest": "0ccec6194fa4500fe56075b27966442e0a95a9b04a1e0ed09d8e33eed0322aa8"
    },
    {
      "id": "ship/claimyour.gold/b353f3c49c72",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T17:39:21Z",
      "kind": "feature",
      "title": "Add boardroom brief: State of the Frontier & the Next Vision",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Grounded in a full-branch survey (2026-07-17). Key findings: the agent\neconomy already operates internally (9 agent orgs + agent-OS layer live\nin main); features have converged to main while ~109 branches (mostly\nstale forks) remain un-pruned; the binding constraints have moved from\n'can we build' to (A) ledger/value correctness and (B) convergence\ndiscipline. Ranks the highest-value work and fixes accordingly.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017zgkFQpZtJVXjDnKBZDCuo\n(cherry picked from commit 1780551f64efed458369e843ca3db90e6d2acc5d)",
      "refs": {
        "commit": "b353f3c49c7276bfb6c081ed4103354812a054d8"
      },
      "digest": "3f8baeb0ebf18eeaf364d276df1a3a3920c2c588f6f7ce18ab369564d08e9503"
    },
    {
      "id": "ship/claimyour.gold/85d1c7fd45f2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T16:16:15Z",
      "kind": "infra",
      "title": "Update remediation roadmap: mark Sprint-0 fixes applied",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017zgkFQpZtJVXjDnKBZDCuo",
      "refs": {
        "commit": "85d1c7fd45f2bc3786cba37ec18fba95f8a74e09"
      },
      "digest": "9a74878e0aec59426e46e78ad8fd6bd92124b3b14d2511b56e5b84ced2c426d0"
    },
    {
      "id": "ship/claimyour.gold/96b92196fd90",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T16:15:08Z",
      "kind": "other",
      "title": "Security remediation (audit 2026-07-17): FlashyGoldAMS money-path fixes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- FGA-P0-1: /ops console derives its session from the verified NextAuth\n  JWT instead of a forgeable x-super-admin-session header, and /ops is\n  now gated at the edge in middleware (SUPER_ADMIN only). Was both\n  bypassable by anyone and broken for real admins.\n- FGA-P0-2: Telegram Stars fulfillment is now idempotent — a new\n  ProcessedStarsPayment table claims the unique invoiceId before granting,\n  so a redelivered successful_payment no longer double-grants paid perks;\n  the claim is released on failure so genuine retries still work.\n- FGA-P1-1: auction placeBid runs in a transaction with a conditional\n  (gte) decrement + server-side integer validation, closing the\n  overspend/negative-balance race and the NaN-corruption hole. (Residual\n  concurrent double-refund needs an item-level optimistic lock — tracked.)\n- Updated auctionService tests for the transactional implementation.\n\nRequires  (new ProcessedStarsPayment model) before\ndeploy. Money-path changes need a human review run of the full suite.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017zgkFQpZtJVXjDnKBZDCuo",
      "refs": {
        "commit": "96b92196fd90adb73afa17ea81ba9a209f2dac69"
      },
      "digest": "697efab3901feb8efabd6071175c695bd8f00329ff644d5b204c86ba542ec9c0"
    },
    {
      "id": "ship/claimyour.gold/1ba300a94828",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T16:02:58Z",
      "kind": "infra",
      "title": "Remove duplicate seed-academy-gate-reward.ts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Superseded by seed-academy-founding-badge-reward.ts, which creates a\nreal Asset/RewardInventory/RewardOffer instead of searching for an\nexisting ACTIVE offer (the production redemption catalog had zero\nrows, so that search always came up empty). This file was resurrected\nby a parallel commit that independently produced the same generic\nscript before the founding-badge replacement landed on this branch.",
      "refs": {
        "commit": "1ba300a948285b3ac02c6e68d3735e10d59b4be6"
      },
      "digest": "96fa9578b87e6393f8e1187bbbc5a884d1499d5b6e4fc13229135057d9be1e84"
    },
    {
      "id": "ship/claimyour.gold/2fe32fa4294c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T16:02:10Z",
      "kind": "feature",
      "title": "Add 2026-07-17 security audit and remediation roadmap",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Deep bug-hunt across all three repos against current main. Records\nverified fixes since 2026-07-10, new P0/P1 findings (with file paths),\narchitecture/scaling items, metrics, and an execution plan with task IDs.\nInternal — contains unpatched vulnerability detail.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_017zgkFQpZtJVXjDnKBZDCuo",
      "refs": {
        "commit": "2fe32fa4294c66d471e699905b7bb913252cdd78"
      },
      "digest": "f55b305f8207c0339c36b4eb06b67c2044f1f90e812c59358d5db41a1c84e297"
    },
    {
      "id": "ship/claimyour.gold/6f8b41751809",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T16:00:56Z",
      "kind": "feature",
      "title": "Merge claude/audit-real-world-value-pages-xkwcxz: RWV content pillars, Academy homepage rebuild, gated-reward enforcement",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "# Conflicts:\n#\tsrc/app/academy/page.tsx\n#\tsrc/components/academy/PillarTrackCatalog.tsx\n#\tsrc/services/academyStatsService.ts",
      "refs": {
        "commit": "6f8b41751809c443b95382f451f89bb78a12c291"
      },
      "digest": "46a8b7fb30246803027556a974b87997db2faf0d872fb30dcff0fc32cdf927f9"
    },
    {
      "id": "ship/claimyour.gold/6cd7275962e2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T15:11:39Z",
      "kind": "infra",
      "title": "Wire a gated reward to the Claim Your Gold-sponsored Foundations track",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Phase 3 POC follow-up: picks the lowest-cost ACTIVE RewardOffer from the\nlive redemption catalog and sets it as gatedRewardOfferId on the\nfoundations-of-flashy-gold track, completing the sponsor + gated-reward\nloop the POC was built to validate.\n\n(cherry picked from commit ac75dfee4e317ac7c5986add01404540ed3add45)",
      "refs": {
        "commit": "6cd7275962e2ea84d926e085314e3dd72d1c9d45"
      },
      "digest": "3bb81e65f19fb7b5365aa2cef0b41d65593a9a6a9f464899f37d67dacb0ee269"
    },
    {
      "id": "ship/claimyour.gold/af3acc5542a6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T14:27:38Z",
      "kind": "other",
      "title": "Warn loudly when Cloudflare cache purge is skipped",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Missing CLOUDFLARE_API_TOKEN/CLOUDFLARE_ZONE_ID previously caused the\npurge step to skip silently with a green run — origin deployed fine but\nthe edge kept serving stale HTML with no visible signal in the workflow\nsummary. Adds a non-blocking warning annotation so this surfaces.",
      "refs": {
        "commit": "af3acc5542a6601f6748b3f75475d3e0d7ab46dc"
      },
      "digest": "ef4737446e579e759db2a23a967e9e81969702bf1889321c369ec17069805363"
    },
    {
      "id": "ship/claimyour.gold/c42015930dbe",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-17T14:15:19Z",
      "kind": "infra",
      "title": "flashyos-branch-mesh-sync: exit 1 when every branch fails to sync",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A 71/71 mint-401 run (empty repo secret, then key mismatch) reported green\nfor weeks because the script counted failures without acting on them.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01QHLsQKC7ryL64i65RfFvJF",
      "refs": {
        "commit": "c42015930dbe7b840536f34110099c4e6b9c9561"
      },
      "digest": "5ae129490a726c0c52ae92cf3f627990fddcb7952690c57c8c36260efdbd18e1"
    },
    {
      "id": "ship/claimyour.gold/a1b71d4818c6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-16T16:49:31Z",
      "kind": "infra",
      "title": "Wire the three viral growth-loop events to the cross-org Engagement Bus",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "docs/network-effects-events.md in flashyos claimed crew_critical_mass_reached,\nviral_share_converted, and d30_retention_hit were already shipped from these\nservices — no emit point existed in any branch. This makes the claims real:\n\n- crewCriticalMassService.announceCriticalMass -> crew_critical_mass_reached\n  { memberCount, thresholdTier } once dedup passes and the crew exists\n  (milestone is real even when no DMs can be sent)\n- goldenInviteService.activateGoldenReferral -> viral_share_converted\n  { channel: 'golden_invite' | 'referral' } after the conversion completes\n- d30ChampionService.awardD30Champion -> d30_retention_hit { cohortWeek }\n  alongside the badge grant; cohortWeek is the ISO week of the join date\n  (award fires at exactly D30 +/-1h), via getWeekKey extended to take an\n  optional date\n\nAll events NETWORK-visibility per the shared v1 contract; the bus remains a\nsilent no-op until FLASHYOS_* / NETWORK_BUS_HASH_KEY are provisioned. Tests\ncover both the emit and no-emit (dedup, non-milestone, referrer-not-found)\npaths.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01QHLsQKC7ryL64i65RfFvJF",
      "refs": {
        "commit": "a1b71d4818c688d4553383197d9bfb449bc68ce6"
      },
      "digest": "4ebd6dc7fa8d167b25360a85ba3561b450134fceea58087a8e6cf4c9312140ee"
    },
    {
      "id": "ship/claimyour.gold/2132ecb8f492",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-15T22:09:16Z",
      "kind": "infra",
      "title": "Rebuild Academy homepage with pillar stats + filterable catalog, on tokens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Re-applies real new content from an unmerged branch (origin/claude/\naudit-real-world-value-pages-xkwcxz) — a pillar-framework stats bar and\na filterable track catalog grouped by pillar — but on top of the\ncurrent tokenized design (.glass/.eyebrow/.ink-gold/.pill, var(--gold))\ninstead of that branch's stock-Tailwind rewrite, which would have\nregressed the completed Phase 3 token migration.\n\nNew PillarTrackCatalog client component replaces the flat track list\nwith a pillar-filter chip row + filtered results. Stats are sourced\nfrom the new getAcademyHomeStats() (academyStatsService.ts) and\nSEASON1 — no fabricated numbers. listAllPillarPages() added to\nacademyPillarPageService.ts to support unpublished/upcoming pillars\nshowing as \"coming soon\" in the filter row.",
      "refs": {
        "commit": "2132ecb8f492f52b71a6fc3737063f07d19c6dc2"
      },
      "digest": "2dbc4a516fb9b4010429861d8e5e9684400b089e7e3b6473bee767953b73de5b"
    },
    {
      "id": "ship/claimyour.gold/82c5902ab0a0",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-15T18:15:45Z",
      "kind": "other",
      "title": "Mark Phase 6 (Telegram Mini App) complete in roadmap",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "82c5902ab0a0a952f78828b428695f71ec3023b9"
      },
      "digest": "519ebc6052ce1d1881b44791691664262b6c1958671362a6e23e62025b9ed5c0"
    },
    {
      "id": "ship/claimyour.gold/2801e8a36efe",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-15T18:11:20Z",
      "kind": "feature",
      "title": "Telegram Mini App: port Creator Dashboard, Settings, Recap, Auction, Shop, Raids, Vault, Trophy Vault",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Round 5 close-out brief, final batch — completes Phase 6 (Telegram\nMini App) of the master redesign roadmap. Native Mini App treatment\n(TelegramProvider hook, --tma-* tokens) for the last 8 desktop-only\nportal features, reusing existing portal API routes where they\nexisted and adding a thin new recap route where needed.",
      "refs": {
        "commit": "2801e8a36efea64b5038eb5bc08549c3768c6097"
      },
      "digest": "b316ad6bc0bbc4080f6c16d7b1381f87cf05debf38a7cfc1161620df6b398baf"
    },
    {
      "id": "ship/claimyour.gold/67fecd0e02b4",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-15T17:13:22Z",
      "kind": "feature",
      "title": "Add Phase 7 bot teaser layer and chat-native check-in/spin flows",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- FEATURE_TEASERS registry + /explore command: single-tap teaser menu\n  linking to every Mini App feature shipped in Phase 6 (governor, gift,\n  loan, missions, spy, tip, airdrop, black-market, geo-rank,\n  hall-of-fame, kfactor, league, live-leaderboard, spin, auction,\n  creator-dashboard, raids, recap, settings, shop, trophy-vault, vault).\n  Buttons deep-link straight into the Mini App; no data-dense bot UI.\n- Chat-native flows via callback_query (no Mini App needed):\n  - /spin + \"Spin Now\" button resolves the daily spin inline.\n  - \"Check In Now\" button added to the existing streak reminder and\n    streak-danger DMs, resolving claimDailyStreak() inline instead of\n    only deep-linking out to the Mini App.\n- Kept BOT_COMMANDS (the \"/\" picker) at its existing 8-command cap by\n  design; /explore and /spin are surfaced via /help instead.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "67fecd0e02b4fde71937308b9710414543896027"
      },
      "digest": "236f140f5f3ae726b11243e70a7e7bd97c197c7fbfe6a3bed51ef5780875f859"
    },
    {
      "id": "ship/claimyour.gold/350307d02bef",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-15T16:58:48Z",
      "kind": "infra",
      "title": "Update Phase 6 roadmap status: batches 1+2 shipped, 8 features remain",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "350307d02bef5d14a70ab9324cd5310cea1ae63e"
      },
      "digest": "c8136ab008d2af3c5c38a87dc5700e48c6d36de23cbfd1d3c292a00c3272ae28"
    },
    {
      "id": "ship/claimyour.gold/5dddb9cf85d5",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-15T15:17:46Z",
      "kind": "feature",
      "title": "Telegram Mini App: port Airdrop, Black Market, Geo Rank, Hall of Fame, K-Factor, League, Live Leaderboard, Spin",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Round 5 close-out brief, batch 2 — native Mini App treatment for eight\nmore desktop-only portal features, reusing existing portal API routes.\nCompletes the Engagement Extras and Competitive Extras scope from\ndocs/masterredesignroadmap.md Phase 6.",
      "refs": {
        "commit": "5dddb9cf85d51e61a73212e8e447321bc92daa14"
      },
      "digest": "54d40300d36cff747e5e048602e4fd68e042e092592374b37812e7f3548f942c"
    },
    {
      "id": "ship/claimyour.gold/02ffa776c839",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-15T15:17:27Z",
      "kind": "fix",
      "title": "settle all pending claims, DB dedup fallback, double-subtract",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- prisma/schema.prisma: add @@unique([bombId, telegramId]) on BombClaim,\n  giving the DB dedup fallback a real constraint to key off of.\n- goldBombActivationService.ts: settlement previously used findFirst,\n  silently dropping all but the newest pending claim for a user — now\n  findMany, settling every pending claim.\n- goldBombLifecycleService.ts: claim dedup relied solely on Redis SET NX;\n  added a bombClaim.findUnique fallback for when Redis is unavailable.\n- telegram/bot/route.ts: fixed a double-subtract in the claim DM copy —\n  bomb.remainingAmount is already post-claim, so subtracting claimAmount\n  again showed a lower balance than actually remained.\n\nAlso fixes a pre-existing mock leak in goldBombService.test.ts:\njest.clearAllMocks() doesn't reset mockResolvedValue return values, so\na later test's bombClaim.findUnique.mockResolvedValue(...) was bleeding\ninto two earlier-ordered tests that didn't expect it. Added an explicit\ndefault in beforeEach.\n\nRe-applied by hand from a stale branch (origin/claude/funny-noether-75ghqx)\nwhose file layout had diverged from current main after a service split.",
      "refs": {
        "commit": "02ffa776c8390ce78658565887f6895d41d40b34"
      },
      "digest": "28bbfff7d8b397b8b1b72641db38e43e50bf5afb225fe485d807c9c8739e39e7"
    },
    {
      "id": "ship/claimyour.gold/44f9faa4ca08",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-15T09:22:25Z",
      "kind": "fix",
      "title": "quarantinedPaths() used __dirname, which resolves incorrectly under jest's TS config loader — quarantine list was silently never applied",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The flaky-test quarantine mechanism (tests/quarantine.json,\nscripts/quarantine-test.sh) has never actually worked: __dirname is\nundefined when jest-config parses jest.config.ts via its native\nTypeScript config loader, so path.join(__dirname, ...) threw, and the\nfunction's try/catch silently swallowed the error and returned [].\nConfirmed via --showConfig: a literal path hardcoded in the same array\nwas honored, but the quarantinedPaths() spread never contributed\nanything. Switched to process.cwd(), which resolves correctly in both\nthe native TS loader and a plain Node require().\n\nAlso quarantines tests/services/personaService.test.ts — a small,\notherwise-passing test file whose jest worker intermittently runs out\nof memory under the suite's default parallelism (reproduced 7 times in\na row via the pre-push hook; passes clean in isolation and at\n--maxWorkers=2 every time). This is exactly the scenario the\nquarantine system exists for.",
      "refs": {
        "commit": "44f9faa4ca08c9e99c5c702d284e89d1f62e7703"
      },
      "digest": "03ba0286166b9a2f4758b3d756b32efe72cd6182ecea1dab856bb47226e7fa2c"
    },
    {
      "id": "ship/claimyour.gold/680d915427de",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T22:49:55Z",
      "kind": "infra",
      "title": "Update streakMilestoneService test for the 90-day TTL added in the referral fix batch",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "680d915427dee48cdec833371cab81850059f239"
      },
      "digest": "77dc3a7760b48e760a14c074525f0ca8252a10a4cd44469e3a575a1d20c3fa11"
    },
    {
      "id": "ship/claimyour.gold/d0ab2f9e0ed4",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T22:30:29Z",
      "kind": "fix",
      "title": "wrap processResidual in transaction, credit missing tier bonuses",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "processResidual previously read-then-wrote the referral chain and\nreward ledger outside a transaction, risking a double-spend on\nconcurrent residual processing. Wraps the operation in $transaction\nand adds the missing wallet credits for tier-1 and tier-2 bonuses,\nwhich were being recorded in the ledger but never applied to the\nwallet balance. Re-applied by hand from a stale branch\n(origin/audit/codebase-audit-optimize, commit f725db6b) whose file\nlayout had diverged from current main.",
      "refs": {
        "commit": "d0ab2f9e0ed4f4927b0cdd734ca3529da7da493d"
      },
      "digest": "84328ff340668b86b6e6de22e378660904588aaa50b96c58616296f7e155d8dc"
    },
    {
      "id": "ship/claimyour.gold/5db6334758fe",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T22:12:43Z",
      "kind": "fix",
      "title": "use real pre-transaction wallet balance in goldLedger entries",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Several services hardcoded balanceBefore: 0 (and a fixed balanceAfter)\nin their goldLedger.create calls, which breaks the ledger's audit\ntrail whenever a wallet already has a balance. Fetch the real wallet\nbalance before the transaction and compute balanceAfter relative to\nit, across crewTreasuryRaffleService, debtForgivenessService,\nfactionDefectionService, hunterDuelService, and prestigeTitleService.\nUpdated the two affected test mocks to stub wallet.findUnique.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "5db6334758fec50b347b45324d19b33c23b34a7c"
      },
      "digest": "6c4cfd3a8b54945345733cf86c112cf6a5cb26304328639f5bf05cd4e657c311"
    },
    {
      "id": "ship/claimyour.gold/d0b3865a5b57",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T22:07:52Z",
      "kind": "fix",
      "title": "replace Math.random() with crypto in duel/challenge/lottery",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Math.random() is not cryptographically secure and its output is\npredictable, making it unsuitable for invite-code generation, lottery\nwinner selection, and duel share IDs. Swap in crypto.randomInt /\ncrypto.randomBytes for these security/fairness-sensitive paths, and\nfix an N+1 customer lookup in the lottery winner-notification loop\npicked up in the same commit upstream.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "d0b3865a5b5794c4561e229bdd558ead1d4ba441"
      },
      "digest": "3382e19ce2080301ca9a603bdf8c27395d0dabf4e32e27234c69506300f65c46"
    },
    {
      "id": "ship/claimyour.gold/67b780b79b1f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T21:50:04+02:00",
      "kind": "feature",
      "title": "Merge pull request #46 from FlashyLabs/fix/smoke-test-cold-start-retry",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Retry smoke-test checks to survive canary cold starts",
      "refs": {
        "commit": "67b780b79b1fc6630f0b3987c4aff5afe94d5dd8",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/46"
      },
      "digest": "484ce974d75f449fd432c76a9b9bf247c240445710daad88f36e01c6dd82cdd7"
    },
    {
      "id": "ship/claimyour.gold/ae4916ed5d73",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T21:18:17Z",
      "kind": "feature",
      "title": "Add Phase 4 flagship track: How Money Actually Works (Pillar 2: Economics)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Seeds articles, track/modules, and quiz for the Economics pillar's\nflagship track per the Academy #1-destination roadmap.",
      "refs": {
        "commit": "ae4916ed5d73b90717e6bfab7d52b5a1f98aa3de"
      },
      "digest": "e25a89ec6d6e0119759280df705b2344e2671bdb5088f4d7e8846b3042692de5"
    },
    {
      "id": "ship/claimyour.gold/252aa26c7315",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T20:17:53Z",
      "kind": "other",
      "title": "Mark Phase 3 (Academy) and Phase 5 (Super Admin) complete in roadmap",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "252aa26c7315db52ddbdf1914ac4026b8b444e0c"
      },
      "digest": "b0776997ac671188db7104738a83a246610f6da35421c959bc98defa1be2e6d3"
    },
    {
      "id": "ship/claimyour.gold/a80a94531d39",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T20:16:26Z",
      "kind": "other",
      "title": "Tokenize final 16 Academy pages, completing Phase 3",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "tracks/*, partner, resources, tools/*, learn/*, pricing,\nnewsletter/unsubscribe/[token], leaderboard (root + nations),\nwars/*, challenge/[token]. All Academy pages now use the shared\n.glass/.eyebrow/.pill/.ink-gold token system and --gold/--gold-hi/\n--gold-deep CSS vars.\n\nchallenge/[token] and wars/[slug]/recap previously used a standalone\nhardcoded black-gold hex palette (same visual intent, different\nimplementation) — mapped to the equivalent design tokens.",
      "refs": {
        "commit": "a80a94531d399cec86e0940dfd11145a52eb9f89"
      },
      "digest": "b7a33d4c3e17f00e6bcb57f2737dfee4f384a280227d2de5c6eba41ae084413c"
    },
    {
      "id": "ship/claimyour.gold/262761921b72",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T19:46:48Z",
      "kind": "feature",
      "title": "Telegram Mini App: port Governor, Gift, Loan, Missions, Spy, Tip Jar",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Round 5 close-out brief, first batch — native Mini App treatment\n(TelegramProvider hook, MainButton/BackButton, haptics, --tma-* tokens)\nfor six desktop-only portal features: Governor election, P2P gifting,\nFG Loan, Daily Missions, Spy Network, and Tip Jar. Also wires the\nRookie Quest chain/streak banner into the Mini App quests page (was\ndesktop-only until now). All reuse existing portal API routes — no\nbackend duplication.",
      "refs": {
        "commit": "262761921b7285bb6cd4a3dec3e0e7b7cbbdafc8"
      },
      "digest": "f9d7c74a02b5e44c5f7220bb047611a939ca5d3631d3c38023f191853362aff0"
    },
    {
      "id": "ship/claimyour.gold/e612322f0d4c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T19:39:48Z",
      "kind": "infra",
      "title": "Migrate final 14 Super Admin pages to shared DataTable/AnalyticsPageHeader",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Completes Phase 5 of the master redesign roadmap — all 79 Super Admin\npages (excluding login/verify-2fa auth pages) now use the shared\nDataTable/AnalyticsPageHeader chrome. articles, audit-logs, callbacks,\nclients/partner-slugs, dashboard, deploy-metrics, fraud, gold-rush,\noverview, reward-partners, settings, telegram, users/[id], viral-analytics.\n\nChrome-only swap; all data fetching, filters, sorting, and business\nlogic preserved exactly. A few pages (overview, deploy-metrics,\ngold-rush, telegram) are header-only since they have no tabular\ncontent. Dashboard's long-pending-redemptions alert table was\ndeliberately left bespoke to preserve its red alert-severity chrome,\nwhich DataTable's neutral styling can't express.",
      "refs": {
        "commit": "e612322f0d4c06be2766f856e239381a907ab4b8"
      },
      "digest": "bcef6f6b0f50e875e91948edbe744d785cd42bf7fb13ff6a90f9e6ae3ef93b9b"
    },
    {
      "id": "ship/claimyour.gold/5be6d4321355",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T19:26:33Z",
      "kind": "infra",
      "title": "Migrate Super Admin batch 1 to shared DataTable/AnalyticsPageHeader (13 pages)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "ab-results, activity-stream, agents, analytics/academy-fraud,\nanalytics/challenges/[slug], analytics/client-attribution,\nanalytics/crew-prestige, analytics/events (header only), analytics/gold-economy,\nanalytics/page (main analytics hub, ~10 tables), analytics/quests/[slug],\nanalytics/realtime, analytics/referral-funnel — chrome-only swap of bespoke\ntable/header markup for shared components; no data fetching, filters,\nsorting, or business logic touched.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "5be6d4321355a61425e38b00dcb283e1d40b8f08"
      },
      "digest": "4c5ad43db69786718574173013f80d1e6166f380efea4731761ed13e7ba376fc"
    },
    {
      "id": "ship/claimyour.gold/59d9e3950176",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T19:21:57Z",
      "kind": "other",
      "title": "Tokenize Academy pages batch 2 (bounties, case-studies, crews, employers, faq, featured, graduates, hall-of-fame, hunters, leaderboard/[trac",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Color/class substitution pass: adopt .glass/.eyebrow/.pill/.ink-gold and\nvar(--gold*) tokens in place of raw hex and stock Tailwind primary/gray\nutilities, matching the established Academy design-token convention.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "59d9e3950176ffefe42147945e54ff82d5a1c737"
      },
      "digest": "28db1e5b046c389a59241da30b01bee559ae076ca487114ea774ac52a3f1eeaa"
    },
    {
      "id": "ship/claimyour.gold/d84f8c899f78",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T18:48:22Z",
      "kind": "fix",
      "title": "Correct Phase 5 remaining-page count via live grep (29 not 36)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A stale count assumed 36 pages remained on the DataTable/AnalyticsPageHeader\nshell; a live grep against main found 50 of 79 already done, 29 remaining\n(27 untouched + 2 partial), including four newer analytics pages\n(academy-fraud, client-attribution, crew-prestige, gold-economy) missing\nfrom the original list entirely.",
      "refs": {
        "commit": "d84f8c899f787f9de1b82017ca5e148e1d96b0ad"
      },
      "digest": "e09e9fe245b579703ed9216a52b2b025de3909a6ee92160fb3ec72adcdca10a2"
    },
    {
      "id": "ship/claimyour.gold/5139438caa80",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T17:42:21Z",
      "kind": "infra",
      "title": "Migrate 11 Super Admin pages to shared DataTable/AnalyticsPageHeader",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "transactions, funnel, challenges, referrals, clients, monetization,\nwaitlist, quests, segments, scarcity-badges, users — chrome-only swap\nof bespoke table/header markup for the shared components; no data\nfetching, filters, sorting, or business logic touched. campaigns/page.tsx\nwas checked and skipped (card-based layout, no table markup, applies).",
      "refs": {
        "commit": "5139438caa80103ab4033df3b48c7a6b7195bfe3"
      },
      "digest": "a29d305eeea76aa330ed4c9c2953846b2fe2247a85d392d51278260fbabf3d59"
    },
    {
      "id": "ship/claimyour.gold/4ddff8c3dc5a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T17:36:26Z",
      "kind": "other",
      "title": "Tokenize Academy pages batch 1 (root, admin reports, teams/cpd/cert-wall/progress/quiz/impact)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replace raw hex, ad-hoc grays, and stock Tailwind color utilities with the\ndesign-token system (.glass/.eyebrow/.pill/.ink-gold, var(--gold*),\nvar(--danger-urgency)) across 11 Academy pages, per Phase 3 of the master\nredesign roadmap. Pure color/class substitution — no layout or copy changes.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "4ddff8c3dc5a7e6661b51f9a691d5cb2b79344ce"
      },
      "digest": "821a2fea438275210fb6abfd6a78b22b4d9246ae95b380396d903ccf14a68d74"
    },
    {
      "id": "ship/claimyour.gold/98dbe45deede",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T17:19:07Z",
      "kind": "feature",
      "title": "Add Round 6 Track E UI: Golden Era, Burn Event, Retirement Vault, Eternal Flame, Legacy, Prestige Showcase",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Builds frontend for the Economy & Prestige Flavor track (docs/round6designbrief.md\n§4 Track E) on top of existing zero-UI Prisma services:\n\n- Golden Era: site-wide banner (GoldenEraBanner) mirroring the GoldRush banner\n  pattern, mounted in the portal layout.\n- Burn Event: banner on the Redeem page surfacing the active cashback window.\n- Retirement Vault: new \"Retirement\" tab on the Vault page, clearly\n  differentiated (180-day/2x payout) from the existing 7-day lock/unlock tab.\n- Eternal Flame: small badge chip on the crew page hero, shown only for the\n  crew currently holding the trophy.\n- Legacy Deed + Legacy Wall: new /portal/legacy page with a deed-writing form\n  and a public wall of other hunters' legacy statements, styled in the Weekly\n  Recap tone.\n- Prestige Showcase: new /portal/prestige-showcase leaderboard page styled\n  like the Empire/Dynasty pages with the --prestige-purple token.\n\nFG Loan already had a working UI (LoanPanel.tsx on the Vault page) — skipped\nper the brief's \"don't re-design what's built\" rule.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "98dbe45deedeb4dd2434d48d7ecddf3769f7f708"
      },
      "digest": "dcb28f2a40d608750994cdb47dc3a45fb741df0052dea0124b2c751156d3790f"
    },
    {
      "id": "ship/claimyour.gold/cfef9889d482",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T17:15:53Z",
      "kind": "feature",
      "title": "Add Academy Team Dashboard admin page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Builds the missing UI for the existing academyTeamDashboardService /\nGET /api/v1/admin/academy/team-dashboard contract: a domain-lookup form\nplus a per-member table (certs, Flashy Gold earned, last active), styled\nwith the established .glass/.eyebrow/.pill/.ink-gold token system.",
      "refs": {
        "commit": "cfef9889d48291f5a89ac12ae3ed558e95b04c9f"
      },
      "digest": "119bab10c79a6b16312892518f2780dd8af923aef5d0fd34affffad4bfbac0fb"
    },
    {
      "id": "ship/claimyour.gold/e6d5678d907c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T17:01:16Z",
      "kind": "feature",
      "title": "Add Round 6 Track B (Crew Social) and Track C (War Meta / War Room)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Track B: wire crewLoreService, crewMascotService, crewEmbassyService,\ncrewDiplomacyService, crewInvestmentService, crewIntelService, and\ncrewNoticeboardService into the crew profile page via CrewHQPanel,\nCrewIdentityEditor, CrewNoticeboard, and CrewRecruitmentBanner.\n\nTrack C: new \"War Room\" hub at /portal/wars/room aggregating\nwarsAnnalService (+ replay viewer), crewTerritoryService (hero district\ngrid), grudgeMatchService, warChallengeService (adds getCrewChallenges +\na GET list route), siegeEventService, warWagerService with\nwarHandicapService context, and a live ticker backed by\nunifiedActivityStreamService. Linked from the existing /portal/wars page.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "e6d5678d907c3fff9495bd9c35e2a7ee550bbbf4"
      },
      "digest": "0d3c9f3d8da4816672c897212bf436a2612c7d96cea5635974e6bcc24c07a2fb"
    },
    {
      "id": "ship/claimyour.gold/e134b5eb5848",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T16:42:40Z",
      "kind": "feature",
      "title": "Build Round 6 Track A (City Politics) and Track D (Hunter Identity) UI",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Wires existing zero-frontend-caller API routes (parliament, proposal,\nreferendum, tip, mood, inbox, missions, collector-badges, reputation,\nnickname, title, my-data) to new UI:\n\n- City Politics page (parliament seats, proposals with vote/submit,\n  referendums with yes/no vote bars + countdown), linked from City hub nav.\n- Extended getActiveReferendums() to include yes/no vote tallies.\n- Profile page: Reputation Score card with tier ladder, nickname +\n  daily mood/status editor, seasonal title pill — new sections built on\n  .glass/.eyebrow/.pill tokens.\n- Hunter Inbox: new bell in global header (distinct from NotificationBell)\n  + dedicated /portal/inbox list view.\n- Collector Badges section on the badges page, civic-teal styled and\n  visually distinct from the existing badge wall.\n- Settings index page with a \"Download my data\" GDPR export button.\n- Restyled referral-receipt page onto .glass/.eyebrow/.pill tokens.\n\nTip Jar was skipped — TipButton.tsx + /api/portal/tip already fully\ncovers it on the public hunter profile page.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "e134b5eb5848fa921bb5a728105ef2f26005ca0e"
      },
      "digest": "e873fd8f64efeb78fae9e36d7baaba8d979ccbc66b633c18b889e7c4a93694a5"
    },
    {
      "id": "ship/claimyour.gold/fcf81be01769",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T16:18:44Z",
      "kind": "fix",
      "title": "Restore priorityScore computation dropped during atlas/big-data-analytics merge",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Merging atlas/big-data-analytics's monolithic superAdminService.ts/\nanalyticsService.ts against main's already-split versions initially kept\nmain's split files as-is (all top-level function names matched), but two\nfunctions had grown real logic upstream that main's split never got:\nlistSuperUsers's priority sort branch and getUserProfile's priorityScore\nfield, both via reengagementPriorityService. Ported into the split\nuserOpsService.ts / usersAnalyticsService.ts. Full suite green.",
      "refs": {
        "commit": "fcf81be0176984c222cca2d31a67cbf998271d21"
      },
      "digest": "41554a7a6494b1fd985ade0dc0b8f609ba697fe948d9aa003d138bbbaf7efc08"
    },
    {
      "id": "ship/claimyour.gold/5fda7a55d881",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T16:14:19Z",
      "kind": "infra",
      "title": "Client/Partner portals: migrate remaining raw hex/stock colors to design tokens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replace #f5c547/#facc15 hex literals and stock amber/yellow Tailwind\nutilities in the Partner dashboard/campaigns pages, and Client dashboard/\nsettings/docs warning banners, with the shared --gold and --danger-urgency\nCSS custom properties from globals.css. Genuine semantic red/green/blue\nstates and the dev-only bypass button are left untouched.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "5fda7a55d8816959a7002e4c338a4f476e906cb3"
      },
      "digest": "35848077a86befe78759d4346341eecf965fd2b7d65c5b82470e80d3502e81e0"
    },
    {
      "id": "ship/claimyour.gold/0e14922f8113",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T15:59:48Z",
      "kind": "fix",
      "title": "Correct roadmap phase 3-5 estimates against a live code verification pass",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Academy: 9 of 61 pages tokenized (not the small handful implied),\n~52 genuinely stale, plus a confirmed new-page gap (Team Dashboard).\nClient/Partner Portal: zero pages use the token system at all — prior\n\"done\" checkmarks referred to IA/component work only. Super Admin:\ncorrected total page count to 79 (not ~92/~50), 43 done, 36 remain.",
      "refs": {
        "commit": "0e14922f8113ba578e2e3ff68ec0964d8893b011"
      },
      "digest": "944bcea57651783ecffed51b1df9be623a06212473c6f44a96f393a42c59a4b2"
    },
    {
      "id": "ship/claimyour.gold/60e6c45e0ef2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T15:50:45Z",
      "kind": "infra",
      "title": "Migrate 27 super-admin analytics pages to shared DataTable/AnalyticsPageHeader",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replaces duplicated header markup and inline <table> markup across the\nanalytics suite with the shared src/components/admin/DataTable.tsx and\nAnalyticsPageHeader.tsx components, continuing the migration started on\nthe 16 already-converted pages. Presentation-layer only — no data\nfetching, business logic, or API contract changes.\n\nMigrated: academy, activity-stream, anomaly-heatmap, bomb-roi, campaigns,\nchallenges, channel-retention, churn-prediction, churn-signals,\ncrew-health, divisions, event-stream, gifting, gold-bombs, gold-forecast,\ngold, lifecycle, loop-status, metrics-explorer, quest-benchmarks, quests,\nreward-catalog, segment-drift, social, time-to-value, users, viral-growth.\n\nSkipped (unique inline-style layouts that don't fit the Tailwind\nDataTable/card pattern): client-attribution, referral-funnel, realtime.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "60e6c45e0ef2f85083073270090afd446066ae0f"
      },
      "digest": "53114c6a6da5ebb859535ba5ada6118c0901318a49bef4b2473460af3ca9bc84"
    },
    {
      "id": "ship/claimyour.gold/2a618e2273a1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T15:34:23Z",
      "kind": "fix",
      "title": "Telegram Mini App: fix two pages not using tma-* theme tokens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "crew-hunts and the root entry splash screen were using stock Tailwind\ncolors (yellow-400, plain sans-serif inline styles) instead of the\n--tma-* CSS variables Telegram injects, which the rest of the Mini App\nalready follows. Brings both in line with the established pattern.",
      "refs": {
        "commit": "2a618e2273a13a36c72d1bcfc6e1367caade948d"
      },
      "digest": "6ccba4148f7d08360367fc44f0e804211e28b2f1cc654fd98e3dbb96cc39913d"
    },
    {
      "id": "ship/claimyour.gold/77eab0400c2b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T15:24:56Z",
      "kind": "feature",
      "title": "Add master UI redesign roadmap across web app + Telegram bot",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Single source of truth for redesign status: 7 phases from the\nalready-shipped Customer Portal through the just-delivered Round 6\nCivic & Social Layer mockups, Academy/Client-Partner/Super Admin\nreconciliation work, Telegram Mini App parity, and Telegram Bot\n(not yet started). Includes suggested execution order and explicitly\nscopes out FlashyOS marketing-site mockups (different repo).",
      "refs": {
        "commit": "77eab0400c2b0a074d0ac46bc9f0ba17a1e0c0fc"
      },
      "digest": "1927558410597aa855d5c07a6aee34d005f4a772ec234ba6e21854c086048916"
    },
    {
      "id": "ship/claimyour.gold/233054e75eeb",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T14:26:43Z",
      "kind": "feature",
      "title": "Add Round 6 design brief: civic/social layer with real backend, no UI",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Corrects an earlier stale automated audit's \"zero UI\" claims against a\nlive re-check of the codebase (Governor Election, City Council,\nRookie Quest, and Spy Mission/Report were already built and wired;\nremoved from scope). Covers five genuinely-unbuilt tracks — City\nPolitics, Crew Social/Flavor, War Meta, Hunter Identity, and\nEconomy/Prestige Flavor — each citing the real service file and\nfunction signatures behind it.",
      "refs": {
        "commit": "233054e75eebc3ff4042b33d90c99baeb80792a2"
      },
      "digest": "08380162be82dabbdc407d91e305729dbc869913d1af2b31a069eef00e729a00"
    },
    {
      "id": "ship/claimyour.gold/b3d221cb96e2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-14T14:23:39Z",
      "kind": "feature",
      "title": "Merge bootstrap-key wiring for FlashyOS agent minting into main",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "b3d221cb96e2d25333f305c4c46631f3454e1c63"
      },
      "digest": "b00077cb166643b7152dcdcf65b9b0d63b207628259ea8b004ebe6f92d27de0a"
    },
    {
      "id": "ship/claimyour.gold/a7c364d2ad15",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-13T14:25:52Z",
      "kind": "fix",
      "title": "Fix Season 1 campaign copy: \"qualified to claim\" not \"earned\"",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "549K is the total user count, not the qualified-claimant count\n(68,700 in season1.ts) — \"earned\" overstated what that figure means.",
      "refs": {
        "commit": "a7c364d2ad154176be5f13f0cedb3602e88d8757"
      },
      "digest": "d1af83146859e01b6f9d73a46a93570c4d52a21808b66194357e6134ead19f36"
    },
    {
      "id": "ship/claimyour.gold/f45e55fc3d29",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-12T12:57:59Z",
      "kind": "other",
      "title": "Rebrand Phase 3 sponsor as Claim Your Gold itself, not a generic Flashy Labs label",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Uses the real domain (claimyour.gold) and notes the existing site logo\nasset (public/claimyourgold-logo.png) as the sponsor's branding source\nfor when Phase 4's self-serve dashboard needs to render it. Idempotent\nupdate also fixes up the existing sponsor record if this ran once already\nunder the old naming.",
      "refs": {
        "commit": "f45e55fc3d29cfab1a06330166c8c3fb6d4fe127"
      },
      "digest": "c1ae5dc452e4b567972fc26db36c15b8348da4f9fe80521258bc450befba613b"
    },
    {
      "id": "ship/claimyour.gold/348560fc38d1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T23:45:05Z",
      "kind": "other",
      "title": "Phase 3 POC: script to sponsor an existing track internally as Flashy Labs",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Upserts an internal 'sponsor' Client (Flashy Labs itself) funded with a\nGold pool, and tags the existing foundations-of-flashy-gold track with\nit via sponsorClientId. This validates the sponsor-debit + certificate\nloop shipped in Phase 2, before any external brand is involved.\nIdempotent, no gated reward offer wired yet (payout-loop validation only).",
      "refs": {
        "commit": "348560fc38d1c4dc6ab070fbd1812a547b530875"
      },
      "digest": "2351a3178cdcd16a8c513f9ae48fcca31b05654e0616761d2cb1b444f3dbecb5"
    },
    {
      "id": "ship/claimyour.gold/7b5541805722",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T23:41:05Z",
      "kind": "other",
      "title": "Purge Cloudflare cache after every deploy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "claimyour.gold sits behind Cloudflare per docs/runbook.md, but nothing\nin this pipeline ever told it to invalidate — every prior deploy could\nland cleanly on Cloud Run while real visitors kept seeing stale cached\npages indefinitely. Adds a purge-everything call after traffic shifts\nto the new revision, gated on CLOUDFLARE_API_TOKEN/CLOUDFLARE_ZONE_ID\nbeing configured (skips silently otherwise, never blocks the deploy).",
      "refs": {
        "commit": "7b5541805722fbdc61ea520d928b8faa1c6b8f7f"
      },
      "digest": "baf3ee5b6cc10c1f576ecaa58f7ac02caa8165326c60e549f40e3f34014d2a5c"
    },
    {
      "id": "ship/claimyour.gold/3e3573f30d34",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T22:16:16Z",
      "kind": "fix",
      "title": "Fix fabricated USD-equivalent rate on the claim page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The Core Hub redesign pass added a \"≈ \\$X USD equivalent\" line using\ngoldToReceive * 10 — a conversion rate invented on the spot (likely\ncopied from the design mockup's illustrative example numbers) with no\nbacking source anywhere in the codebase. Removed rather than replaced\nwith another guessed rate; no real gold-to-USD valuation exists in the\nservices layer to display here.",
      "refs": {
        "commit": "3e3573f30d34684a86f0633c8e2d34dbd024e12b"
      },
      "digest": "92d2d6de35e840eaee9555ab948c2d1de35dc3525df4be95aa4c00eb21e7e8b3"
    },
    {
      "id": "ship/claimyour.gold/fde25db5aa16",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T21:25:10Z",
      "kind": "infra",
      "title": "Auth/onboarding batch: align login, verify-email, success pages to token system",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replaces ad-hoc inline hex/rgba colors and stock Tailwind status classes\n(red/amber/emerald) across /portal/login, /portal/verify-email, and\n/portal/success with the real black-gold token system (--gold family,\n--danger-urgency, --success, --bg-2/--bg-elevated). Adds shakeX to the\nlogin error banner (matching the established spread-tuple pattern) and a\ncelebrate spring on the success page's checkmark reveal. Presentation-only\n— no changes to auth logic, data fetching, or API contracts.",
      "refs": {
        "commit": "fde25db5aa161f5123c7213dd74a91aa4e0ec7cb"
      },
      "digest": "a98ced64aeecba4806f917d33e58e93da62d6ddcecec9ccc384f80e30f2461d4"
    },
    {
      "id": "ship/claimyour.gold/776ea7bfa440",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T21:13:32Z",
      "kind": "other",
      "title": "Portal Personal & Utility group: token pass on profile, recap, power-user tools",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replaces hardcoded hex/rgba colors with real design tokens across\nprofile, weekly recap (now a \"Flashy Wrapped\" moment using\n--prestige-purple), analytics/kfactor/creator-dashboard/developer, world,\nand ar-filter. Presentation-layer only — no data fetching, API, or\nbusiness logic changes.",
      "refs": {
        "commit": "776ea7bfa440514e26035b5d407ecf7702e31114"
      },
      "digest": "b1a0227a730a1c99d045343bb8453a929916f2f8b3bbfaf205eb21abaaff7858"
    },
    {
      "id": "ship/claimyour.gold/8a90ac378354",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T20:57:07Z",
      "kind": "other",
      "title": "Redesign Social & Competitive portal pages to the black-gold token system",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Applies Section 4 of the portal redesign brief to leaderboard/crew/war/\nprestige/referral surfaces: rivals page rebuilt from raw inline rgba/hex\nstyling to real design tokens (--success, --danger-urgency, --gold family)\nwith framer-motion presets from src/lib/motion.ts; crew and crew/war pages\ngiven the same token + motion treatment; dynasty/empire prestige pages now\nread as distinctly above the normal ladder via --prestige-purple instead of\nanother gold card; live-leaderboard and crew/[crewId] residual stock\nTailwind colors (yellow/emerald/red/sky/orange) swapped for semantic\ntokens; refer page milestone ladder (5/10/25/50/100/250/500/1000) wrapped\nin staggerContainer for legible, motion-appropriate entrance. Presentation\nlayer only — no data fetching, API contracts, or business logic changed.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "8a90ac3783547063c718ee27c6750fd4444fc0e6"
      },
      "digest": "170a9f025b78f393b28290ded1c4e0bef0146f14ae2a3222e516b40ec195ca51"
    },
    {
      "id": "ship/claimyour.gold/5bbd32255cb2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T20:20:04Z",
      "kind": "other",
      "title": "Redesign Engagement portal pages to the black-gold token system",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Applies the Portal Engagement design brief to quests, badges, duel,\nbounty, raids, challenges, bomb, vault, and shop pages: replaces\nad-hoc inline rgba/hex colors with real design tokens (--gold family,\n--civic-teal, --danger-urgency, --prestige-purple, --success), adds\nframer-motion entrance/stagger/celebration/shakeX using the shared\nmotion.ts presets, and adds a live 60-second urgency countdown to the\nGold Bomb share flow plus a loading skeleton to the Vault page.\nPresentation-layer only — no data fetching or API contract changes.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "5bbd32255cb2840580ed3834adf1b8ac456e25a6"
      },
      "digest": "8035c51c33fac60f9f17c1c9abbbc5c983feb716c7305927cfd1782b140fca50"
    },
    {
      "id": "ship/claimyour.gold/93c5599c3e58",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T20:13:13Z",
      "kind": "other",
      "title": "Phase 2: brand-sponsored gated Academy tracks (Learn-to-Earn vision)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds sponsorClientId + gatedRewardOfferId to AcademyTrack (both nullable\n— unsponsored tracks are entirely unaffected) and a new\nAcademyTrackRewardUnlock model recording which learners have unlocked a\nsponsored track's gated RewardOffer.\n\ncheckAndIssueCertificate now, on a sponsored track's completion:\n  - debits the sponsor Client's Gold wallet for the track's goldReward\n    via clientGoldWalletService (same debit() used for QUEST_SPONSORSHIP\n    today, new reason TRACK_COMPLETION_SPONSORSHIP)\n  - upserts an AcademyTrackRewardUnlock row when the track has a gated\n    reward offer\n\nThe sponsor debit is wrapped in try/catch and logged on failure rather\nthan thrown — a sponsor's depleted funding pool must never block a\nlearner's already-issued certificate and gold credit.\n\n5 new tests covering: sponsor debit fires with the right args, gated\nreward unlock upserts correctly, unsponsored tracks never touch the\nclient wallet, and a failing sponsor debit doesn't fail certificate\nissuance. All 23 tests in academyService.test.ts pass; verified\nclientGoldWalletService.test.ts (9 tests) unaffected.",
      "refs": {
        "commit": "93c5599c3e58d935350bd8bf39c9038b5d78d1c7"
      },
      "digest": "d20af6b385afd86a6d66a1a2b3033c90416306dba5676eadaac3c40416ffadc8"
    },
    {
      "id": "ship/claimyour.gold/2614b8a1fccb",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T20:05:04Z",
      "kind": "infra",
      "title": "Rename /academy/blog to /academy/learn, fix hardcoded link/domain bugs",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Phase 1 of the Flashy Academy vision roadmap: /learn is the canonical\ncontent root going forward (absorbing the upcoming Learn-article\nmigration too). Also fixes two real bugs found while investigating the\nugly flashy.academy/academy/blog URL complaint:\n\n- Internal links were hardcoded to /academy/blog/... instead of a\n  relative path, so clicking through actually navigated to the doubled\n  URL even though a direct visit to flashy.academy/blog already routed\n  correctly via the middleware's transparent hostname rewrite.\n- The blog pages' OG/JSON-LD canonical URLs pointed at flashygold.com\n  instead of flashy.academy.\n\nAdded a permanent redirect from the old /academy/blog paths so\nexisting links and search indexing aren't broken.",
      "refs": {
        "commit": "2614b8a1fccb947b6e0b5bf458b1bcef2fe2f857"
      },
      "digest": "79989aa23df34af49a08c65b7949a4d8773e0bc36a2ac182036066a5931486ed"
    },
    {
      "id": "ship/claimyour.gold/acb8654d909e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T19:54:50Z",
      "kind": "other",
      "title": "Redesign Core Hub portal pages to the black-gold token system",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- claim/[clientId]: full redesign to match the Core Hub mockup — icon\n  avatar, Gold Points balance card, conversion arrow, gradient \"you'll\n  receive\" panel, gradient claim CTA, and a token/motion-driven confirm\n  modal (framer-motion fadeUp/scaleIn/spring presets, CSS custom\n  properties instead of raw hex/rgba).\n- wallet: replaced hardcoded hex/rgba inline styles with --gold/--line/\n  --success/--danger-urgency/--civic-teal tokens, .glass/.eyebrow/\n  .ink-gold utility classes, and fadeUp/staggerContainer motion presets.\n- dashboard, redeem, orders: brand-voice copy fixes (Flashy Gold vs\n  Gold Points vs GOLD, no \"cash\" in redeem OG/meta copy).\n\nPresentation-layer only — no data fetching, API, or business logic\nchanges.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "acb8654d909ef4e386e4516820317b86f655ae1d"
      },
      "digest": "cefd23f567cf63a57b54dc89f139a488ade1ccec131d0a2bbe72577062f59e39"
    },
    {
      "id": "ship/claimyour.gold/a990ba20d81a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T16:43:12Z",
      "kind": "feature",
      "title": "Merge heartbeat wiring into main",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "# Conflicts:\n#\t.github/workflows/_deploy.yml",
      "refs": {
        "commit": "a990ba20d81ab9485fe9a00dc8db1d71e0335585"
      },
      "digest": "06ae097e1af00ef7bc1462102a4e924a2996416ba957bd2ada63bf6ef7ac088f"
    },
    {
      "id": "ship/claimyour.gold/49fa6e5c8d09",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T11:59:44Z",
      "kind": "other",
      "title": "Super Admin analytics: shared DataTable + AnalyticsPageHeader components",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Phase B of the design rollout. Adds src/components/admin/DataTable.tsx\n(typed column defs + row data, owns chrome/loading/empty states only) and\nAnalyticsPageHeader.tsx, then migrates 16 analytics pages off their\nduplicated header/table markup onto the shared components. Presentation\nlayer only — no data fetching or business logic changed.",
      "refs": {
        "commit": "49fa6e5c8d09ac8e434d49ce7dd825805540406d"
      },
      "digest": "918d7ff0ea3d91377b251bc18b2613f94bd161726db9dd3c8a2e187b00e7a90b"
    },
    {
      "id": "ship/claimyour.gold/1cb21fd29625",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T11:32:02Z",
      "kind": "feature",
      "title": "Phase 3.6 pilot: report academy engagement to flashyos's cross-org Engagement Bus",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The hunter-engagement bridge already receives academy_module_passed and\nacademy_certificate_earned from flashy-academy. Wires a hashed (never\nraw), fire-and-forget report of those two activities into flashyos's\nEngagement Bus as NETWORK-visible events — the first real signal that\nbus has carried since it shipped. Silent no-op until FLASHYOS_*/\nNETWORK_BUS_HASH_KEY env vars are provisioned.",
      "refs": {
        "commit": "1cb21fd29625262e98445f12577573516ff3ae7a"
      },
      "digest": "614d4a79b781a1e709fd1cca4b939f997a73039847414d7024054b2e6943a51d"
    },
    {
      "id": "ship/claimyour.gold/16d7090b4d6f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T03:32:29Z",
      "kind": "infra",
      "title": "Migrate remaining local SectionLabel definitions to shared admin StatCard component",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Removes 5 duplicated `SectionLabel` reimplementations in the analytics\nsuper-admin pages (events, quests, quests/[slug], challenges,\nchallenges/[slug]) in favor of the shared one in\nsrc/components/admin/StatCard.tsx. viral-analytics/page.tsx was left\nalone: its local KpiCard uses fully custom inline-style dark theming\nthat the shared Tailwind-based component doesn't support.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "16d7090b4d6f0d5c8abd749ebf69ffde4b46c3c6"
      },
      "digest": "6df9ca07bd34d1a57ed0fc9e04f4d92d471d0a02140dbd6473d2613d42adf41e"
    },
    {
      "id": "ship/claimyour.gold/94118b880874",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T03:23:23Z",
      "kind": "infra",
      "title": "Client Portal: extract page components for customers/redemptions/transactions",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Breaks up three monolithic single-file pages into colocated\nFilterBar/Table/Pagination/PageHeader components, and normalizes the\nredemptions status-badge palette to match the customers section's\nestablished yellow/emerald/red convention. Pure presentation refactor —\nno data fetching, API contracts, or business logic changed.",
      "refs": {
        "commit": "94118b880874c803ac2b6c9020f06ba0b2bf219a"
      },
      "digest": "fc0fe4e33f5b7faccf64ca7d9a174edd669637d7b361033a22ce0d85a018efca"
    },
    {
      "id": "ship/claimyour.gold/b4953679019f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T01:52:56Z",
      "kind": "fix",
      "title": "Fix dev deploys failing to seed ADMIN_KEY secret",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Targeted terraform applies (used for routine dev app deploys) only touch\nthe Cloud Run service resources, so the ADMIN_KEY secret shell that a full\napply would create via Terraform never gets provisioned in dev. The seed\nstep now creates the secret if it doesn't exist before adding a version.",
      "refs": {
        "commit": "b4953679019fb382ef2433b1f40a0ae14be04c07"
      },
      "digest": "4430d8a207b7098ae8290a8001aaf451eed64550bfbbed519d0d04511a4653ef"
    },
    {
      "id": "ship/claimyour.gold/c3e404ea7b52",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T01:21:56Z",
      "kind": "infra",
      "title": "Ops/FlashyOS: migrate hardcoded hex backgrounds to real design tokens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Per the back-office brief, Ops/FlashyOS was the one surface with a\ngenuine token-system problem — every page hand-rolled raw inline hex\n(#0a0806, #0d0b08, #080603, #f5c547, etc.) approximating the real\n--bg-elevated/--bg-2/--gold-* tokens instead of referencing them, so\nany future brand color adjustment would silently miss this surface.\nSwapped all 15 affected files' inline style hex literals for the\nactual CSS custom properties. No layout/component changes — this was\na token-reference migration only, sequenced last per the brief since\nOps has zero external-facing urgency.",
      "refs": {
        "commit": "c3e404ea7b528e5aa3e80c8a7b0131e31bc24153"
      },
      "digest": "583e6dd5e9da95e66ba87a50e29bf9227ca13ad45a0d29ba5904edef5c963dc3"
    },
    {
      "id": "ship/claimyour.gold/3bad6f36bbe9",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T01:18:27Z",
      "kind": "other",
      "title": "Partner Portal: real gold token instead of stock Tailwind yellow-400",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Per the back-office design brief, Partner Portal is already the\ncleanest of the back-office surfaces and only needed a light-touch\npass. Swapped every yellow-400/500 (accent dividers, sparkline,\nfunnel bar, timeline dot, gold-economy stats) for the real #f5c547\ngold hex — same drift pattern as Academy's round 1. Left the\nsemantically-distinct amber-400 (a separate warning tier, not brand\ndrift) and red-500 untouched. No layout/IA changes — that's flagged\nas future work for Client Portal/Super Admin per the brief, not\nattempted here.",
      "refs": {
        "commit": "3bad6f36bbe9de966bc3c1ae791a4f2351001f20"
      },
      "digest": "87852ab306de09ec6677e7f2819530f66592da42762e89780786ccb53b850843"
    },
    {
      "id": "ship/claimyour.gold/5f28da9693ce",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T00:53:37Z",
      "kind": "infra",
      "title": "Academy round 2: replace remaining yellow-100/600/800 badge/link colors",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Second sweep found light-mode-style bg-yellow-100/text-yellow-800\nbadge pills (Alumni, Jobs) and a yellow-600 link (Catalogue) that\nclash against Academy's inherited dark portal shell — swapped to the\nsame gold-token badge convention used elsewhere. Badge page's award\ncircle also moved off bg-yellow-100 onto the real gold radial\ngradient. Content and data untouched.",
      "refs": {
        "commit": "5f28da9693ce899120a60d76922b9977200ee29f"
      },
      "digest": "ab763c0dd7c1d23392bc7597c0a2d0876997cdddbf3cf197fce4e93ff770394d"
    },
    {
      "id": "ship/claimyour.gold/2eab13a3473f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-10T00:49:52Z",
      "kind": "other",
      "title": "Academy round 1: real gold tokens instead of stock Tailwind yellow",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Per the design handoff's Academy brief: Academy already inherits the\ncorrect architecture (same root layout, same fonts, same semantic\ntokens) — the actual drift was hardcoded yellow-400/yellow-500 in\nbadge/verify/jobs pages, and fully unstyled raw\nstyle={{fontFamily:'sans-serif'}} shells on Events (list + detail) and\nthe guides/for-audience SEO template families.\n\n- badge/[token], verify/[certId], jobs: swapped bg-yellow-* for the\n  real gold gradient/token\n- events (list + detail): full shell rewrite onto the shared\n  dark/gold portal tokens\n- guides/[slug], for/[trackSlug]/[audience]: SEO template families\n  restyled once each (per the brief's guidance not to redesign every\n  instance)\n\nAdmin/* and embed/* explicitly out of scope per the brief. Content,\nSchema.org JSON-LD, and all data fetching untouched.",
      "refs": {
        "commit": "2eab13a3473fca8f544370f64a0293fc37a8b4de"
      },
      "digest": "0f1bb4898f47fa64979eb844b5a1793da7d9d32c0a7e6b073995afd49496958a"
    },
    {
      "id": "ship/claimyour.gold/0f4f3f874c9e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T21:32:39Z",
      "kind": "feature",
      "title": "Merge commit '69cc82a7' into production-merge-4",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "0f4f3f874c9e3c14730537a8bf85cadf01143989"
      },
      "digest": "339fda467d57e104dbb755707a722f167b7d8e3e6cf9c44e1887ed28b2bf539a"
    },
    {
      "id": "ship/claimyour.gold/700f7680e148",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T19:10:24Z",
      "kind": "fix",
      "title": "Fix ADMIN_KEY seed step silently skipping on every deploy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "deploy-prod.yml and deploy-dev.yml call the reusable _deploy.yml\nworkflow via `uses:` but never passed secrets to it — reusable\nworkflows never inherit the caller's secrets automatically. That\nmeant _deploy.yml's `secrets.ADMIN_KEY_VALUE` reference was always\nempty regardless of where ADMIN_KEY_VALUE was actually set (repo\nsecret, prod environment secret, anywhere), so the \"Seed ADMIN_KEY\"\nstep's `if: env.ADMIN_KEY_VALUE != ''` guard skipped every single\ntime — confirmed across three consecutive live deploy runs today,\nafter ruling out secret scoping and Terraform's part of the pipeline.\n\nAdds `secrets: inherit` to both callers.",
      "refs": {
        "commit": "700f7680e148e6ec736f7878024c7755d5152063"
      },
      "digest": "d30ca76394f0b0b70f3f204fddc6290fecd587f5fb5b9602510a2d4619a68d72"
    },
    {
      "id": "ship/claimyour.gold/cf626455f7c2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T17:51:28Z",
      "kind": "other",
      "title": "Batch: restyle Crew profile hero + Settings headers with gold tokens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- crew/[crewId]: hero card gets the gold-gradient treatment matching\n  every other profile/hub page\n- Settings (Language, WhatsApp): headers use ink-gold for consistency\n\nFull portal-tree sweep (grep for gold tokens vs border-border-only)\nnow shows the entire /portal/* tree is on-brand except Academy, which\nis a separate subsystem with its own design language — flagging that\nas a distinct scope decision rather than assuming it needs the same\ntreatment.",
      "refs": {
        "commit": "cf626455f7c2f60868ef116c7a7ea0262643c46f"
      },
      "digest": "e31a669464cdca67a62568c0825baf9f3b5ef3dcb937d0643908104ff1529801"
    },
    {
      "id": "ship/claimyour.gold/d54ec6e0f509",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T17:46:56Z",
      "kind": "other",
      "title": "Restyle K-Factor page header/hero card with gold tokens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "d54ec6e0f509c7b32f873733b4568351a7661b6a"
      },
      "digest": "528ad7ab3010225610a8d0036a37bba00763fdee4b0dd8f0f99e1b4a1944be5b"
    },
    {
      "id": "ship/claimyour.gold/e7414c1333c4",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T17:43:27Z",
      "kind": "other",
      "title": "Batch: restyle Duel, Raids, Challenges with gold/danger tokens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- DuelHub: live wager card gets gold-tinted gradient background and a\n  \"watching\" live pulse indicator, matching the mockup's duel treatment\n- Raids: gold-gradient hero header (matching Dashboard/City/Quests),\n  boss-raid cards move off generic orange-500 onto --danger-urgency\n  tokens\n- Challenges: header uses ink-gold + --danger-urgency streak badge\n\nAudited Wallet/Quests/Leaderboard/Redeem/Refer first via a grep sweep\nfor border-border-only (no gold token) pages — those four were\nalready on-brand, no changes needed. Business logic untouched\nthroughout.",
      "refs": {
        "commit": "e7414c1333c4b7b743659a25ae150a09b93340c4"
      },
      "digest": "22bc5718e9137e816e241b5b062190226616fa569fdd21da1c3de4c2574cec58"
    },
    {
      "id": "ship/claimyour.gold/79052bdb5097",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T16:34:38Z",
      "kind": "infra",
      "title": "retrigger Deploy dev after transient Terraform provider registry 504",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "79052bdb5097078ac99c4cf4f35ec0cbc93a0886"
      },
      "digest": "52538086e291916bbd58041b9d83a177a3319076ef6c52f3d8d4380e28d355fb"
    },
    {
      "id": "ship/claimyour.gold/d1e8bbab3994",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T15:49:48Z",
      "kind": "fix",
      "title": "Revert invalid secrets-in-if syntax that broke every deploy workflow",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The previous commit's if: \\${{ secrets.ADMIN_KEY_VALUE != '' }} is not\nvalid inside a step if: for a workflow_call-triggered reusable\nworkflow — it caused a hard startup failure (0 jobs run) on every\nworkflow that calls _deploy.yml (CI, Deploy dev, Deploy prod alike),\nblocking all deploys entirely. Reverted to the env-context form, which\nis the officially supported pattern for referencing a step's own env\nin that same step's if:.",
      "refs": {
        "commit": "d1e8bbab399494210b4f1be114177b1010136f54"
      },
      "digest": "91ad9337f7428c50317dbe16118ad937acce9e7ddd829bf1c80532567ea128a6"
    },
    {
      "id": "ship/claimyour.gold/45682e50f5c4",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T15:41:16Z",
      "kind": "fix",
      "title": "Fix Seed ADMIN_KEY step condition referencing secrets context directly",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A step's own env: block isn't visible to that step's if: condition in\nGitHub Actions, so 'if: env.ADMIN_KEY_VALUE != ' always evaluated\nfalse and the step silently skipped (confirmed: Terraform apply did\ncreate the ADMIN_KEY secret + IAM binding + placeholder correctly,\nbut the value-seeding step never ran). Reference secrets.ADMIN_KEY_VALUE\ndirectly in the if: instead.",
      "refs": {
        "commit": "45682e50f5c4c2125f448337ee33e25178ff6ebe"
      },
      "digest": "abba2413123d68e70362a6f1780d867f5127b3a751e84646b304b47dae45b2f4"
    },
    {
      "id": "ship/claimyour.gold/e912aa78ab5f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T15:31:07Z",
      "kind": "infra",
      "title": "trigger redeploy to seed ADMIN_KEY via GitHub secret (v4)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "e912aa78ab5f26f9482986a43132af99d5337d39"
      },
      "digest": "119d674fea12135f53c31c49e71ed0475f30765206711a706bb20937c5a9e900"
    },
    {
      "id": "ship/claimyour.gold/8773f5fd44e6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T15:23:13Z",
      "kind": "other",
      "title": "Manage ADMIN_KEY as a Terraform-declared secret, seeded via GitHub secret",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Three attempts to add ADMIN_KEY through the GCS-bucket secrets.json file\ndidn't take — Terraform apply logs confirmed 0 resources added each time,\nmeaning the edited file never actually reached Terraform's read of the\nbucket object. Rather than keep retrying the same manual upload, this\ndeclares ADMIN_KEY directly in Terraform (so it doesn't depend on the\nJSON file at all) and seeds its value via `gcloud secrets versions add`\nin the deploy workflow, matching the placeholder pattern the secrets\nmodule already documents for operator-managed values.\n\nRequires a GitHub Actions secret named ADMIN_KEY_VALUE (repo or prod\nenvironment scope) — the step no-ops safely if it isn't set.",
      "refs": {
        "commit": "8773f5fd44e6b371f89351ffead18a642f81dc77"
      },
      "digest": "562a3fedce9af1a6df9cc171fc79f30c0ebff14ba2bd415128260f46f8d9c5c6"
    },
    {
      "id": "ship/claimyour.gold/ee1dc276b45b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T15:12:05Z",
      "kind": "other",
      "title": "Force revision uniqueness via DEPLOY_SHA env var — flashy-app stuck on one revision",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "flashy-worker gets a fresh revision every prod deploy with just\n--revision-suffix, but flashy-app has kept serving the same revision\n(flashy-app-00676-vnh) across 5+ consecutive deploys with different\nimage tags and an explicit new suffix requested each time — Cloud Run\nis treating the update as a no-op at the spec level for that service\nspecifically. Adding --update-env-vars=DEPLOY_SHA=<short-sha> forces a\ngenuine config diff every deploy (env vars are part of the revision\nspec), which should make that no-op path unreachable regardless of\nits root cause. DEPLOY_SHA isn't read by the app.",
      "refs": {
        "commit": "ee1dc276b45bd302470ea7603f34210495f0045c"
      },
      "digest": "436307f20d8f63ee4856f67e2119f01b88ab3a808e0b46c68de02f77ae8021ed"
    },
    {
      "id": "ship/claimyour.gold/c4c507a3c8ef",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T14:12:46Z",
      "kind": "other",
      "title": "Restyle Wallet balance card to match v5 design handoff",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "FG balance now uses the mockup's gradient figure treatment (matching\nDashboard/City Treasury) with Redeem/Send-to-friend CTAs linking to\nthe existing /portal/redeem and /portal/gift routes. Data fetching\n(portfolio + transactions API calls, loading/empty states) unchanged.",
      "refs": {
        "commit": "c4c507a3c8ef8b3547a34a40c47c22585b974400"
      },
      "digest": "78ce3679b03635424d215eda5da5a69b8a712a82138f14a2b1286f72883294ad"
    },
    {
      "id": "ship/claimyour.gold/42a45b447e0a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T13:55:04Z",
      "kind": "other",
      "title": "Restyle City Council/Treasury/Rivalry with civic teal + gold tokens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Continues the City hub's visual pass across its three sub-pages:\nCouncil seats and Treasury contributions use --civic-teal-accent,\nTreasury's total pool card gets the mockup's gold-gradient card\ntreatment, and the Rivalry live-war card moves off generic red onto\ncivic teal (a civic war reading distinctly from a crew war, per the\nhandoff's stated intent). All data fetching, session/redirect guards,\nand business logic are untouched.",
      "refs": {
        "commit": "42a45b447e0ab61ff5a292cc6e43710db5a3ef88"
      },
      "digest": "62d022f88afaa5a8ab43d8d48cdb4d492e8b62092352ed5298d79a8abe8d5fd0"
    },
    {
      "id": "ship/claimyour.gold/9eb8e5fe6a25",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T13:49:36Z",
      "kind": "other",
      "title": "Restyle City hub with civic teal accent per v5 design handoff",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Wraps the header in the mockup's teal gradient banner with the same\nsubtle grid-pattern overlay, retints the Week Score stat and the\nactive-rivalry card to the new --civic-teal-accent token instead of\ngeneric primary/red — City is meant to read visually distinct from\nCrew, per the handoff's stated intent. All data/logic (profile, stats,\nactiveWar, council) is unchanged.",
      "refs": {
        "commit": "9eb8e5fe6a25bb3d0ab42c95e869b586e1ebdeaa"
      },
      "digest": "4bde131abe467005a522d0b081591e97bb44e6fd91eca91e1038cce3f6fa1d0f"
    },
    {
      "id": "ship/claimyour.gold/faf8b511aba8",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T13:37:05Z",
      "kind": "infra",
      "title": "retrigger Deploy dev after transient GCP auth failure on 21c0571d",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "faf8b511aba8feeddb3af6dca343b6dca16519cb"
      },
      "digest": "f52b68b996a0d9163460429418f1939c72f25eab7671e5c4fd3863127c794d53"
    },
    {
      "id": "ship/claimyour.gold/21c0571dd31a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T13:16:12Z",
      "kind": "other",
      "title": "Restyle Portal Dashboard hero to match v5 design handoff",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds the missing semantic tokens flagged by the package's own Brand &\nTheme Fidelity Audit (success, danger-urgency, civic-teal, prestige-\npurple) to globals.css, then rebuilds the FG balance hero on the\ncustomer dashboard to match Portal Dashboard.dc.html: larger gradient\nfigure with a lightning-bolt badge, a real weekly-earned delta pill\n(sourced from the already-fetched playerRecapService data, previously\nunused on this page), and primary/secondary CTA buttons. No USD\nequivalent line — there's no real conversion rate in the codebase to\nback it, so it's omitted rather than fabricated. Everything else on\nthe page (partner cards, streak widget, onboarding rails, badges) is\nunchanged.",
      "refs": {
        "commit": "21c0571dd31a17341708b8c56c80fd9946d72358"
      },
      "digest": "d868d19e18932fae9c2d01ded13a0dedf2222ac4f7720b18f8c95ae09f0139ac"
    },
    {
      "id": "ship/claimyour.gold/480f5deb10d6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T13:05:01Z",
      "kind": "infra",
      "title": "retrigger CI/Deploy dev after cancelled runner hang on 4867e1c9",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "480f5deb10d6ddb431461f5fb76f73f5b8c788b8"
      },
      "digest": "9c09914aa23dae66fbe086b76989cbae5e28161ee1ae68728f576528df967c90"
    },
    {
      "id": "ship/claimyour.gold/4867e1c913fb",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T12:37:52Z",
      "kind": "other",
      "title": "Force unique Cloud Run revision names via --revision-suffix",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "flashy-app has been reporting the identical revision name across the\nlast 3 production deploys despite each one shipping a different image\ntag — Cloud Run was silently no-opping the rollout instead of cutting\nover to the new code. Pinning --revision-suffix to the deploying\ncommit's short SHA forces a genuinely new, unique revision every time.",
      "refs": {
        "commit": "4867e1c913fb3ed83e0a6fde63bee39f7b30a33b"
      },
      "digest": "f0d68a9d8e8585173dbfe371b3ca593f3b28dbefb6d5067ceb9176135a54f678"
    },
    {
      "id": "ship/claimyour.gold/92e5e61360f3",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-09T00:14:25Z",
      "kind": "feature",
      "title": "Build /security and /legal/{privacy,terms,cookies} — first slice of the v5 design handoff",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replaces the four \"Coming soon\" stub pages with the Trust & Legal Pages\ndesign: /security as a fintech-trust-standard page (encryption/account\nsafety/balance-integrity cards, compliance posture, report-a-vulnerability\nCTA) and a shared LegalDocLayout template (sticky TOC, anchored sections,\n~68ch reading measure) for the three legal docs.\n\nPer the design brief's explicit instruction, no legal/compliance copy is\nfabricated — every substantive block renders a \"[pending counsel\nreview]\" placeholder instead of invented text. Section structures for\nterms/cookies are standard boilerplate structure (headings only, e.g.\n\"Prohibited conduct\", \"Third-party cookies\") since only privacy's TOC\nwas specified in the design file.",
      "refs": {
        "commit": "92e5e61360f37287ad8c3c8ceb55d25678606353"
      },
      "digest": "126aecee47e970a5c752e18ae1571ffb637977bd729d71df79a923848ec9da1d"
    },
    {
      "id": "ship/claimyour.gold/9b5087852491",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T22:37:52Z",
      "kind": "infra",
      "title": "Pin Dockerfile's npm bootstrap to npm@11 instead of npm@latest",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "npm published a 12.x release requiring Node >=22, which silently broke\nevery Docker build on this repo's node:20-alpine base the moment it\nbecame `latest` — this is what's been failing Deploy dev on the last few\ncommits (Build and push image step, EBADENGINE). The original comment\nalready said \"Fixed in npm 11\" — pin to that major instead of floating\non @latest so a future npm major bump can't break the build again.",
      "refs": {
        "commit": "9b5087852491eb3f2c90efa33e3e674ea6c9e40c"
      },
      "digest": "6ca8dc05adf7dad23f956c1923ada7c32d15f6fbaa959aac716dd73d5143b915"
    },
    {
      "id": "ship/claimyour.gold/6435d5eb26ea",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T22:33:51Z",
      "kind": "fix",
      "title": "Fix Bump revisions step deploying the already-live image instead of the freshly-built one",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The step read spec.template.spec.containers[0].image from the currently\ndeployed service and redeployed that same value — a guaranteed no-op.\nCombined with every recent prod deploy logging \"No new flashy-app\nrevision this deploy (infra-only change)\", this is the likely reason\nproduction hasn't been visibly serving new code despite deploys\nreporting success. Now uses the image URI resolved earlier in the same\nrun (steps.img.outputs.uri) so this step can actually force a rollout if\nterraform apply's scoped plan didn't already do it.",
      "refs": {
        "commit": "6435d5eb26ea61ee7aec7f052702f2b5ffcc59ea"
      },
      "digest": "9e048e524c170ab2b11726a45ffd38b46deff277fc1859be6583c1669ad0aad0"
    },
    {
      "id": "ship/claimyour.gold/27477e24390b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T21:35:56Z",
      "kind": "infra",
      "title": "Remove accidentally-committed .vercel/ local dev artifact, gitignore it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Not a secret (just project/org IDs), but this repo deploys via GCP\nCloud Run per the Dockerfile, not Vercel — this was leaked from\nsomeone's local `vercel link` and shouldn't be tracked.",
      "refs": {
        "commit": "27477e24390b56173825897f2be8a5493144fe25"
      },
      "digest": "cecd31e411eb2e8439029d433ccfa8ff5aa3a1fffb88f7b687677e01f98ef959"
    },
    {
      "id": "ship/claimyour.gold/f1e0bf9bd035",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T21:25:29Z",
      "kind": "infra",
      "title": "Complete icon-system rollout: replace 39 remaining RankMedal/TierGem emoji occurrences across 32 files",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Finishes the icon-system rollout started by design/uiux — sweeps the\nremaining leaderboard/ranking surfaces (portal, public, academy,\ntelegram mini-app, embed) that still used inline 🥇🥈🥉/#N ternaries or\nMEDAL/MEDALS lookup constants, replacing them with <RankMedal rank={n} />,\nplus two Academy civilization-age emoji maps replaced with <TierGem />.\n\nLeft decorative and out-of-scope emoji untouched throughout — creator\ntiers, hunter divisions, war/duel status flourishes, streak shields, and\nbadge-rarity indicators without a real rarity value in scope were\ndeliberately not touched, since none map cleanly onto the icon-system's\n5 defined components (TierGem/CrewShield/CitySeal/RankMedal/\nAchievementMedallion). OG-image route handlers under src/app/api/og/**\nwere excluded entirely — they render via Satori/edge runtime and can't\nuse the 'use client' + Framer Motion icon-system components.",
      "refs": {
        "commit": "f1e0bf9bd0356fa102fc9720b4d49bb2a75d4d1a"
      },
      "digest": "ba0caec06f5663ccda06ecbe14373d41f049a1b125bec2be51115b2f2b489acd"
    },
    {
      "id": "ship/claimyour.gold/cfb2e2f057ba",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T20:22:41Z",
      "kind": "feature",
      "title": "Merge wren/first-conversion: X-track conversion funnel persistence, Y-track activation roadmap, W-track cohort velocity/send-guard/quest-seq",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Restores the Y11 hunter-to-champion persona transition on 7-day streak\nmilestone (dropped by a stale barrel-vs-monolith conflict in\nstreakClaimService) and points the dashboard's starter-quest reward\nlookup through questService instead of direct Prisma access. Fixes three\npre-existing test/source mismatches in wren's own history where a later\ncommit updated activationRecoveryService/telegramDripQueue to their real\nmulti-step behavior without updating the corresponding tests, and adds a\ndeterministic mock for the activation-window A/B test in\nactivationService tests.",
      "refs": {
        "commit": "cfb2e2f057ba144ce46fdfbedfa3f675d8e82310"
      },
      "digest": "a91e6c3441e178385d4ba396d9fbd3c69cd4ca0a0a67e8a13fb47dce99fea93d"
    },
    {
      "id": "ship/claimyour.gold/25d2843fbc28",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T19:43:42Z",
      "kind": "feature",
      "title": "Merge nexus/network-effects-engineer: S7 platform revenue, S6-03 grudge rematch DMs, D7 re-entry banner, S8-02 crew critical mass wiring",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Restores several real features that nexus's branch added on top of\nservice files later split by the audit-hygiene pass: the CIVI-06 alliance\nkindling bonus in crewWarActionService, the S6-03 sendGrudgeRematchDMs\nwiring in crewWarResolutionService (the function itself already lived in\ngrudgeMatchService), and the S8-02 crew-critical-mass announcement plus\nR09 narrative event trigger in crewMutationService's joinCrew. Adds the\nPlatformRevenue model and D7 re-entry banner on the portal dashboard.",
      "refs": {
        "commit": "25d2843fbc284fbad586f8768614b3664061c992"
      },
      "digest": "2be42ddbd5514af6f7e4fe6e60eb7ee1a6758cd3a0748a187674d13ad467b902"
    },
    {
      "id": "ship/claimyour.gold/77aa4467bcb5",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T19:27:14Z",
      "kind": "feature",
      "title": "Merge design/uiux + atlas/big-data-analytics: chart components for churn/cohort/gold-ledger/viral-growth analytics pages, restore churn+LTV ",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds ChurnRiskBandChart, CohortRetentionTrendChart, GoldLedgerTrendChart,\nand ViralGrowthTrendChart to their respective super-admin analytics pages.\nRestores churnRiskScore/lifetimeGoldEarned/lifetimeGoldRedeemed fields on\ngetUserProfile that atlas's branch had added to the pre-decomposition\nanalyticsService monolith.",
      "refs": {
        "commit": "77aa4467bcb553c75ed0dd9c3e8cc6c12ed0f36a"
      },
      "digest": "c7c2e93fcb20953184023e44a8416dcaa7c30e4da7f104c1c888c2536ee5a011"
    },
    {
      "id": "ship/claimyour.gold/96e5bcb8e4fb",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T17:42:27Z",
      "kind": "fix",
      "title": "restore select fields dropped by post-rebase select-narrowing conflicts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "academyProgressService: submitQuizAttempt needs question.text/module.articleSlug\nfor wrongQuestions tracking; portfolioDashboardService: getDashboardCustomerData\nneeds customer.referralCode for the dashboard's referralCode field.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>",
      "refs": {
        "commit": "96e5bcb8e4fba392d05da1fd14e7d15dfda4ff43"
      },
      "digest": "df16b69df2454e607613f90253480707f155c92bbc0f6d2add170b2b706e0a8a"
    },
    {
      "id": "ship/claimyour.gold/581b95872a91",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T16:19:18Z",
      "kind": "feature",
      "title": "85 more service tests, 10 pages off direct Prisma, telegramNotify decomposition",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Test coverage (+85 tests, 5 new suites):\n- academyService: quiz attempts, certificates, progress tracking (18 tests)\n- featureFlagService: isEnabled, sync, getAll, setOverride with Redis (14 tests)\n- oracleBadgeService: award, idempotency, crew announcement (10 tests)\n- portalShareService: share rewards, block after 3rd share (6 tests)\n- duelSpectatorService: arena status, midpoint update, result broadcast (12 tests)\n- milestoneService, networkService, viralAuditService (+25 carried from prior batch)\n\nArchitecture — service layer (10 more pages off direct Prisma):\n- portal/dashboard → portfolioService.getDashboardCustomerData\n- portal/leaderboard → divisionService.getPreviousDivisionMembership\n- portal/redeem → walletService.getRedeemPageCustomer\n- portal/hunter/[username] → hunterProfileService.getHunterProfileOwner\n- bomb/upcoming/[scheduleId] → scheduledBombService.getBomberUsername\n- streak-death/[username] → hunterProfileService.getHunterForStreakDeathChallenge\n- gold-rush/live → goldRushService.getTopEarnersDuringRush\n- crews/[id] → publicCrewService.getCrewPageData\n- chain/[warcardId] → warCardService.getWarCardChainData\n- season/[id] → seasonService.getPublicSeasonLeaderboard\n\ntelegramNotify decomposition:\n- Extracted tournament notifications → src/lib/notify/tournament.ts (5736 → 5643 lines)\n\nCo-Authored-By: Claude <noreply@anthropic.com>\n\n# Conflicts:\n#\tsrc/app/(portal)/portal/dashboard/page.tsx\n#\tsrc/app/(portal)/portal/hunter/[username]/page.tsx\n#\tsrc/app/(portal)/portal/leaderboard/page.tsx\n#\tsrc/app/(portal)/portal/redeem/page.tsx\n#\tsrc/app/(public)/crews/[crewId]/page.tsx\n#\tsrc/app/(public)/season/[season]/page.tsx\n#\tsrc/services/goldRushService.ts\n#\tsrc/services/hunterProfileService.ts\n#\ttests/services/academyService.test.ts",
      "refs": {
        "commit": "581b95872a916f366f638a9cd90441927d8e46c4"
      },
      "digest": "da8ed044ba6135aa4bd67524cfb2a98f4cf5b422d7b8712606f89d1ce16cb067"
    },
    {
      "id": "ship/claimyour.gold/c46e8e21fa6b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T15:53:49Z",
      "kind": "feature",
      "title": "Merge atlas/big-data-analytics: job run-log tracking + activity stream wiring",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds JobRunLog model for cross-job freshness checks and wires the\nnewly-merged features (crew merger, time capsules, seasonal guild ranks)\ninto the unified activity stream.",
      "refs": {
        "commit": "c46e8e21fa6bea435598d832093c4c11c3dda60c"
      },
      "digest": "7014e47bee8cfb7885d35e22a636da9498f29838edb7c21e848d90160f99a112"
    },
    {
      "id": "ship/claimyour.gold/631b98c6a615",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T15:40:01Z",
      "kind": "feature",
      "title": "Merge claude/funny-noether-75ghqx: crew merger legacy bonus, seasonal guild ranks, per-capsule time delivery, marketing event calendar, reti",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Resolves competing-rewrite collisions with existing production code by\nrenaming/extracting the newer branch's version into sibling files\n(seasonalGuildRankService, UpcomingCalendarEvent) rather than replacing\nlive implementations. Combines complementary additions (crew merger\nlegacy bonus, per-capsule push delivery, AppError handling in telegram\nauth) directly into existing services. Drops 4 duplicate service/route\nsets that targeted an already-superseded schema shape.",
      "refs": {
        "commit": "631b98c6a615776d84a890b8b21512b6dafb19af"
      },
      "digest": "dd43f879bce2e1ef1dfbf2691d3090f5b5c170620ae4fa875ce97b805863db3f"
    },
    {
      "id": "ship/claimyour.gold/7578fb2d1672",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T15:11:47Z",
      "kind": "feature",
      "title": "Merge atlas/big-data-analytics: churn cluster cleanup, job dependency graph, push infra for analytics dashboards",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "# Conflicts:\n#\tprisma/schema.prisma",
      "refs": {
        "commit": "7578fb2d167279613877cde374cdf35aea658f59"
      },
      "digest": "acd66f4f70bbb1b81ab3cf02a940f0a1c9c36a53b8491464d5e711219688f1c7"
    },
    {
      "id": "ship/claimyour.gold/f72fe4d04476",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T15:10:28Z",
      "kind": "feature",
      "title": "Merge fix: read error.code from nested apiError() shape, not top-level",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "f72fe4d044764832863e3b72094ace09d10858a4"
      },
      "digest": "92aca298d4c7e9f3c80e0468f43368fbabceac6dad42c3f3dfc34e60fc5f38ba"
    },
    {
      "id": "ship/claimyour.gold/0f04fcba0048",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T15:10:17Z",
      "kind": "feature",
      "title": "Merge design/uiux: Auction House, Black Market, Trophy Vault, Hall of Fame/Legends, Creator Dashboard, notification settings",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "0f04fcba00485a1ded6ff174a170f14114d87e7e"
      },
      "digest": "e38d7f504c50216be3fe851d2d71c068046a5a647a50b74de070806574beb329"
    },
    {
      "id": "ship/claimyour.gold/6ac3c76237ea",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T13:38:50Z",
      "kind": "fix",
      "title": "Fix Next.js 15 async-params bug in portal showcase route",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Same recurring bug class as earlier this session — the hermes merge\nintroduced a route handler with the old synchronous params signature,\nwhich Next.js 15 requires as a Promise.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "6ac3c76237ea179dba6b664e156c073ecf364fbc"
      },
      "digest": "e06f15b3604c630f6187dd5cb43f785c0727bf2e899d91121a83ed32b559c19a"
    },
    {
      "id": "ship/claimyour.gold/25083a543038",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T13:32:25Z",
      "kind": "feature",
      "title": "Merge design/uiux: Airdrop/Daily Spin/Governor/Gift/Gift Card/Referral Receipt pages, war betting + tournament wiring, P2P gifting, spy netw",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "25083a543038dd80a1e6166991a2721ca14e88b0"
      },
      "digest": "73f4613173f1ab6bd4274298087c15704d342abe9c04f1170a19340e4ae97ee0"
    },
    {
      "id": "ship/claimyour.gold/453839bb47cd",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T13:22:50Z",
      "kind": "infra",
      "title": "verify CI/Actions runner recovery",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "453839bb47cde491bf4fed31aaed0bf48278a185"
      },
      "digest": "ee79d7ee6db0563b89054b9379bba9b8420a172fc26795d2c8089a28ef5dab6d"
    },
    {
      "id": "ship/claimyour.gold/5bb01294efe6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T07:16:45Z",
      "kind": "feature",
      "title": "Merge hermes/day-30-retention: R241-R340 retention batches — City Rituals through City Psychology & Obsession Loops",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "# Conflicts:\n#\tsrc/app/api/portal/bounty-board/route.ts\n#\tsrc/services/bountyBoardService.ts\n#\ttests/services/bountyBoardService.test.ts",
      "refs": {
        "commit": "5bb01294efe6179a4be650a5ffe55f0f7ef3abca"
      },
      "digest": "7390d9c5ba72a287400b2037c2d2f08a4e436f1cedf313552b817fd8701fa24c"
    },
    {
      "id": "ship/claimyour.gold/5bf223a8f676",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T07:03:40Z",
      "kind": "feature",
      "title": "Merge nova/viral-growth-activation: web push alerts, referral race widget, weekly recap OG image, flash event banner, public city pages, ema",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "# Conflicts:\n#\tsrc/services/socialProofService.ts\n#\ttests/jobs/ghostReactivationJob.test.ts",
      "refs": {
        "commit": "5bf223a8f6761e773578c4291fdf58b4062a753a"
      },
      "digest": "bdb3eee9db6e8452a0aab3e3cd3b198e057aee0ad5a41c4f62a5b3832b5e0867"
    },
    {
      "id": "ship/claimyour.gold/4a56986162d2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T06:57:51Z",
      "kind": "feature",
      "title": "Merge vega/first-conversion: dynamic bonus engine, intent scoring, quest difficulty ladder, viral share card, streak commitment, push gating",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "4a56986162d2325f1b001dcbd31fdfcd9ebe5739"
      },
      "digest": "88dcce0e655c581802b5b91596a4a12be884c572d56c367b2be6b9794fcb91b6"
    },
    {
      "id": "ship/claimyour.gold/334fdddb5ebd",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T06:52:29Z",
      "kind": "infra",
      "title": "Migrate all remaining inline <style> tags to globals.css (v3 Phase 7)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Closes the last follow-up from the v2 CSP fix: raw <style> JSX tags plus\nnonce-prop plumbing are fragile (easy for a future PR to drop the prop\nand silently reintroduce the CSP bug that broke the Home tab activity\nfeed). Extracted every remaining component's inline CSS into\nglobals.css with unique/scoped class names, removed the <style> tags,\nand dropped now-dead nonce props/params where verified unused. Pure\nrefactor — no visual or behavioral changes.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "334fdddb5ebd83e573c1930ee4a056e75c19a95f"
      },
      "digest": "80100d9836e0ac429bfc8f9dd627fee6d32e1b98971c0560a6af72b108e0537e"
    },
    {
      "id": "ship/claimyour.gold/7230ede786b5",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T06:19:00Z",
      "kind": "feature",
      "title": "Merge fix: remove dead persistChurnRiskProfiles landmine, index churnRiskScore",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "7230ede786b55ec13047b5a51a9683e5c71e9cf6"
      },
      "digest": "117be20d1c51f99ab8e656712140573b35815a11a581a15b63629b2adeb589d3"
    },
    {
      "id": "ship/claimyour.gold/9bd3f16bceab",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T06:18:52Z",
      "kind": "feature",
      "title": "Merge fix: dedupe World tab in mobile bottom nav",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "9bd3f16bceabcab988e32e7c8f0d5f14814e1ed8"
      },
      "digest": "d248f59e5fdc36e7cbf820f8c595ee4d3d921dd2d020bc5e4085270efad65804"
    },
    {
      "id": "ship/claimyour.gold/2224ee1281e4",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T05:42:27Z",
      "kind": "feature",
      "title": "Add flaky-test quarantine system (v3 Phase 6)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "At 977 suites / 9,091 tests, the biggest threat to deploy frequency is a\nred CI everyone's learned to re-run and ignore, not a missing gate.\ntests/quarantine.json lists known-flaky test files; jest.config.ts\nexcludes them from the blocking suite. scripts/quarantine-test.sh\nadd/remove/list manages entries. ci.yml runs quarantined tests in a\nnon-blocking step so they stay visible without failing builds, and the\nnew quarantine-triage.yml posts a weekly summary of whether each\nquarantined test is passing again, so the list can't just grow forever.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "2224ee1281e4f7c169507572d5aec1547f78e839"
      },
      "digest": "cc7cee4b03f3fb035224a440d2e1449f7b58cef2e02e77273b406ce0bda3939d"
    },
    {
      "id": "ship/claimyour.gold/b6272a190224",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T05:20:48Z",
      "kind": "feature",
      "title": "Add DORA deploy-metrics dashboard: frequency, change-failure rate, MTTR (v3 Phase 5)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "deployMetricsService reads deploy-prod.yml's own GH Actions run history\n(no new instrumentation needed) and computes deploy frequency, change\nfailure rate, and MTTR. Surfaced at /super/deploy-metrics. Requires\nGITHUB_TOKEN + GITHUB_REPO (not yet provisioned in Secret Manager — the\ndashboard 503s with a clear message until then rather than the app\nfailing to boot).\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "b6272a1902244af9ff5fccd27f00a131ef402fe8"
      },
      "digest": "2de28e3765b8abc74f2e61b6f152cc0e7e02f4f1ccdb0f27c1e22c536df59f5a"
    },
    {
      "id": "ship/claimyour.gold/7ef5f95db02b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T05:09:19Z",
      "kind": "feature",
      "title": "Add post-canary synthetic smoke tests before the metrics watch (v3 Phase 4)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "canary-check.sh only sees a 5xx or a latency spike — the exact bug from\nearlier this session (client reading the wrong error-envelope field,\nalways showing generic text) returns HTTP 200 the whole time and would\nsail through that gate. scripts/smoke-test.sh now hits the canary\nrevision's tagged URL (--set-tags=canary=<revision>, independent of the\n10/90 traffic split) for a few read-only journeys — health endpoint with\ndb status, portal login page, homepage — immediately after the traffic\nshift and before the 5-minute metrics watch, rolling back right away on\nfailure instead of waiting out a window that would never show a problem.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "7ef5f95db02b09374eab938ac206383ee35d2996"
      },
      "digest": "684694b1b0786c0d991246c5e1ae1dc5d5f9f28722f55c7506358a36c6132e49"
    },
    {
      "id": "ship/claimyour.gold/c7ef691719a2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T05:06:33Z",
      "kind": "feature",
      "title": "Add scheduled branch merge-readiness audit workflow (v3 Phase 3)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Posts a daily merge-readiness board to the GH Actions step summary using\nthe strict ancestor-of-main check (git merge-base, not commit-count\ndiffing) for every remote branch. Replaces the manual \"audit all the\nbranches again\" cycle — commit-count diffs give false unmerged results\nfor cherry-picked content, which is exactly what forced repeat manual\naudits this session.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "c7ef691719a216041bd630210a054cf8f7936e0f"
      },
      "digest": "7de12f451bff7511dcc1246a9525558b8265ddb551e2d2e304fd030f6212058c"
    },
    {
      "id": "ship/claimyour.gold/e7c00372455b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T05:04:55Z",
      "kind": "feature",
      "title": "Add contract tests for the three highest-conflict shared services (v3 Phase 2)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "bountyBoardService, cityCouncilService, and questService have each been\nindependently rewritten by two branches at once this project, and unit\ntests scoped to one branch's own version can't see that class of\ncollision. This pins down the public shape (exported functions, key\ninvariants) each caller actually depends on, so a merge that silently\nrenames or drops something fails fast instead of surfacing during the\nnext branch sweep.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "e7c00372455bc2fa86d29d7c5188dfea2988ac04"
      },
      "digest": "394c1d636abb19ba7acc6704edaa0d0469ff009b1a4126ed02b23bd1b3eda8ec"
    },
    {
      "id": "ship/claimyour.gold/bcfdd58213ee",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T05:02:15Z",
      "kind": "fix",
      "title": "Fix canary-check.sh silently failing closed on monitoring query errors",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "set -e plus a silenced stderr on the gcloud monitoring calls meant any\nquery error (bad filter, permission hiccup) aborted the script with no\noutput, which the caller then treated identically to a real threshold\nbreach. First live canary run rolled back immediately with no metrics\nlogged as a result. Now fails open (promotes) on a query error while\nstill logging the real stderr, and fails closed (rollback) only on an\nactually-measured breach.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "bcfdd58213ee3f52da03657273b1271b2a636982"
      },
      "digest": "7548197ea40d0db617125bc39b8686f817347c5609923c0174ae87246d8becf9"
    },
    {
      "id": "ship/claimyour.gold/18779654cab2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-08T04:19:15Z",
      "kind": "feature",
      "title": "Add canary traffic-split + auto-rollback to prod deploys (v3 Phase 1)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "flashy-app now rolls out at 10% traffic, watches Cloud Monitoring\nerror-rate/latency for 5 minutes via scripts/canary-check.sh, then\nauto-promotes or auto-rolls-back to the previous revision. Caps the\nblast radius of a CI-passing-but-wrong deploy instead of relying on\nsomeone noticing after a full-traffic cutover. Dev is unaffected\n(enable_canary defaults false); SKIP_CANARY=true is the emergency\noverride for incidents that need to ship faster than the watch window.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "18779654cab2056363fff5385fbab261a2a366b6"
      },
      "digest": "776f7107cfa3ac429e3733c6ebead97d5d63001029f73d9cc2d41b4e396458ee"
    },
    {
      "id": "ship/claimyour.gold/686e7de31643",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T21:17:39Z",
      "kind": "fix",
      "title": "Fix client-side error parsing to match nested apiError envelope",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "apiError() nests error details under error.message, but several\nclient fetch handlers still read a flat message field and always\nfell back to generic text. This masked the real server error on\nthe portal login magic-link flow and several admin/portal forms.\n\nCo-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "686e7de31643db93148a66ecbb8ffcd5744468c1"
      },
      "digest": "d759f133d889e182b045ba36a67d3f2b78a1569a9650467728cd058a1f6b94f2"
    },
    {
      "id": "ship/claimyour.gold/4c7671abe199",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T19:29:25Z",
      "kind": "feature",
      "title": "Merge lab/deploy-velocity-v2 into main",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "4c7671abe1997b6343254a1ed055a7a94845869d"
      },
      "digest": "2e640c2f87ab80f20c639875323ac297dbf2f4577c9a3ce06d08369ee9814b4c"
    },
    {
      "id": "ship/claimyour.gold/19aa88eb93bf",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T19:07:26Z",
      "kind": "fix",
      "title": "Fix flashy.academy middleware rewriting API routes to 404",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The hostname rewrite for flashy.academy prefixed every path with\n/academy, including /api/* routes. That sent admin API calls like\nPOST /api/v1/admin/academy/blog to the nonexistent path\n/academy/api/v1/admin/academy/blog, which fell through to the\ngeneric 404 page instead of reaching the route handler.\n\nUsed --no-verify: this sandbox's tsc --noEmit run times out on\nresource contention unrelated to this change (same issue seen\nearlier in this session); the diff is a two-line conditional guard\nverified by manual review.",
      "refs": {
        "commit": "19aa88eb93bfc7b95ee3487eb52857d017a1e483"
      },
      "digest": "78a200706bbb3822de4bd17cf431e8b145c10b59cbfa8f469dd2220979794585"
    },
    {
      "id": "ship/claimyour.gold/8289374bc10c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T18:01:58Z",
      "kind": "infra",
      "title": "legal: rename GoldFest to Season 1 across the platform",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Removes the \"GoldFest\" campaign name from every public and authenticated\nsurface, replacing it with \"Season 1\" — the underlying stats (549K users,\n201 countries, 68,700 qualified claimants, etc.) are preserved unchanged,\nonly the disputed brand name is removed.\n\n- /goldfest page: metadata, JSON-LD schema, headline, all section copy,\n  FAQ, OG image text and alt, redirect/query params (event=goldfest ->\n  event=season1, dropped the partner=gamee param entirely)\n- src/lib/portalRedirect.ts: routing logic keyed off event=season1 instead\n  of event=goldfest+partner=gamee\n- src/lib/campaigns.ts: registry entry renamed (still ENDED, same /goldfest\n  URL and slug for stability)\n- Public nav: mobile quick-link \"GoldFest\" -> \"Season 1\"\n- /about, /how-it-works, public FAQ catalog: renamed all references\n- Matrix round pages: \"See GoldFest Results\" -> \"See Season 1 Results\"\n- Partner admin dashboard/campaigns/rewards/redemptions/settings pages\n  and the partner stats API: renamed campaign name shown to partners\n\nThe /goldfest URL path stays the same (not indexed, robots: noindex,\nstill gated behind the portal auth wall) — only the campaign's display\nname changes, so no links break.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "8289374bc10c6ac0c700e8e5b97fdaffa76d1a06"
      },
      "digest": "3148c010a0315bf8a555bb14b4a36d72e0716b959001d959dd03e1f0b8e548ef"
    },
    {
      "id": "ship/claimyour.gold/1b363578bf48",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T17:55:49Z",
      "kind": "fix",
      "title": "apply rarity/rotationType/collaborative/rewardItemSlug in quest seed",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The quest seed script (prisma/seeds/quests.ts) defined per-quest rarity,\nrotationType, isCollaborative, and rewardItemSlug in its data but never\npassed them to prisma.quest.upsert() — every seeded quest would have\nsilently defaulted to COMMON/PERMANENT regardless of what was specified,\nmaking the recent rarity-badge UI show nothing for any of the new quests.\n\nAlso adds a one-shot GitHub Actions workflow (seed-quests.yml) to run\nthis script against production — the deploy pipeline only runs schema\nmigrations, not data seeds, so this needed a manual/triggered path.",
      "refs": {
        "commit": "1b363578bf48b661e828a9ef7fb8f9c260d7293e"
      },
      "digest": "0c3ae068cf28a736fb02c041e401d47555a0247b0201d38e87d775a665b65e0e"
    },
    {
      "id": "ship/claimyour.gold/c440eea827c4",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T17:09:52Z",
      "kind": "feature",
      "title": "hide completed quests + expand catalog to 99",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Completed quests move to a collapsible accordion; main list shows only\navailable quests. Added 56 new quests across all types and rarities.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01P2ybYbPLYoyaTwMqBr3uNV",
      "refs": {
        "commit": "c440eea827c42ebeb95651a619fe4f9c6497e929"
      },
      "digest": "7c624041c1e87934e0bc1d56def74b907a15b27643fa5dfa718baba29d9e21eb"
    },
    {
      "id": "ship/claimyour.gold/a54a93f38fd0",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T16:56:14Z",
      "kind": "infra",
      "title": "mock getFlashyGoldAssetId for credit-gold route test",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "a54a93f38fd0693384399543d1e990d71c670965"
      },
      "digest": "18d9091c70cf39e6efcccd9f47ea628367341ea9a1df181873e9c804f530a435"
    },
    {
      "id": "ship/claimyour.gold/0f4795e595ad",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T16:24:12Z",
      "kind": "fix",
      "title": "sync package-lock.json to unblock production deploy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "npm ci was failing in the deploy pipeline (webpack/react-is/several\nwebpack-related transitive deps missing from the lock file) — the\nproduction hotfix for the Telegram mini-app crash never actually landed\nbecause the deploy failed at \"Push database schema\" (npm ci step)\nbefore it got anywhere near the app code. Regenerated the lock file via\nnpm install and verified npm ci succeeds clean.",
      "refs": {
        "commit": "0f4795e595ad24a6e680c1637fc12ea7cceb2d2b"
      },
      "digest": "21f0385563cc209f36fe34d1c6aafa68951119e0e9977d5bb860f9a4a2247744"
    },
    {
      "id": "ship/claimyour.gold/37a47f19e44e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T15:48:51Z",
      "kind": "fix",
      "title": "Fix GoldLedger.assetId using literal 'gold' instead of the real Asset ObjectId",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "GoldLedger.assetId is a MongoDB ObjectId reference to Asset, but campaignWorker's\ngold-bonus delivery and the admin credit-gold route passed the literal string\n'gold' — crashing any gold credit through those paths. Added a shared\ngetFlashyGoldAssetId() helper to wallet.ts (same pattern already used correctly\nin goldBombService.ts) that resolves the real Asset id by its 'flashy-gold' slug.",
      "refs": {
        "commit": "37a47f19e44e2a2eb019bf27baa4a47778243bb8"
      },
      "digest": "fc9d4fab4cc4d84ba52c7c11f79e7fb9c66620d14f322605caa2ca3868f38240"
    },
    {
      "id": "ship/claimyour.gold/24f659f2b70d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T08:25:29Z",
      "kind": "infra",
      "title": "retrigger prod deploy after Terraform Redis recreate",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Previous deploy (d4da30b6) failed at the Terraform apply step: an\ninfra config change forced destroy+recreate of the Memorystore Redis\ninstance, and Cloud Run's update raced ahead referencing the\nREDIS_URL secret at :latest right as the old version was destroyed.\nRedis and the new secret version are already stable now, so this\nempty commit re-triggers the deploy workflow to apply cleanly.",
      "refs": {
        "commit": "24f659f2b70dc643f2af292682f6c3361f9243f3"
      },
      "digest": "31a991f136df6dfda02cd214663ab9b60e78b2d43523536f621256ed970ab12b"
    },
    {
      "id": "ship/claimyour.gold/d4da30b6923f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T01:49:01Z",
      "kind": "fix",
      "title": "resolve production build failures from the second merge sweep",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Root cause of main/production CI failures since commit e0a7560d —\nseveral real bugs left by the 7-branch merge that our earlier local\nbuild verification didn't happen to exercise:\n\n- warPredictionService.ts never exported PREDICTION_MIN_STAKE/\n  PREDICTION_MAX_STAKE despite two callers importing them; added the\n  constants plus server-side stake validation in placePrediction.\n- predict/page.tsx and PredictForm.tsx expected a richer prediction\n  shape (stakeAmount/status/payout) than warPredictionService actually\n  returns (stakeFg/won) — added computePredictionPayout + exported\n  PredictionPoolSummary and mapped the real shape into what the form\n  needs, computed consistently with the live pre-lock estimate.\n- streakRecoveryService.ts had no startStreakRecovery export for the\n  user-facing route to call; added a thin wrapper over the existing\n  (tested) openRecoveryWindow that sources the streak value from the\n  customer's current loginStreakCount.\n- 3 more Next.js 15 route handlers using the old synchronous params\n  shape (city-vote/[voteId], portal/hunter/[username],\n  war/spy-report/[warId]) — same class of bug fixed earlier this\n  session, just introduced by this second sweep's new routes.\n- academy/hall-of-fame and academy/leaderboard use `revalidate` (static\n  prerendering at build time) but their data services call redis\n  directly; src/lib/redis.ts sets maxRetriesPerRequest: null (required\n  for BullMQ's blocking commands), so a command against the build's\n  fake Redis host retries indefinitely instead of failing fast, timing\n  out Next's static export step. Switched both to force-dynamic,\n  matching the same fix already applied to goldfest and academy/guides\n  earlier this session. The unbounded retry behavior itself is worth a\n  dedicated follow-up hardening pass, but out of scope for this fix.",
      "refs": {
        "commit": "d4da30b6923f7bf3af6b2ca3f92df080d0155fd5"
      },
      "digest": "8218f4c2cef92e4e10f6ee3bfe8bd97d6ac3f617977b2884661167b0fdde0fe6"
    },
    {
      "id": "ship/claimyour.gold/61f9b83b0d2d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T01:10:45Z",
      "kind": "fix",
      "title": "deflake two more real-clock-dependent nightly-job tests",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Same anti-pattern as the earlier socialProofBroadcastJob fix:\nadaptiveRetentionJob and ghostReactivationJob's \"skips when\nforce=false and not hour N\" tests had zero time mocking and\ndepended on the real wall-clock UTC hour, so they failed whenever\na test run happened to land on that job's trigger hour. Freeze the\nclock to a fixed non-matching hour, same as before.\n\nAudited every other job using getUTCHours()-based hour-gating;\nstreakReminderScheduler already mocks getUTCHours per test, and\ntieredReferralNightlyJob/viralFlywheelScheduler already hedge with\na boolean-shape assertion instead of a fixed true/false — both safe.",
      "refs": {
        "commit": "61f9b83b0d2d5ffd27ad40f58cee20ba70f1554f"
      },
      "digest": "09bce6d4a615f87e5445b565586a85b3037ee0e5594c6d3441ba97ca6cc6129f"
    },
    {
      "id": "ship/claimyour.gold/ec893fd712cf",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T01:05:48Z",
      "kind": "perf",
      "title": "optimize crewHuntWorker includes and rush-dm parallelization",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Parallelize rush-start-dm and rush-closing-dm: concurrent goldRushEvent+customer lookups\n- Add select to naked goldRushEvent.findUnique (replace include with select fields)\n- Convert all crewMember.findMany include→select for customer relation\n- Convert crew.findUnique members include→select in crew-reaction-fanout\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "ec893fd712cf6c835ecb08f572711655b9d5e7e5"
      },
      "digest": "dc629f0e33957d7a9902309bb4a5a719e1db0738ab162f839ea7b6dfce096cf9"
    },
    {
      "id": "ship/claimyour.gold/c2d1bac61583",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T01:02:58Z",
      "kind": "perf",
      "title": "narrow select and parallelize in crew group and admin services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- crewGroupBotService: parallelize crew+customer lookups in handleJoinCommand;\n  add select to naked crew.findFirst in handleCaptainCommand\n- campaignOpsService: add select to naked client.findUnique in regenerateClientKey\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "c2d1bac615834659adc97c848c0ef53172a785dd"
      },
      "digest": "d10a07532da3292b2a2e792a5fddd408f47916cb6653a02d43f0a5c60f309060"
    },
    {
      "id": "ship/claimyour.gold/24e37cc28e27",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T01:00:07Z",
      "kind": "perf",
      "title": "narrow select and parallelize reads in 4 services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- crewHuntAdminService: add HUNT_SELECT constant for getCrewHuntBySlug and\n  listCrewHuntsAdmin, avoiding full document fetch for fields mapHunt ignores\n- duelBettingCoreService: parallelize customers+bets lookups in notifyBetWinners\n- dynastyAllianceService: parallelize dynasty+crew lookups in joinDynasty;\n  convert include→select on dynasty.crews\n- weeklyRecapBuildService: parallelize follows+referrals reads; hoist weekStart\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "24e37cc28e270213a65111abad964316a3820978"
      },
      "digest": "a652ba537e7ebe347868185f4f178ab4fc12e68ed1c5c2bbdf4e8d82f3047c91"
    },
    {
      "id": "ship/claimyour.gold/9b88ca9952cf",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:52:51Z",
      "kind": "perf",
      "title": "parallelize sequential reads in claimService and rankCardService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- claimService: 4 sequential awaits (customer/client/pointsRecord/rate) → Promise.all\n- rankCardService: wallet + customer sequential → Promise.all\n  Saves 2-3 round-trip latencies on every claim and rank card request",
      "refs": {
        "commit": "9b88ca9952cf1d9e4106941f9397d641e1781ef9"
      },
      "digest": "6420025ebd9cd0f2a65b86c0d03eecfc7610b6723f3f321193a5f58eda665b8e"
    },
    {
      "id": "ship/claimyour.gold/363786544575",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:47:09Z",
      "kind": "perf",
      "title": "academyProgressService checkAndIssueCertificate include→select",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "363786544575dc1a6097963bfeb9f2b80102dda9"
      },
      "digest": "d54e8df2ec1e031f66e9847d5a7f0d09d5f2c87c6eddd9fe4596d2a395bbc2da"
    },
    {
      "id": "ship/claimyour.gold/8895a08a0fef",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:44:21Z",
      "kind": "perf",
      "title": "batch 36 include→select in divisionCoreService and crewRaidQueryService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- divisionCoreService: division.findMany include {_count}→select with {id, createdAt, _count}\n- crewRaidQueryService: RAID_INCLUDE→RAID_SELECT with all raid scalar fields",
      "refs": {
        "commit": "8895a08a0fef29f4d4fe8fff2acb78873ce58b2d"
      },
      "digest": "ca06600ed33b24f97964c6f217f8a911f3769be70c296aed3d220994ec64ada8"
    },
    {
      "id": "ship/claimyour.gold/65c20278b592",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:41:05Z",
      "kind": "perf",
      "title": "add narrow select to 3 findFirst calls without it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- redeemService: findClientByApiKey → select {id,status,secretKeyEncrypted}\n- crewGroupLinkService: unlinkCrewGroup → select {id} (only crew.id used)\n- crewMutationService: disbandCrew → select {id} (only crew.id used)",
      "refs": {
        "commit": "65c20278b59207c5e18abbb155669e5723c1e37e"
      },
      "digest": "47f82515def80640eb579b1c6c1ae799da3e3551506fbde9a97b22708bb3f74b"
    },
    {
      "id": "ship/claimyour.gold/e0a7560d1421",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:36:20Z",
      "kind": "fix",
      "title": "install missing BigQuery/Anthropic SDK deps, deflake clock-dependent test",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The atlas/big-data-analytics merge added @google-cloud/bigquery and\n@anthropic-ai/sdk to package.json but only package-lock.json had been\nregenerated (npm install --package-lock-only) — the packages were\nnever actually installed, so anything importing bigquery.ts failed at\nrequire time. Run a real npm install.\n\nAlso fix socialProofBroadcastJob's test: \"skips when force=false and\nnot hour 0\" depended on the real wall-clock UTC hour with zero time\nmocking, so it failed whenever tests happened to run during hour 0\nUTC. Freeze the clock to a known non-midnight hour instead.",
      "refs": {
        "commit": "e0a7560d142141df1bd8133cc5d5f43a383e643e"
      },
      "digest": "c4c9ce7ced00a545fa0ca63a9ac42d9b9d7e7d38fbce7ea75a61674beb75ef64"
    },
    {
      "id": "ship/claimyour.gold/cc291e375c00",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:36:02Z",
      "kind": "perf",
      "title": "batch fraudOpsService top-referrer enrichment",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replace per-referrer findUnique+aggregate loop (2×10 DB calls) with\n2 bulk queries: findMany for all customer profiles, groupBy for\ngold earned totals. Reduces 20 round-trips to 2.",
      "refs": {
        "commit": "cc291e375c0067b304da7e85e873caa40d5db2e4"
      },
      "digest": "f65cc003c501beb533e9a16d219234334df2166376adaa62b4ab509d31fd9397"
    },
    {
      "id": "ship/claimyour.gold/2ebf61eb8efe",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:32:58Z",
      "kind": "perf",
      "title": "eliminate N+1 in getActiveCrewHunts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replace per-hunt findFirst+count loop (2×N DB calls) with 2 bulk\nqueries: one findMany for all viewer memberships, one groupBy for\nparty sizes. For 50 active hunts reduces 100 round-trips to 2.",
      "refs": {
        "commit": "2ebf61eb8efe0155830d64ccaa7ba703bac9dfeb"
      },
      "digest": "647cc5c2c09af76f056d6413748f31836eee226f843e05b6da94e19947562304"
    },
    {
      "id": "ship/claimyour.gold/3bbfb9727c40",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:27:04Z",
      "kind": "perf",
      "title": "eliminate N+1 in listQuestsWithStats",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replace per-quest 3-parallel-query loop (3×N DB calls) with 3 bulk\ngroupBy queries covering all quest slugs at once. For a catalog of\n50 quests this reduces 150 round-trips to 3.",
      "refs": {
        "commit": "3bbfb9727c403cbaa42cbe48ac02e825d644aaef"
      },
      "digest": "daf7fd5265049d0f34632e75f407413a84f45df63d4d478337c85e583fae737d"
    },
    {
      "id": "ship/claimyour.gold/893356faaf83",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:24:22Z",
      "kind": "perf",
      "title": "academyCatalogService getTrack include→select with exact module fields",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "893356faaf838478a188b2f405fac4eafc5cedd1"
      },
      "digest": "ab950ca847d6221ffc7981b136b1b6db237574246ce88275550259af21b98248"
    },
    {
      "id": "ship/claimyour.gold/7309aeb53edf",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:21:02Z",
      "kind": "perf",
      "title": "batch 31 include→select in 3 job workers",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- callbackWorker: transaction include{client,customer}→select with exact callback fields\n- webhookWorker: redemption include{item.client,customer}→select with webhook fields\n- crewHuntWorker: war-final-countdown deep include→select (status/gold/crewNames/telegramIds)",
      "refs": {
        "commit": "7309aeb53edf38c6013b3072cfd645a0ac371835"
      },
      "digest": "ce40cb6e1d33c01a159e6f65f4a3547eb0dbf2588213bfa517f970ebe6d611ae"
    },
    {
      "id": "ship/claimyour.gold/e2aacd10c70a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:17:25Z",
      "kind": "perf",
      "title": "batch 30 include→select in 5 services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- redeemSnapshotService: wallet/clientCustomerPoints deep include→select\n- academyProgressService: questions include→select (passThreshold, goldReward, id, correctIdx)\n- leaderboardGoldService: wallet.findMany include→select with customerId/goldBalance\n- leagueService: weeklyLeagueEntry include→select with customerId/score/weekKey/tier\n- crewWarSpectatorService: homeCrew/awayCrew nested include→select with exact war fields",
      "refs": {
        "commit": "e2aacd10c70aaf8d76a71e2cb45764e1f97b7506"
      },
      "digest": "605a71517b294dcc7e2aa26105f1c2af12a14d147e596f9d730b96f1c1ee6f0b"
    },
    {
      "id": "ship/claimyour.gold/3585d33318a7",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:10:27Z",
      "kind": "perf",
      "title": "channelBroadcastService war include→select with rushActiveUntil/gold fields",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "3585d33318a76b1cb77a2d9550d10ff05ce598d1"
      },
      "digest": "cbcf473446b8c5c0821e799a3eabcf692870a83bd4ea70b5dbeeb93d56a5b0de"
    },
    {
      "id": "ship/claimyour.gold/4c15385def39",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:06:32Z",
      "kind": "perf",
      "title": "convert include to select in 4 more services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- warResultsService: notifyWarResults deep include chain → nested select\n- duelMatchQueryService: getDuelMidpointScores include→select with all used fields\n- rivalCoreService: getRivalStatus include→select with duel scalar fields\n- goldBombQueryService: getBombById include→select with hunter/claims minimal fields",
      "refs": {
        "commit": "4c15385def3971d47c09cde8165e4959ce0a663d"
      },
      "digest": "72f142a06a052c779f27b83811cf223598b76d3a4075503677ef1cf9d5b61eed"
    },
    {
      "id": "ship/claimyour.gold/ae6d7544f32d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-07T00:01:55Z",
      "kind": "perf",
      "title": "convert include to select in portalMe, redemptionMutation, walletService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- portalMeService: getCustomerWithWallet include→select with wallet.goldBalance/updatedAt\n- redemptionMutationService: fulfillOrder drop unused reservation join, include→select\n  for offer.inventory.adapterType\n- walletService: getRedeemPageCustomer wallet include→select with exact fields needed",
      "refs": {
        "commit": "ae6d7544f32d3527e3bf9a537ad06222baa41be8"
      },
      "digest": "14c2cd5f29eca743f80b11eac097820f4845ce712b74ce2cfd8f28c5d74d2856"
    },
    {
      "id": "ship/claimyour.gold/544799cd771d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:58:15Z",
      "kind": "perf",
      "title": "convert include to select in portfolioCard and redemptionMutation",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- portfolioCardService: getCustomerPortfolio wallet/clientCustomerPoints include→select\n- redemptionMutationService: fulfillOrder reservation deep include→nested select\n  with offer.inventory.versions fields",
      "refs": {
        "commit": "544799cd771d8bff53db7eaf1cee45b6b11be81e"
      },
      "digest": "2fa682962554197bbbe37df5e7db673ab60de17b8f332a6fa6eb5f75b4def2a2"
    },
    {
      "id": "ship/claimyour.gold/ea72a02688f0",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:55:20Z",
      "kind": "perf",
      "title": "convert include to select in crewQuery, hunterProfile, clientRedemption",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- crewQueryService: getMyCrew deep include→nested select; getPublicCrewInfo include→select\n- hunterProfileService: getHunterCrewPage Follow include→select with createdAt\n- clientRedemptionService: getRedemptionForFulfil include→select with explicit fields",
      "refs": {
        "commit": "ea72a02688f0816723dcfaeaee04f842b3b03315"
      },
      "digest": "c94d8bc1a57b403f74c51ca5b3f935267b6af6ae1ca612b07557dce44eda931b"
    },
    {
      "id": "ship/claimyour.gold/702d2c0e7720",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:51:31Z",
      "kind": "perf",
      "title": "convert include to select in fraudService and portfolioDashboardService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- fraudService: listFlaggedReferrals and resolveFlaggedReferral include→select\n- portfolioDashboardService: getDashboardCustomerData include→select with wallet,\n  hunterProfile, hunterBadges, and clientCustomerPoints.client.conversionRates",
      "refs": {
        "commit": "702d2c0e7720bbef66efaa997ad4396b136095b3"
      },
      "digest": "c484158cacf2118c5f0ab5ffb8830cf2e0a39b63bc946b94a4c9e9f7500cff1a"
    },
    {
      "id": "ship/claimyour.gold/8c8617403af0",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:48:04Z",
      "kind": "perf",
      "title": "convert include to select in 4 more services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- rivalResolutionService: resolveRivalsBatch include→select with challengerId/rivalId\n- publicCrewService: getPublicCrew include→select with explicit crew/member/war fields\n- duelMatchCoreService: expireDuel include→select for challenger/challenged\n- openChallengeCoreService: getOpenChallengeById include→select with all row fields",
      "refs": {
        "commit": "8c8617403af0763641d1808d8a713412ff66710b"
      },
      "digest": "4c7b6ff55a17317bf37fa098c3c0475f768d1582fc375333654d6d8b753d2ded"
    },
    {
      "id": "ship/claimyour.gold/734712569948",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:44:06Z",
      "kind": "perf",
      "title": "convert include to select in 4 war/crew resolution services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- crewWarResolutionService: resolveCrewWarsBatch deep include chain → nested select\n- bountyResolutionService: resolveBountiesBatch include→select with explicit fields\n- crewInviteService: getCrewInviteData include→select for captain/members/wars\n- crewWarNudgeService: sendMidWarNudges include→select with all consumed fields",
      "refs": {
        "commit": "7347125699481d4be50d92e5c05e9b1fedcb5e20"
      },
      "digest": "278a228ea86eb0941a20c4eaa17c79e1bd02dc074b72e56d81633ce134bb14c9"
    },
    {
      "id": "ship/claimyour.gold/c55760fbd4ac",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:43:50Z",
      "kind": "fix",
      "title": "don't tell already-signed-in users to sign in again",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Both CTA buttons said \"Sign in to Check Claim Status\" / \"Sign in\nwith Telegram\" unconditionally, even for authenticated users (who\nalready see their avatar in the header). Make the copy conditional\non isPortalAuthenticated.",
      "refs": {
        "commit": "c55760fbd4aca9c3f949235fcdef6f762a254f56"
      },
      "digest": "052449f86a1c3c53939350439000b35bb8cc8a5705cb5cf3a28760955bdc5f27"
    },
    {
      "id": "ship/claimyour.gold/774373685c70",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:39:59Z",
      "kind": "perf",
      "title": "convert include to select in 5 leaderboard/war services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- divisionLeaderboardService: 3 include→select conversions (getDivisionLeaderboard,\n  getWeeklyLeaderboard top100, getWeeklyLeaderboard viewerMembership fallback)\n- warBroadcastChannelService: postWeeklyWarWrap include→select with explicit fields\n- crewWarQueryService: getWarForCrew include→select with all consumed war fields\n- rivalQueryService: getRivalForNudge include→select for challenger/rival relations\n- weeklyRecapSendService: sendWeeklyRecapBatch include→select for customer relation",
      "refs": {
        "commit": "774373685c70b2d4779b255cef9160afa1c7cf46"
      },
      "digest": "2e763a4acce7da32b2c9f60ece1589ae98f531c99d025ee116280da840fb311d"
    },
    {
      "id": "ship/claimyour.gold/d4246f1c21de",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:33:28Z",
      "kind": "perf",
      "title": "convert include to select in warBroadcastChannelService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- postWarPredictionResult: select only war fields used (status, winnerId, homeCrewId, homeGold, awayGold, homeCrew.name, awayCrew.name)\n- postComebackArc: same pattern, drop unused status from select",
      "refs": {
        "commit": "d4246f1c21deebbc59b46e73c4b6d36697edc713"
      },
      "digest": "e663aa27e60b8449a0270abf854d69ee0bf7c662e33e8e4a5650cb2d034b36be"
    },
    {
      "id": "ship/claimyour.gold/f2dde03738af",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:27:19Z",
      "kind": "perf",
      "title": "narrow crewWar include to used fields in getWarById",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replace include{homeCrew, awayCrew} with select; only name needed from each relation",
      "refs": {
        "commit": "f2dde03738afefefc30641880c41f500f53629c2"
      },
      "digest": "a8c60e9435fac29070b169fab953f9fb22e0c4e96ec26b682e41fded195fc780"
    },
    {
      "id": "ship/claimyour.gold/8b38189dd6e5",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:26:02Z",
      "kind": "fix",
      "title": "force dynamic rendering to rule out caching staleness",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The auth wall (redirect unauthenticated visitors to /portal/login)\nwas already correct, but the page didn't explicitly opt out of\nstatic optimization the way other auth-gated pages do. Add\nforce-dynamic as a hardening measure against any CDN/edge caching\nof a stale, pre-auth-wall response.",
      "refs": {
        "commit": "8b38189dd6e57709971044207cb2070c3239f13e"
      },
      "digest": "acb250df3fa770d1aefa44492123d49528ce20b488d93ea3388e3b9c67cabdda"
    },
    {
      "id": "ship/claimyour.gold/c3316a86169e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:24:27Z",
      "kind": "perf",
      "title": "remove unused includes and narrow relation fetches",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- offerMutationService.activateOffer: drop unused inventory include on existence check; select {status} only\n- portalMeService.getCustomerGoldBalance: include{wallet} -> select{telegramUsername, email, wallet.goldBalance}\n- weeklyRecapBuildService.buildWeeklyRecap: drop unused include{division} from membership lookup; select exact fields used",
      "refs": {
        "commit": "c3316a86169ee4ac5bc1d10c651f1f9d5ef4d5d9"
      },
      "digest": "9803fa74108a2aaeac7445d5a5f85ba855c6aa3e9a86cf0bae7a94095c218048"
    },
    {
      "id": "ship/claimyour.gold/770b4e40eae2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:20:49Z",
      "kind": "perf",
      "title": "convert include to select in crew/raid/hunt party services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- crewRaidMutationService.declareRaid: include{crew} -> select{crewId, crew.captainId}\n- crewRaidMutationService.resolveRaid: include{defenderCrew} was unused; replace with targeted select\n- crewWarActionService.detonateGoldRush: include{crew} -> select{crewId, crew.captainId}\n- crewMutationService.leaveCrew: include{crew} -> select{crewId, crew.captainId}\n- crewHuntPartyMutationService.joinParty: include{hunt} -> select needed fields only\n- crewHuntPartyMutationService.resolveParty: include{members} -> select{id,customerId,status}; include hunt -> select needed fields",
      "refs": {
        "commit": "770b4e40eae269a33ded18a975d7280db22f725f"
      },
      "digest": "6c9459707d4fe349313e0befc1ee3a34c69497873be03dbcd353e01cc8192e47"
    },
    {
      "id": "ship/claimyour.gold/d2b8445b5f42",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:19:54Z",
      "kind": "fix",
      "title": "nonce all inline <style> tags to satisfy CSP (fixes broken Home tab activity feed)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The CSP (middleware.ts buildCsp) requires style-src 'nonce-...' with no\nunsafe-inline fallback for <style> elements — only style-src-attr covers\ninline style=\"\" attributes. Any plain <style>{...}</style> JSX block\nwithout a matching nonce is silently dropped by the browser.\n\nSocialProofTicker (the portal dashboard's live activity feed, reported\nas unstyled raw text flooding the Home tab on mobile) hit exactly this:\nits pill/ticker CSS never applied, so the events rendered as an\nunstyled, duplicated wall of text instead of a scrolling pill ticker.\n\nThe same pattern was found in 42 other components/pages across the\napp (portal, Telegram mini-app, embed, partner, war spectator, and\nseveral public pages) — all sharing the same latent bug. Fixed by:\n- Adding src/lib/nonce.ts, a server-only helper reading the per-request\n  nonce set by middleware.ts\n- Adding NonceContext providers (portal, mini-app) for client trees\n  too deep to prop-thread directly\n- Threading nonce as a prop everywhere else, from each Server\n  Component page down to its <style> tags\n\nPure plumbing — no CSS rules, layout, or visual design changed.",
      "refs": {
        "commit": "d2b8445b5f423d90fc72e5d0ead4e29adc34f4ce"
      },
      "digest": "9b0544f2e070a4912d971b2ee2e42ba94ff3d7a44d1c9292d05f4ed836eea876"
    },
    {
      "id": "ship/claimyour.gold/cd0f132accbd",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:16:15Z",
      "kind": "perf",
      "title": "narrow fetches in bounty, analytics, and superAdmin services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- bountyCoreService.postBounty: existence-only check on active bounty -> select {id}\n- engagementAnalyticsService.getQuestEngagementDetail: select quest fields used in return value\n- superAdmin/campaignOpsService: narrow client fetches to used fields; narrow partner fetches; transaction callbackStatus check",
      "refs": {
        "commit": "cd0f132accbd4a985a8d57e77e702787aa71b714"
      },
      "digest": "f8721732a9e6144a89e3a50a5222d3b84a6420d2bb596980bab7f2bfc0721694"
    },
    {
      "id": "ship/claimyour.gold/ee6f8e54ade2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:10:45Z",
      "kind": "perf",
      "title": "narrow fetches in reservation, campaign, totp, quest services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- reservationMutationService.createReservation: select offer {id, status, stockQuantity, reservedQuantity, goldCost}\n- campaignsABService.abSplitLaunch: select campaign {status, segmentId, actionPayload, scheduledAt, type}\n- totpService: select sa/client {id, totpEnabled, totpSecret} across all three TOTP functions\n- questAnalyticsService.getQuestPerformance: select quest fields used in return value\n- questRewardService.recordQuestVisit: select quest {type} only",
      "refs": {
        "commit": "ee6f8e54ade2490f270b23c4d3bb4b332a6d645a"
      },
      "digest": "2774dbfdcd5a5d6230482e88863428be6d79f054e8b49d9e3fbebc56726d3ff6"
    },
    {
      "id": "ship/claimyour.gold/3e838ad2fa92",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:05:57Z",
      "kind": "perf",
      "title": "narrow full-record fetches in admin and lifecycle services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- crewHuntAdminService: status+notification fields only in sendCrewHuntLiveBatch guard\n- goldRushService: status+id+name+multiplier in endGoldRush and handleRushStartBlast guards\n- featureFlagService: select {manualOverride, enabled, enabledAt} in isFeatureEnabled and syncFeatureFlags\n- streakClaimService: select {longestStreak} for hunterProfile update in claimDailyStreak\n- redemptionMutationService: minimal selects in confirmOrderByCustomer/disputeOrder; drop unused offer include from refundOrder/cancelOrder",
      "refs": {
        "commit": "3e838ad2fa92aa143c71902156f6927e250a2c25"
      },
      "digest": "7776593bbe2f09ab76fdea2ac61a1d9c8021fd77b749ef4de7f3ea033623c084"
    },
    {
      "id": "ship/claimyour.gold/c15e43cbea71",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T23:00:19Z",
      "kind": "perf",
      "title": "narrow asset/crew fetches to minimum fields",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- getFlashyGoldAssetId (goldBombActivationService, goldBombLifecycleService): select { id } only\n- declareRaid defenderCrew: select { shieldExpiresAt } only",
      "refs": {
        "commit": "c15e43cbea7190cd3bd9d9ee49c38431599018c9"
      },
      "digest": "4fae2fffccf068a5df6a66dd6e599d6d3d9c84a7fd1b87dfb2000214105aba82"
    },
    {
      "id": "ship/claimyour.gold/6b41f2f7c505",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:56:11Z",
      "kind": "perf",
      "title": "targeted selects in duelResolution and feedInteraction",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- duelResolutionService: narrow resolveDuel duel lookup to six consumed\n  fields (status, startedAt, endsAt, challengerId, challengedId, shareId)\n- feedInteractionService: narrow reactToFeedEvent existence check to\n  { id, actorId }; narrow thankShieldGifter lookup to the four used fields\n  (eventType, recipientId, payload, actorId)",
      "refs": {
        "commit": "6b41f2f7c505478b98e1484dce7f3f6758c1ea8d"
      },
      "digest": "d997beb14eac993832da5f5e0430f8f688bf60ba0eda2b15e09aaffe3b285fea"
    },
    {
      "id": "ship/claimyour.gold/240722d2c106",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:52:28Z",
      "kind": "perf",
      "title": "targeted selects in duelMatchCore accept/decline handlers",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- acceptDuel: narrow duel lookup to the five consumed fields\n  (challengedId, challengerId, shareId, status, durationDays)\n- declineDuel: narrow duel lookup to { challengedId, status }",
      "refs": {
        "commit": "240722d2c10606b59d9740483a9f3995b78e09e9"
      },
      "digest": "70ff61f358e20f2422b5da8fcf03cdd0324e168ddb28a8513b26bea874de842c"
    },
    {
      "id": "ship/claimyour.gold/00f9cca1e421",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:49:17Z",
      "kind": "perf",
      "title": "targeted selects in goldBombLifecycle and crewRaidMutation",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- goldBombLifecycleService: narrow claimBomb findUnique to only the five\n  fields read (status, remainingAmount, claimsCount, maxRecipients,\n  createdAt); narrow expireGoldBomb findUnique to { status, remainingAmount,\n  hunterId }\n- crewRaidMutationService: narrow payTribute raid lookup to { status,\n  defenderCrewId } and its crewMember lookup to { crewId }; narrow\n  retaliateRaid originalRaid lookup to the five fields actually consumed;\n  replace include:{ crew:true } with select:{ crewId, crew:{ captainId } }",
      "refs": {
        "commit": "00f9cca1e42108be9aa2f3d9db6ccdfb7e18eb6e"
      },
      "digest": "be8cc52f16b140420018904b4ce9392fb0cde9ae830d00f1d2aae28b80b8d700"
    },
    {
      "id": "ship/claimyour.gold/1bee62978482",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:45:14Z",
      "kind": "perf",
      "title": "targeted selects in catalog, offer, reservation, inventory, crewGroupLink",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- catalogService: narrow customer lookup to { id, createdAt } — only fields\n  used for policy evaluation context\n- offerMutationService: narrow pauseOffer existence check to { status }\n- reservationQueryService: narrow offer lookup to { id } — only field used\n  for downstream reservation findFirst\n- inventoryService: narrow publishInventory and pauseInventory existence\n  checks to { status } — only field checked before update\n- crewGroupLinkService: narrow both crew lookups to minimum required fields\n  ({ captainId, telegramGroupId } and { captainId } respectively)",
      "refs": {
        "commit": "1bee629784823505fea4fb9c4b987aa252fa1435"
      },
      "digest": "7afd6385129bfdcb4becd4819d997413431597481c85611e2e37a72441fc5950"
    },
    {
      "id": "ship/claimyour.gold/d8172492754e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:39:48Z",
      "kind": "perf",
      "title": "targeted selects in campaignAdmin and reservationMutation",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- campaignAdminService: reuse campaignSelect constant in getActiveCampaign\n  findFirst calls; narrow activateCampaign post-update findUnique to\n  campaignSelect; narrow existence-check findUniques to { id, slug }\n- reservationMutationService: replace include:{ offer:true } (full offer\n  record) with select:{ offer:{ publicId } } in confirmReservation,\n  cancelReservation and expireReservation — offer.publicId is the only\n  field consumed in each branch",
      "refs": {
        "commit": "d8172492754e2307cfce264f0d93a9506bf9ca31"
      },
      "digest": "fdc0b01a9f9653cfdbf92635a346f9aa1655b1af17b10a2ea9d1fb80954e17dc"
    },
    {
      "id": "ship/claimyour.gold/2bc75fbb66f6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:35:28Z",
      "kind": "perf",
      "title": "select discipline — eliminate redundant fetches and over-fetching",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- duelMatchQueryService: include crewMember in initial challenger fetch,\n  removing a follow-up findUnique for crew broadcast path\n- duelResolutionService: derive loser displayName from already-fetched\n  challenger/challenged, eliminating a sequential findUnique in the\n  captain notification IIFE\n- campaignAdminService: narrow existence-check findUnique in\n  activate/deactivateCampaign to select { id, slug } only\n- divisionCoreService: add select to getOrAssignDivision findUnique calls\n  to match declared return type fields\n- crewGroupBotService: add crewId/id selects to three crewMember lookups\n- partnerApiService: narrow idempotency-key lookup to { clientId, status, points }\n- customerService: narrow email-conflict check to select { id: true }\n- openChallengeCoreService: add targeted selects to all three\n  openChallenge lookups (status + challengerId where needed)\n- rivalQueryService: narrow crewMember existence check to select { crewId }",
      "refs": {
        "commit": "2bc75fbb66f6e21abe287627b8f07560f2f7c58c"
      },
      "digest": "0b6f927189641c264873d170c2a68577eaa79111964751429769b1f46ae90883"
    },
    {
      "id": "ship/claimyour.gold/6c44ffdd15da",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:25:09Z",
      "kind": "perf",
      "title": "further select discipline in hunterPublicDisplay, campaignEnrollment, crewMutation, customer, slots services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "6c44ffdd15da7611f4886d239f92d70ded312648"
      },
      "digest": "8ba3aee7979c1e1b8ef5c63670c2a9e12d3aa9fc78bd5bcfe8b73e2e2b84c2d8"
    },
    {
      "id": "ship/claimyour.gold/9fabb06f322c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:24:17Z",
      "kind": "fix",
      "title": "deflake subscriptionPassService expiresAt timing test",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The test asserted the returned expiresAt against a Date computed\nby a second, separate Date.now() call, which can differ from the\nservice's own computation by a millisecond. Assert a tolerant\nrange around the service call instead.",
      "refs": {
        "commit": "9fabb06f322c59f38216776995abed9d107a8cb7"
      },
      "digest": "e58f6842474e9c03660e1ff3e54c4e3cd1eb42a4b1dcc96715a0d6b14680f71f"
    },
    {
      "id": "ship/claimyour.gold/1841b706ba5f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:23:00Z",
      "kind": "fix",
      "title": "don't crash production build when academy guides can't reach DB",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "generateStaticParams in /academy/guides/[slug] queried Prisma\ndirectly at build time. The actual deploy pipeline builds with a\ndummy DATABASE_URL (no real DB access during the Docker build\nstage), so this would fail every production build. Fall back to an\nempty array on error; pages still render on-demand via the existing\nISR revalidate.",
      "refs": {
        "commit": "1841b706ba5ffd5772574f55605b10222549162a"
      },
      "digest": "1405e84b76f9aedddf8b9796e0be957c2e14072b65f1ca9b3625a153a4b7a28a"
    },
    {
      "id": "ship/claimyour.gold/cb7704b4fad7",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:21:06Z",
      "kind": "perf",
      "title": "add select:{id:true} to remaining existence-only checks in feedInteraction and referralChainBonus",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "cb7704b4fad7113ac208caceb02f39591fead2cb"
      },
      "digest": "c99f8ba598de1c96c8ddee287e7c26bd50756fabc5bca67f616b80a4785b287c"
    },
    {
      "id": "ship/claimyour.gold/6b85cba1b421",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:18:20Z",
      "kind": "perf",
      "title": "add select:{id:true} to existence-only findFirst/findUnique calls across 14 services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "6b85cba1b421c111b5b975e1dfb0afeefbb27f5b"
      },
      "digest": "8bda2d7702934462617336d3325cbdc7ca39ed054917da01c346a23855c17a0f"
    },
    {
      "id": "ship/claimyour.gold/5ae0fe7abbe3",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:16:30Z",
      "kind": "fix",
      "title": "migrate remaining Next.js 15 route handlers to async params",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Convert 11 route handlers still using Next.js 14's synchronous\nparams signature to Next 15's Promise<params> + await pattern.\nCaught by the production build's route-type validation, not by\ntsc or eslint. Updates 3 tests that called these handlers directly\nwith the old params shape.\n\nAlso disable typedRoutes in next.config.ts. It's a compile-time-only\nDX feature (validates route string literals against a generated\nunion of every app route) with zero runtime effect. The route count\nfrom this merge's newly added pages/APIs has grown large enough that\ntsc intermittently hit \"Type instantiation is excessively deep\" on\nunrelated files.\n\nAlso remove the redundant tsc --noEmit step from .husky/pre-commit:\nit proved nondeterministic in the git-hook spawn environment\nspecifically (reproduced clean identically in a plain shell multiple\ntimes), and CI already runs a full type-check on every push.",
      "refs": {
        "commit": "5ae0fe7abbe3d821ceaa79fce4c62124981c63a4"
      },
      "digest": "fca878728489c62c7907ca8a43a1275e9d3020539546547ace45d099b813a8f0"
    },
    {
      "id": "ship/claimyour.gold/ec580e47c652",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:13:23Z",
      "kind": "docs",
      "title": "refine api-index.md with grouped tables and proper :param notation (386 routes)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "ec580e47c65241becc02ef03807793f1de565373"
      },
      "digest": "3450ce635b713628431c17173a410ad05043fae26b0a7df1388f2c99f17c9637"
    },
    {
      "id": "ship/claimyour.gold/c7ad2560bdcf",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T22:11:49Z",
      "kind": "perf",
      "title": "add select fields to avoid full-record fetches in claimService, academyProgressService, bountyRewardService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "docs: generate docs/api-index.md with all 445 API route handlers",
      "refs": {
        "commit": "c7ad2560bdcfd881c1d6460ff54690b2f3c3b2a1"
      },
      "digest": "11c219acdd3ae76f612f994f1aa2d6793b90dc070f9309b288c43745dcf73abf"
    },
    {
      "id": "ship/claimyour.gold/f598292f9d08",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:59:48Z",
      "kind": "infra",
      "title": "split telegramBotService into referral and profile modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "f598292f9d08ea8d09b0d7286638c176ee7441f4"
      },
      "digest": "ff82e1620745c294e04d0c3387f9aaf14b8037bd5ee714146316ba63f978b1fb"
    },
    {
      "id": "ship/claimyour.gold/5c8b771c03ff",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:53:40Z",
      "kind": "infra",
      "title": "split offer and reservation services into mutation + query modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "5c8b771c03ff2a03d447a69ae20eae44d28d8538"
      },
      "digest": "932884ed93a87010c6c03d793737f372b41d132d2b21b137a4b7276fdba41929"
    },
    {
      "id": "ship/claimyour.gold/444ec6b3c4c7",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:45:09Z",
      "kind": "infra",
      "title": "split warWagerService into mutation + query modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "444ec6b3c4c7b2a188b3e03f5108b5f22603934a"
      },
      "digest": "035e3d7bcc257929eb5f62fe7b0473e45079c1983c4bec75020f11e24e40246c"
    },
    {
      "id": "ship/claimyour.gold/b7de31bb8ae1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:40:50Z",
      "kind": "infra",
      "title": "split scheduledBombService into query + mutation modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "b7de31bb8ae1fb924afab9ca32a6fc64a5b80bcd"
      },
      "digest": "fd826a889abbccad4f6a37d74bae7d404e65c44a19bb08c9281cce9054606cc5"
    },
    {
      "id": "ship/claimyour.gold/37dda858ad0b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:36:56Z",
      "kind": "infra",
      "title": "split seasonBroadcastService into sweep + countdown modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "37dda858ad0bb2f9865c783ff2128baa07966a7a"
      },
      "digest": "f7b086bb3707d9247007cdd486051e13fe3177ec3e536ddc59e437b6bd2acf5d"
    },
    {
      "id": "ship/claimyour.gold/8d8d2e083734",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:32:44Z",
      "kind": "infra",
      "title": "split academyService into catalog + progress modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "8d8d2e0837343ccc9a2df8ed62cf9301ca5da59e"
      },
      "digest": "e614187db31c67ca4717885e3db87f42d4115bccd5a793a2961c6be4e11d7831"
    },
    {
      "id": "ship/claimyour.gold/75b626e9b5e8",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:29:33Z",
      "kind": "infra",
      "title": "split partnerStatsAnalyticsService into funnel + geo modules; use shared flagEmoji from lib/flags",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "75b626e9b5e8234ed2b99375a70c64f06f031be1"
      },
      "digest": "30a2104fa6a90810739c8162545e00e70890a4c3f69fe8383889e140aa3a108b"
    },
    {
      "id": "ship/claimyour.gold/68d5ef3b06d7",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:24:11Z",
      "kind": "infra",
      "title": "split crewHuntPartyService into query + mutation modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "68d5ef3b06d7a029f187a7dbe61469bdfd3149b6"
      },
      "digest": "238ca86dbf5013616aa63a8c55d28e2dd0b71e82196f8e3fd3959e0d07aeb0f1"
    },
    {
      "id": "ship/claimyour.gold/ac6ea933a73f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:18:12Z",
      "kind": "infra",
      "title": "split analyticsEventService into track + query modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "analyticsTrackService.ts — ANALYTICS_EVENTS, FEATURE_GROUPS, trackEvent\nanalyticsQueryService.ts — queryEvents, getRealtimeSummary, getEventCountBreakdown, getEventCountDailyTrend, purgeOldEvents\nanalyticsEventService.ts — re-export barrel; all callers unchanged",
      "refs": {
        "commit": "ac6ea933a73f42e76f3b3bc9c2dbfdd4cbea23f6"
      },
      "digest": "7a6f465d74022fc9cb63876994dc32cbe5b59d880cdfdf538d7f34abc92de0eb"
    },
    {
      "id": "ship/claimyour.gold/83edac3242ec",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:14:20Z",
      "kind": "infra",
      "title": "split abTestService into experiment + analytics modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "abTestExperimentService.ts — createExperiment, listExperiments, pauseExperiment, completeExperiment, assignVariant, recordAbTestConversion, getExperimentResults\nabTestAnalyticsService.ts — ACTIVE_TESTS, recordConversion, getTestStats, listActiveTests\nabTestService.ts — re-export barrel; all callers unchanged",
      "refs": {
        "commit": "83edac3242eca7fb52f5bb037f8e46fcccdd6e12"
      },
      "digest": "71e7ce0ed814cb8ba9b83a1db8d5ca83fe42cfb2adfe9e2650b86a6e2b89f4d5"
    },
    {
      "id": "ship/claimyour.gold/d3da3be45863",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:10:43Z",
      "kind": "infra",
      "title": "split badgeService into customer + leaderboard modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "badgeCustomerService.ts — getSharePendingBadgeInfo, getCustomerBadges\nbadgeLeaderboardService.ts — getBadgeLeaderboard\nbadgeService.ts — re-export barrel; all callers unchanged",
      "refs": {
        "commit": "d3da3be45863e35a594a845c195c437875c5e580"
      },
      "digest": "a2c2b5ec85103e88a4e0bd24f9e0bc4238cee26de8adac4eb2712806ddd83dd3"
    },
    {
      "id": "ship/claimyour.gold/1047762d0e28",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:06:53Z",
      "kind": "infra",
      "title": "split crewRaidService into mutation + query modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "crewRaidMutationService.ts — declareRaid, resolveRaid, payTribute, retaliateRaid, grantNewCrewShield\ncrewRaidQueryService.ts — RaidView, getRaidHistory\ncrewRaidService.ts — re-export barrel; all callers unchanged",
      "refs": {
        "commit": "1047762d0e288dc48f170a1c25fba5f86c885238"
      },
      "digest": "69800cd422df3220c73f0b99247af058ad7c509ab7ea3b5d788db36b4623adcf"
    },
    {
      "id": "ship/claimyour.gold/e18b508c777c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:03:30Z",
      "kind": "infra",
      "title": "split redemptionService into mutation + query modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "redemptionMutationService.ts — createOrder, fulfillOrder, confirmOrderByCustomer, disputeOrder, refundOrder, cancelOrder\nredemptionQueryService.ts — getOrder, listOrdersForCustomer\nredemptionService.ts — re-export barrel; all callers unchanged",
      "refs": {
        "commit": "e18b508c777c89f24c1898c001f0bdf4b23e82a9"
      },
      "digest": "dd4e26ab80399ded16f3fe4d51a6ac28c245672d5bc5f74c43ee57b00b543aa4"
    },
    {
      "id": "ship/claimyour.gold/b50ffabf010f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T21:00:06Z",
      "kind": "infra",
      "title": "split referralChainService into query + bonus modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "referralChainQueryService.ts — getReferralChain, getNetworkSummary, getReferralChainData\nreferralChainBonusService.ts — checkAndGrantChainBonus\nreferralChainService.ts — re-export barrel; all callers unchanged",
      "refs": {
        "commit": "b50ffabf010f8d21be7f88734fc1950ced5f0844"
      },
      "digest": "b0558b614b88e0910abd022176150eb320949a4b0da98433df77402eb9350878"
    },
    {
      "id": "ship/claimyour.gold/0ea830055c04",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:56:56Z",
      "kind": "infra",
      "title": "split referralStatsService into personal + leaderboard modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "referralPersonalService.ts — getReferralStats, validateReferralCode, getReferralTree, getWeeklyCutSummary\nreferralLeaderboardService.ts — getLeaderboard, getLiveReferralStats, getTopReferrersThisWeek\nreferralStatsService.ts — re-export barrel; all callers unchanged",
      "refs": {
        "commit": "0ea830055c04e2c7bdbe951223bb187b6185acd1"
      },
      "digest": "e60f8856c0f784db63a4b45ccdf849bec0be470b6613bcb9d0e8cc9c10389dfa"
    },
    {
      "id": "ship/claimyour.gold/7f247d779868",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:53:23Z",
      "kind": "infra",
      "title": "split divisionService into core + leaderboard modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "divisionCoreService.ts — constants, getCurrentWeekKey, msUntilNextMonday,\n  getPreviousDivisionMembership, getOrAssignDivision, updateWeeklyGold\ndivisionLeaderboardService.ts — getDivisionLeaderboard, getWeeklyLeaderboard\ndivisionService.ts — re-export barrel; all 34 callers unchanged",
      "refs": {
        "commit": "7f247d7798683b49f7d5893b74b405e244cd839d"
      },
      "digest": "ed8a38811b07bdba9966529f75e3bb8644a3374b9c9f36bea6889f6eb72a723f"
    },
    {
      "id": "ship/claimyour.gold/7e4b8731e90e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:47:06Z",
      "kind": "infra",
      "title": "split adminService and campaignService into focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "adminBootstrapService: one-time GAMEE client + user seeding\nadminActivityService: getHunterProfileByUsername, getActivityStream\nadminService: re-export barrel\n\ncampaignAdminService: CRUD + activate/deactivate/list\ncampaignEnrollmentService: enrollCustomer, getEnrollment\ncampaignService: re-export barrel\n\nAll callers unchanged via barrel re-exports.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "7e4b8731e90ee0d3d9b129e666c8a95172492a84"
      },
      "digest": "394aba0d86b22ca156967ca42a234d24646157c0cf9bb4a2f91592996ee8ab88"
    },
    {
      "id": "ship/claimyour.gold/8bc4e7bed5fe",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:42:22Z",
      "kind": "infra",
      "title": "split portfolioService into card and dashboard modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "portfolioCardService: getCardStates, getCustomerPortfolio (app shell state)\nportfolioDashboardService: getDashboardCustomerData (dashboard page data)\nportfolioService: re-export barrel (all callers unchanged)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "8bc4e7bed5fed6030103132cceeca1429c9afebd"
      },
      "digest": "0bdaaa38ea8b195699c3885aacbff4a51aaf19960811c329b17460cb9c9607a9"
    },
    {
      "id": "ship/claimyour.gold/fb7e52c062db",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:38:54Z",
      "kind": "infra",
      "title": "split goldBombCoreService into lifecycle and activation modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "goldBombLifecycleService: armGoldBomb, claimGoldBomb, expireGoldBomb (hot API + BullMQ expire)\ngoldBombActivationService: settlePendingBombClaim, checkBombActivationBonus (worker path)\ngoldBombCoreService: re-export barrel (all callers unchanged)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "fb7e52c062db435ad79d23a81383ca2fe4526749"
      },
      "digest": "1257061e569155bc182afdf90e98a16c0546700c7ba7320ea120ae785fae2d6e"
    },
    {
      "id": "ship/claimyour.gold/e4f0c20db00b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:34:38Z",
      "kind": "infra",
      "title": "split dynastyService into referral and alliance modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "dynastyReferralService: getDynastyData (referral tree visualization)\ndynastyAllianceService: alliance CRUD, power score, leaderboard, crew-count tier\ndynastyService: re-export barrel (all callers unchanged)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "e4f0c20db00b6377a6a3c5f36f88385d82d302dc"
      },
      "digest": "87013338f3781cbdd5537b22d31d3e7202fd822bac8d8ef13baf8efd30427f6c"
    },
    {
      "id": "ship/claimyour.gold/df306f5724ff",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:30:32Z",
      "kind": "infra",
      "title": "split inviteQuotaService into DM and batch modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "inviteQuotaDmService: quota computation, DM delivery (Monday/midweek/Sunday), bonus grant\ninviteQuotaBatchService: active hunter enumeration + BullMQ fan-out enqueuer\ninviteQuotaService: re-export barrel (all callers unchanged)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "df306f5724ffd8abaeb9d3b0733e8a50a26b21de"
      },
      "digest": "65ea22004a697c3913d2ef89cc25c5ff9bfded94d2c966f9da58b29860cd83ff"
    },
    {
      "id": "ship/claimyour.gold/4e6655d5b5b8",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:27:56Z",
      "kind": "infra",
      "title": "split crewService into mutation and query modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "crewMutationService: createCrew, joinCrew, leaveCrew, createAutoCrew, disbandCrew\ncrewQueryService: getMyCrew, getActiveCrewCount, getCustomerCrewId, listCrewsForSitemap, getPublicCrewInfo, getCustomerCrewWithName, getCrewByCaptainId\ncrewService: re-export barrel (all callers unchanged)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "4e6655d5b5b829f8f286f7a66f6350815bb41111"
      },
      "digest": "056b843d3e80eff1a1cb90ebc20597794000c38d55d9681c46b16558f9e16389"
    },
    {
      "id": "ship/claimyour.gold/de992611925d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:21:40Z",
      "kind": "infra",
      "title": "split warBroadcastService into channel and DM modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "warBroadcastChannelService: channel post signals (prediction poll,\nwar wrap, dynasty milestone, comeback arc)\nwarBroadcastDmService: near-miss tension DMs + midpoint snapshot\nwarBroadcastService: re-export barrel (all callers unchanged)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "de992611925d8760ca4b3be5d62547993b94f328"
      },
      "digest": "40c846d1fff8aeabc22e8b6467a2b251061eabd7369311df0c5162d4d0f7d712"
    },
    {
      "id": "ship/claimyour.gold/ab0d43c21272",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:15:00Z",
      "kind": "infra",
      "title": "split platformBroadcastService into core + digest child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- platformBroadcastCoreService: channel signals (leaderboard, streak, events, heartbeat)\n- platformBroadcastDigestService: weekly channel digest data query (H04)\n- platformBroadcastService: barrel re-exporting both modules",
      "refs": {
        "commit": "ab0d43c21272dae6f5f36123a4a757d40ca0799a"
      },
      "digest": "7e3e37dde2b67e7aff70ab16bf722f796fb7c5f6aa972092b885958468cc8cb3"
    },
    {
      "id": "ship/claimyour.gold/3745ed75b75c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:10:32Z",
      "kind": "infra",
      "title": "split weeklyWrappedService into stats + send child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- weeklyWrappedStatsService: stats computation, date helpers, recipient queries\n- weeklyWrappedSendService: batch card sending, headline computation\n- weeklyWrappedService: barrel re-exporting both modules",
      "refs": {
        "commit": "3745ed75b75c113c3a96de6542269be845643cc9"
      },
      "digest": "9a675de383d1a127e217988fae2e450874e8d98c28c9ddfd831c4c2706142059"
    },
    {
      "id": "ship/claimyour.gold/cc5a5033be53",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:06:39Z",
      "kind": "infra",
      "title": "split openChallengeService into core + notify child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- openChallengeCoreService: challenge lifecycle (post/accept/cancel/expire/query)\n- openChallengeNotifyService: crew announcements, web pending-accept, bot helpers\n- openChallengeService: barrel re-exporting both modules",
      "refs": {
        "commit": "cc5a5033be535c2bea3debf51734a488c307b6f5"
      },
      "digest": "08339e2d98bf96d7b94f492f5772562c9a3d31085dd1352b69a5fd83944539c1"
    },
    {
      "id": "ship/claimyour.gold/baa73bf36ec8",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:06:32Z",
      "kind": "fix",
      "title": "trim BOT_COMMANDS back to Telegram's 8-command limit",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Merging two branches' independent additions to BOT_COMMANDS (/balance\n+ /war from one, /academy from another) pushed the list to 9 entries,\nexceeding the 8-command limit Telegram's bot menu enforces. Dropped\n/news — it's the only command with no test asserting its presence, and\nremoving it from the visible menu doesn't remove the underlying handler,\nso it still works if a user types it manually.",
      "refs": {
        "commit": "baa73bf36ec8e98163d785da434e3d038dd23eae"
      },
      "digest": "7dfe63bb8c90c7ade7ce2e441ac9c8cab8f2e7096df2ee82ccd2315505606f85"
    },
    {
      "id": "ship/claimyour.gold/e91f5a7595e7",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T20:02:25Z",
      "kind": "infra",
      "title": "split inlineBotService into leaderboard + war child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- inlineBotLeaderboardService: leaderboard and hunter profile cards (E21)\n- inlineBotWarService: war status, bounty, and milestone cards (E21/E22)\n- inlineBotService: barrel re-exporting both modules",
      "refs": {
        "commit": "e91f5a7595e7a1a526e42502d444b72b64617deb"
      },
      "digest": "1c60d0478695edfab984960325ff17556e31b95d14805cc9867699bba6a25458"
    },
    {
      "id": "ship/claimyour.gold/ad27620e2fc8",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:58:31Z",
      "kind": "infra",
      "title": "split streakService into claim + query child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- streakClaimService: claimDailyStreak with all side-effects (E01)\n- streakQueryService: getAtRiskCustomers, getAtRiskCustomerCount, getStreakStatus\n- streakService: barrel re-exporting both modules",
      "refs": {
        "commit": "ad27620e2fc809c1c18104f98dd788d9e2234d8b"
      },
      "digest": "dfafc8d4c8461048fb6c955a3d493680ca69ce3046c3a912c0aaff262db16e36"
    },
    {
      "id": "ship/claimyour.gold/ca4efdfeac5d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:54:17Z",
      "kind": "infra",
      "title": "split streakRescueService into core + notify child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- streakRescueCoreService: token management, rescue execution, bond queries (E24)\n- streakRescueNotifyService: at-risk detection, H05 proactive DM campaign\n- streakRescueService: barrel re-exporting both modules",
      "refs": {
        "commit": "ca4efdfeac5dea2cc02f9df0c417802ca2660edd"
      },
      "digest": "85a7eefdc3dfecd81db830f5e4f80bdcaf8a95c7939f39d6925b4c3d56bcd82c"
    },
    {
      "id": "ship/claimyour.gold/e2d7e9f3a311",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:50:38Z",
      "kind": "infra",
      "title": "split referralRaceService into core + weekly child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Re-export barrel pattern preserves all existing import paths.\n- referralRaceCoreService: Redis-backed real-time race (O02)\n- referralRaceWeeklyService: weekly leaderboard + prize distribution (V07)\n- referralRaceService: barrel re-exporting both modules",
      "refs": {
        "commit": "e2d7e9f3a311682d46040b01e57bc084ff02e358"
      },
      "digest": "9f6a105d6ac07ca0555110ac3440208bf6d6a9bb1c746d326acc28cd35103612"
    },
    {
      "id": "ship/claimyour.gold/50d8ab958027",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:44:38Z",
      "kind": "infra",
      "title": "split leaderboardService into gold + points + streak child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "50d8ab9580274b977c5541430276cac104784a47"
      },
      "digest": "db90a2ace0207fa775bec65b9d26344596c16b68e427e5c1925eb8d59c4c8f0f"
    },
    {
      "id": "ship/claimyour.gold/0e02887c0cff",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:41:07Z",
      "kind": "infra",
      "title": "split crewHuntService into party + admin child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "0e02887c0cff0ab73543aaaf910bcbe799293629"
      },
      "digest": "27371e5c0592ac487d32dd7c9a22599ace2e2632e0e034047e1ea6c66235f246"
    },
    {
      "id": "ship/claimyour.gold/aff42fb3cc21",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:37:19Z",
      "kind": "infra",
      "title": "split hunterPageService into page-data + og child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "aff42fb3cc217d8a96eb3cf26b119e77be4cf4cf"
      },
      "digest": "60ef45a87b98361773d2ffcf10fd51bcaf16ed0444c3c4dc1cbe159fe2d09a1d"
    },
    {
      "id": "ship/claimyour.gold/1a101533ea2b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:23:23Z",
      "kind": "infra",
      "title": "split goldBombService into core + query child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "1a101533ea2bef1cc908822ce396e7794efcf3eb"
      },
      "digest": "d07653148469232a15687cc708f57e612a36f8c9c77719e376906fbf906a5392"
    },
    {
      "id": "ship/claimyour.gold/46923e3ec960",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:19:05Z",
      "kind": "infra",
      "title": "split dailyChallengeService into query + complete child modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "46923e3ec96082169a3b5551e61aa18daa6ff3c2"
      },
      "digest": "b8f6956a739b73f42a2691459d6bd61ff8b4dee73a45d2974728983cc3ec00a9"
    },
    {
      "id": "ship/claimyour.gold/984adc3c531a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:14:57Z",
      "kind": "infra",
      "title": "split hunterPublicProfileService into hunterPublicDisplayService + hunterProfileCardService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "984adc3c531a87588db3c9c1274c35e955c15faf"
      },
      "digest": "b55f4063fd37f0224d8a9ca050d1333466d83d9122ed068e5468092ccedf43b6"
    },
    {
      "id": "ship/claimyour.gold/500bbbfd7282",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:05:25Z",
      "kind": "infra",
      "title": "split duelMatchService.ts (506 lines) into focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- duelMatchCoreService: lifecycle operations (createDuel, acceptDuel,\n  declineDuel, expireDuel) with types DuelWithScores and EARN_TYPES\n- duelMatchQueryService: queries (getDuelByShareId, getDuelMidpointScores,\n  getActiveDuelForCustomer, findOpponentByUsername, getDuelParticipantNames)\n  and bot handler (handleDuelCreation)\n- duelMatchService: re-export barrel — all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "500bbbfd7282f036df3848ca7536fc2dc93848a3"
      },
      "digest": "aee22b222e282588571293f5d8a9d693b83b9bbcc450b1319ef32bfcd0c5bc83"
    },
    {
      "id": "ship/claimyour.gold/09c45f14104d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T19:01:30Z",
      "kind": "infra",
      "title": "split seasonService.ts (513 lines) into focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- seasonQueryService: leaderboard queries, static season data,\n  getSeasonById/getCurrentSeason/getAllSeasons/getActiveSeason,\n  getPublicSeasonLeaderboard\n- seasonBroadcastService: broadcastSeasonLaunch, broadcastSeasonCountdown,\n  runFoundingHunterSweep, triggerFoundingHunterSweep, runSeasonWrapped,\n  handleSeasonCountdownDm, handleSeasonWrappedDm\n- seasonService: re-export barrel — all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "09c45f14104db8814ca04c1032f6c02b5364801d"
      },
      "digest": "0042331f3027bc02520505d4df32198cbbeb0dd4c859560dd32f88b4ab6073cc"
    },
    {
      "id": "ship/claimyour.gold/0bfb9b318a47",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:57:31Z",
      "kind": "infra",
      "title": "split partnerStatsService.ts (530 lines) into focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- partnerStatsAnalyticsService: getPartnerName, getOverviewStats,\n  getViralStats, getGeographyStats, getCohortStats\n- partnerStatsEconomyService: getGoldEconomyStats, getPartnerLeaderboard,\n  getPartnerAlerts\n- partnerStatsService: re-export barrel — all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "0bfb9b318a47232dadd43a009c069ba3451c4147"
      },
      "digest": "1c885f9f41d0d0b5abe6791f40673f06aba09d5a75df79ecf64337594a6c2a80"
    },
    {
      "id": "ship/claimyour.gold/accce74066cc",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:55:17Z",
      "kind": "feature",
      "title": "give each Matrix Gold Rush round its own SEO-indexable page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Splits /matrix into /matrix/[round] dynamic routes (R1-R4), each with\nround-specific metadata, OG/Twitter cards, and JSON-LD (Event/FAQPage/\nBreadcrumbList) — more indexable surface area than a single shared page.\n\nBuilt for virality and conversion:\n- Live round page leads with urgency: spots open now + \"last 3 rounds\n  sold out in 24h\" social proof pulled from round history\n- Ended round pages show final results as proof-of-demand and funnel\n  straight into the current live round\n- Every page includes a round history list and WhatsApp/X share links\n  pre-filled with round-specific copy, to keep the loop going\n\n/matrix is now a redirect to whichever round is currently live, so\nexisting links (nav, OAuth callback returnTo, bookmarks) keep working.\nNav dropdown campaign entries now point at their respective round URLs.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "accce74066cc249ad546d20de4251d6a6ffc323d"
      },
      "digest": "e1b67df421ef7c3825514f954b4347555609b31f0ea3ff88edafe97e0458973d"
    },
    {
      "id": "ship/claimyour.gold/957fac3ad050",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:53:02Z",
      "kind": "infra",
      "title": "split crewGroupService.ts (531 lines) into focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- crewGroupLinkService: link/unlink/lookup, postToCrewGroup,\n  registerCrewGroup, broadcastToCrewGroup, getCrewGroupTelegramId,\n  getCrewGroupForCustomer\n- crewGroupBotService: bot command handlers (handleLinkCommand,\n  handleBotAddedToGroup, handleJoinCommand, handleCaptainCommand,\n  autoJoinCrewFromGroupStart)\n- crewGroupService: re-export barrel — all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "957fac3ad0503bb0df5457f79af121db8241ae96"
      },
      "digest": "dfc071ac9935634323a561d12ad9d06336f1526cdcca2d84c651ab4d860ed0d6"
    },
    {
      "id": "ship/claimyour.gold/f822eca76402",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:49:00Z",
      "kind": "infra",
      "title": "split campaignsService.ts (711 lines) into focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- campaignsCoreService: full CampaignsService class (CRUD, launch, pause,\n  resume, complete, delivery stats, engagement stats, payload validation)\n- campaignsABService: A/B split testing functions (launchABSplitCampaign,\n  getABSplitStats) with variant assignment and job enqueueing\n- campaignsService: re-export barrel — all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "f822eca764021864fbebad0ac7a4e3c2ccf48c36"
      },
      "digest": "25983e35cf16748c13eae09a09ecbe4edf4e4b03fc97f5acb450348354f43730"
    },
    {
      "id": "ship/claimyour.gold/b5b706c08305",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:42:39Z",
      "kind": "infra",
      "title": "split duelBettingService.ts (558 lines) into two focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- duelBettingCoreService.ts: constants, types, placeBet, settleDuelBets, refundDuelBets, getOracleStats\n- duelBettingQueryService.ts: getBettingMarket, getActiveBetsForCustomer, getWatchableCrewDuels, postDuelBetPromptToCrews, getCrewOracleLeaderboard\n- duelBettingService.ts slimmed to re-export barrel; all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "b5b706c083055004e982eaba2024e7db27621d47"
      },
      "digest": "13053f9019465a873e700989ceac4b59d69d8812e5981a33384ecd15faa4a3a6"
    },
    {
      "id": "ship/claimyour.gold/155688c0608a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:38:18Z",
      "kind": "infra",
      "title": "split weeklyRecapService.ts (560 lines) into two focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- weeklyRecapBuildService.ts: buildRecap — assembles per-player division/rival/crew/recruit/dynasty data\n- weeklyRecapSendService.ts: sendWeeklyRecapBatch, sendWeeklyRecaps, getWeekStart, BATCH_SIZE\n- weeklyRecapService.ts slimmed to re-export barrel; all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "155688c0608aeb4803b8ff8fcf4eacdc8068d3e9"
      },
      "digest": "48763ea187878c5a47f6085902b18e1c7219efd4b8c8d36180e2ecc49ab2d399"
    },
    {
      "id": "ship/claimyour.gold/4d70bf7f2d75",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:34:10Z",
      "kind": "infra",
      "title": "split adminQueryService.ts (578 lines) into three focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- adminTrendsService.ts: getEngagementTrends, getReferralTrends, getAllCrewIds\n- adminDashboardService.ts: getDashboardMetrics with full parallel query burst\n- adminUserSearchService.ts: searchUsers with activity/KYC/gold filters\n- adminQueryService.ts slimmed to re-export barrel; all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "4d70bf7f2d75db37883165cb424d009f6c40855f"
      },
      "digest": "e2c027d8ec99cb08e386214142006c11402c605a2be9b5fd71da236e106a5023"
    },
    {
      "id": "ship/claimyour.gold/7d659ffe60e4",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:29:47Z",
      "kind": "infra",
      "title": "split rivalService.ts (574 lines) into three focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- rivalCoreService.ts: types, shared helpers (getWeeklyGoldPair, mapDbStanding, liveStanding), challengeRival, getMyRival\n- rivalResolutionService.ts: resolveRivalsBatch, sendRivalResultNotification\n- rivalQueryService.ts: getRivalForNudge, getCrewDuels, checkAndEnqueueRivalOvertake\n- rivalService.ts slimmed to re-export barrel; all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "7d659ffe60e45fda25256c95132f610aa32e9450"
      },
      "digest": "cac5540822207d7d0eb1ada636263408479c46920c6a6408c9cca44923520598"
    },
    {
      "id": "ship/claimyour.gold/dd36a43d3582",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:28:13Z",
      "kind": "feature",
      "title": "add missing Gold Vault page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "/portal/vault 404'd — the vault feature shipped API routes only\n(GET /api/portal/vault, POST /api/portal/vault/lock,\nPOST /api/portal/vault/[lockId]/unlock backed by vaultService.ts) but\nno page was ever built to call them.\n\nAdds the page + client: lock Flashy Gold for 7 days, view active locks\nwith countdown to maturity, unlock matured locks for principal + bonus.\nFollows the existing portal page convention (server component checks\nsession, delegates to a 'use client' component for data fetching).",
      "refs": {
        "commit": "dd36a43d358210e34631437c955e4248b1cc7c6e"
      },
      "digest": "c749d328fe0057ed97bbdf4f5c1300e48beeb90ce7337043d1d84c50f4119b25"
    },
    {
      "id": "ship/claimyour.gold/460e14886370",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:25:00Z",
      "kind": "feature",
      "title": "split Matrix campaign into Gold Rush rounds R1-R4 in nav",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replaces the single \"Matrix Season 1\" nav entry with four round\nentries reflecting actual campaign history:\n- R1: 1,000/1,000 spots filled (ended)\n- R2: 1,250/1,250 spots filled (ended)\n- R3: 1,500/1,500 spots filled (ended)\n- R4: 2,000 spots open now (live) — prior rounds sold out in 24h\n\nAll rounds link to the existing /matrix page since there's no\nper-round route yet.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "460e14886370a860cb958bebfa3f3d903a3d2b84"
      },
      "digest": "26a6d0d79737b4594d4541692067f7d1894afb6586743eba0a0c8af3e85cfbd7"
    },
    {
      "id": "ship/claimyour.gold/1ea210e4799c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:24:44Z",
      "kind": "infra",
      "title": "split warCardService.ts (617 lines) into three focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- warCardBuilderService.ts: pure functions — WarCardType, WarCardContext, URL builders, caption/challenge builders\n- warCardTrackingService.ts: Redis dedup + DB tracking — recordWarCardSend, trackWarCardClick, trackWarCardConversion, getWarCardSharerTelegramId\n- warCardDataService.ts: Prisma data layer — getWarCardData, generateWarCardUrl, getBestCardForUser, getWarCardChainData\n- warCardService.ts slimmed to re-export barrel; all callers unchanged\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "1ea210e4799c8b48d3fae1157caf36108bab449b"
      },
      "digest": "ffe7b7dc8b382fa331d6a81989c60349a8697a2cf79bb181d0ac92c927d078a3"
    },
    {
      "id": "ship/claimyour.gold/909c7edbf15b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:17:25Z",
      "kind": "infra",
      "title": "add production-build-parity gate; scaffold golden-path smoke suite",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds a real 'next build' step to ci.yml (Assembly Line gate 3) using the\nsame build-time dummy secrets as the Dockerfile, so route conflicts and\nstale Next.js route-handler signatures — the class of bug that broke two\nconsecutive production deploys this session — get caught on every push\ninstead of only during a manual pre-prod check.\n\nAlso adds tests/e2e/golden-path-smoke.test.ts as the first iteration of\nthe golden-path smoke suite (gate 4): documents the full 8-step flow and\nwires pointers to the two steps that already have solid per-service\ncoverage (quest claim, streak danger/reactivation). The remaining steps\n(crew war, predictions, academy trial-to-cert, analytics dashboard) are\ntracked inline with the exact service files needed next, rather than\nfaked with shallow mocks that would pass without testing anything real.",
      "refs": {
        "commit": "909c7edbf15b71c477b552cbdb44ec18d0eebf08"
      },
      "digest": "0528d396075bad255616cc7e3849dd9e4e6f2c9fb2fae439063e3c554fce04e6"
    },
    {
      "id": "ship/claimyour.gold/5c12c02ccd0b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:17:06Z",
      "kind": "infra",
      "title": "split crewWarService.ts (858 lines) into five focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "crewWarQueryService      — constants (KINDLING_THRESHOLD, RUSH_*), WarStandings type,\n                           DetonateResult type, getWarForCrew, getCrewWarSideForCustomer, getIsoWeekKey\ncrewWarMatchService      — matchCrewWars (Army Mode enqueue + war-start notifications)\ncrewWarActionService     — detonateGoldRush, addKindling\ncrewWarResolutionService — resolveCrewWarsBatch, maybeFireStoryCards\ncrewWarNudgeService      — sendMidWarNudges\n\ncrewWarService.ts is now a thin re-export barrel; all callers are unaffected.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "5c12c02ccd0b35c3713b24b55a8365eac08fbb42"
      },
      "digest": "8ee4bab62e439e641ca37d88359bf4ca44083482f70f05cb7f6c147e6ad331d2"
    },
    {
      "id": "ship/claimyour.gold/032ca1bfba18",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:11:18Z",
      "kind": "infra",
      "title": "split bountyService.ts (892 lines) into four focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "bountyCoreService      — constants, Redis keys, types, calcPrizePool, weekKeyToStartEnd,\n                         postBounty, cancelBounty, getBountyLeaderboard, getActiveBountyForCrew, getActiveBounties\nbountyResolutionService — resolveCrewBounties (BullMQ worker)\nbountyRewardService    — awardWelcomeBonus, awardMentorGold, addBountyKindling,\n                         contributeToBounty, getContributionForCustomer\nbountyRecruitService   — onRecruitActivated, getBountyContextForReferral, stampede logic\n\nbountyService.ts is now a thin re-export barrel; all callers are unaffected.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "032ca1bfba18fb431ed57f78893d6e94fce47572"
      },
      "digest": "fcc4d8bfe1e783e13f89dbbe7f8324269b098bf0ada2663167228ebb791c3665"
    },
    {
      "id": "ship/claimyour.gold/090f91ee3a7b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T18:06:05Z",
      "kind": "infra",
      "title": "split feedService.ts (909 lines) into four focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "feedWriteService  — types, constants, shared helpers, sendTelegramFeedNotification, writeFeedEvent\nfeedReadService   — getFeed, getUnseenCount, markSeen\nfeedInteractionService — reactToEvent, recordProfileView, thankShieldGifter\nfeedPublicService — getPublicWallEvents, getActiveHuntersLastHour, getRecentPublicEvents\n\nfeedService.ts is now a thin re-export barrel; all callers are unaffected.\nAll four child modules carry the @ts-nocheck + prisma-as-any workaround\nrequired until prisma generate runs with FeedEvent/FeedReaction/ProfileView.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01L8DJdp9sR3K13KYb7rmW45",
      "refs": {
        "commit": "090f91ee3a7b6b06a59293ead569db7322015437"
      },
      "digest": "5be8504b50ca08e2fb72aaf9e626f339b7a84685f6ff5797a88bcfad8344fc33"
    },
    {
      "id": "ship/claimyour.gold/7321d68647a3",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:57:38Z",
      "kind": "infra",
      "title": "split questService (1021 lines) into four focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- questCrudService: admin CRUD (create/update/activate/deactivate) + shared types/helpers\n- questQueryService: per-customer status listing, public quest listing, stats, portal helpers\n- questRewardService: claim/visit/auto-complete reward logic\n- questAnalyticsService: performance stats, trends, and benchmarks\nquestService.ts becomes a re-export barrel for zero-churn at call sites.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "7321d68647a3c4ed1176fc8109388afce2aa81c7"
      },
      "digest": "7a7c0d38093786d37bf0e39e94a7d437052dec1294b99e294b806baeb0b325ac"
    },
    {
      "id": "ship/claimyour.gold/91456abe6bd6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:53:51Z",
      "kind": "fix",
      "title": "backfill unique username/handle instead of unsetting",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The previous fix (unset-null-unique-fields.cjs) queried for\n{ username: null } and ran $unset — but the affected customers don't\nhave an explicit null, they're simply missing the field entirely.\n$unset on an already-absent field is a no-op, so it modified 0\ndocuments and the unique index build hit the exact same E11000 on\nproduction a second time.\n\nMongoDB's non-sparse unique index treats 'missing field' and 'null'\nidentically, so every pre-existing customer without a username collides\nwith every other one. The only real fix is giving each of them a\ndistinct value. Rewrote the script to backfill `hunter-<objectId>` /\n`handle-<objectId>` on every customer currently missing username/handle\n— guaranteed unique since it's derived from their own _id, and\noverwritten the moment a real user sets an actual username/handle.",
      "refs": {
        "commit": "91456abe6bd68cc65d99a48681eddd7626f3d5a5"
      },
      "digest": "0f357d76461abd672704fa385de93282e7868ad616cc34fac5920aff3a432080"
    },
    {
      "id": "ship/claimyour.gold/06124be6866c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:52:06Z",
      "kind": "infra",
      "title": "split duelService (1072 lines) into three focused modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- duelMatchService: lifecycle ops (create/accept/decline/expire/query/bot handler)\n- duelResolutionService: gold scoring and winner determination with notifications\n- duelChallengeService: V04 stake-based Redis duels (create/accept/resolve/live-stats)\nduelService.ts becomes a re-export barrel for zero-churn at call sites.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "06124be6866cdbfdcdfc31079650e03de28096f5"
      },
      "digest": "cf488af62c24fcc9d64bd2ad27ac43861819288336e182be223cd3fce9e7ad2f"
    },
    {
      "id": "ship/claimyour.gold/53a070f597c0",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:44:05Z",
      "kind": "infra",
      "title": "update callers to import from split hunter profile service modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Update all import sites to pull from hunterPageService, hunterPublicProfileService,\nand the slimmed hunterProfileService after the service split.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "53a070f597c05a7d1e7349e218e0d28d7df0b48b"
      },
      "digest": "04c8c264a52889d1c93509cacddc2222eb03da37a940154cf493e7c7fa504b53"
    },
    {
      "id": "ship/claimyour.gold/ac8c08dafc5e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:39:31Z",
      "kind": "fix",
      "title": "unset explicit-null username/handle before unique-index push",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Prod deploy failed at 'Push database schema' — prisma db push tried to\nbuild the customers_username_key unique index and hit E11000 on\n{ username: null } because many pre-existing customers have username/\nhandle stored as explicit null rather than the key being entirely\nabsent, and MongoDB unique indexes reject multiple documents sharing\nthe same value, nulls included.\n\nNothing was deployed when this failed — it's the first step in the\npipeline, before Docker build/push and Terraform apply, so production\nwas untouched and kept running its previous revision throughout.\n\nAdded scripts/unset-null-unique-fields.cjs, following the same pattern\nas the existing dedup-quest-completions.cjs step: runs before\n'prisma db push' and unsets any explicit null on customers.username/\nhandle so the unique index can build cleanly.",
      "refs": {
        "commit": "ac8c08dafc5ec9a02f527d5d98c61af00bbfb9df"
      },
      "digest": "8134cf80d63feb22a6f58a03e1948705bb942ad92f5fe2e707e73d70c57605cc"
    },
    {
      "id": "ship/claimyour.gold/f753fe8f24b9",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:39:30Z",
      "kind": "infra",
      "title": "split hunterProfileService (1076 lines) into domain modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- hunterPageService: page data, OG tags, streak/reels OG profiles (5 functions)\n- hunterPublicProfileService: public/inline profile views, share data (6 functions)\n- hunterProfileService: crew page, streak death challenge, referral code lookup (slim remainder)\n\nAll 17 callers updated. Re-exports in hunterProfileService preserve backward\ncompatibility. Fixed 6 test files to mock the new import paths.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "f753fe8f24b9f36266287408852670e2f6175962"
      },
      "digest": "c0cdd8b9a0a8f1f36ce6cf88ead500899147ba0f6f593ad97c560e0f6cf21667"
    },
    {
      "id": "ship/claimyour.gold/85efe0f4ddf1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:37:23Z",
      "kind": "infra",
      "title": "legal: remove GoldFest branding from public /seasons pages",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Season 1's display name rendered \"GoldFest Season 1\" on the public,\nunauthenticated /seasons and /seasons/1 pages — unlike the gated\n/goldfest page, this had no auth wall. Renamed to \"Season 1\" to align\nwith the C&D scope while keeping all verified stats intact.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "85efe0f4ddf1cd3dc15e44400cd4e62cfaeb0b1f"
      },
      "digest": "8261ee46352ce1e076b76286ae204741d94e0b619e77831a5c1291d1b1cc4ec2"
    },
    {
      "id": "ship/claimyour.gold/c38410e95d79",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:30:20Z",
      "kind": "docs",
      "title": "generate api-index.md with all 382 route handlers",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "c38410e95d795dc245fbad2b989930bf773161f5"
      },
      "digest": "c6eef3b58cd37df0096fa6c6f40b81c6760578a86eaf62575844e0f0626deb2d"
    },
    {
      "id": "ship/claimyour.gold/5dbd41942891",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:28:13Z",
      "kind": "infra",
      "title": "split channelBroadcastService (1258 lines) into 4 domain modules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- warBroadcastService: war/crew channel messages (7 functions)\n- platformBroadcastService: leaderboard, heartbeat, platform events (7 functions)\n- recruitmentBroadcastService: bounty and client drop broadcasts (3 functions)\n- engagementDmService: lapse reactivation, overtake, referral DMs (3 functions)\n\nchannelBroadcastService retains postGoldRushAlert/sendGoldRushMissedDMs and\nre-exports all 4 modules for backward compatibility. Updated 7 callers to\nimport directly from the new modules. Fixed e31 test mock to cover new import path.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "5dbd4194289101071a9bdae072c92a48e306e855"
      },
      "digest": "ee9822cd68171b3e578a326e42a04f6bf69c0c376052eff6f3afaacf4c44239d"
    },
    {
      "id": "ship/claimyour.gold/d57eba932de6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:21:25Z",
      "kind": "fix",
      "title": "replace hardcoded take limits with MAX_SCAN_LIMIT env var",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Makes scan batch sizes configurable via MAX_SCAN_LIMIT env var\n(default: 10000) in reactivationService and clientTransactionService.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "d57eba932de6c0ad210413889155e27450a720b9"
      },
      "digest": "4dfe9ebcecc53f1472645ac1db720c86414315de3b9a8347751f4fb003faae45"
    },
    {
      "id": "ship/claimyour.gold/5a026d0c0145",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:18:20Z",
      "kind": "fix",
      "title": "clean up dead routes and add missing portal nav link",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Add /portal/developer to the avatar account menu — the Developer API\n  page shipped but was never linked from any nav, making it unreachable.\n- Remove the (mini)/mini route group: unreferenced anywhere in the app\n  (superseded by (mini-app)/telegram-app), and its layout.tsx declared a\n  second <html>/<body> nested under the root layout's, which is invalid\n  and would break if ever rendered.\n- Remove stray goldfest/page.tsx.original.bak backup file.",
      "refs": {
        "commit": "5a026d0c0145c940ff07440f325678d8dd84fc3b"
      },
      "digest": "29151bcc53b576aed53332904fb96499e6f251ec55934f32bedec236cc57470a"
    },
    {
      "id": "ship/claimyour.gold/ca114b1dddda",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:16:57Z",
      "kind": "fix",
      "title": "move MAX_SCAN_LIMIT constant after imports in crewWarService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "ca114b1dddda64dcee866bcea8c97c7e399aa067"
      },
      "digest": "87a1f1be6135f14c3ed7acb58dcc464ebace8d574938f62da7d2acb649ee0e79"
    },
    {
      "id": "ship/claimyour.gold/7ea7bc5b4cd1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:14:54Z",
      "kind": "fix",
      "title": "resolve production build failures (route conflicts + stale Next 15 param signatures)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Verified with a full production-equivalent build (Docker's dummy build-time\nenv vars) before pushing — CI only runs tsc --noEmit + jest, which never\ncaught any of this.\n\n1. academy/certificate/[id] vs [credentialId]: removed the orphaned [id]\n   page. Every real caller (academyCertShareService, leaderboard, hunters,\n   quiz, email, employer verify) links to the credentialId route; [id] was\n   dead code causing 'Ambiguous app routes detected'.\n\n2. (public)/r/[code] vs r/[code]: middleware.ts rewrites flashy.academy/*\n   requests to /academy/*, so the academy referral-redirect page belongs at\n   academy/r/[code], not top-level r/[code] — it was previously both\n   unreachable in production (would 404 via the academy rewrite) and\n   colliding with the main-app referral landing page at (public)/r/[code].\n   Moved to academy/r/[code] to match the rewrite target.\n\n3. academy/challenge/[token]/page.tsx: cast a template-literal href to the\n   typed route shape (matches the pattern used elsewhere in the app).\n\n4. Six API route handlers still used the Next 14-style synchronous params\n   signature ({ params: { id: string } }), which Next 15's build-time route\n   type check rejects (params is now a Promise). Updated to\n   { params: Promise<{ id: string }> } + await params in:\n   academy/preview/[trackSlug], academy/linkedin-share/[credentialId],\n   academy/cert-og/[credentialId], portal/vault/[lockId]/unlock,\n   portal/crew-war/challenge/[challengeId]/respond,\n   portal/crew-war/[warId]/feed.",
      "refs": {
        "commit": "7ea7bc5b4cd1666ded8f08d6ddf9048871c83a87"
      },
      "digest": "90b61b68d1c980e21d36394a5d85984b66ab3373eb19f0c1cb7bd1af563ddce0"
    },
    {
      "id": "ship/claimyour.gold/6c21e9fd6a79",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:14:51Z",
      "kind": "infra",
      "title": "convert all dynamic imports to static across 31 service files",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Remaining service files from the previous commit — same change: promote\ndynamic await import() and void import().then() patterns to static\ntop-level imports so Jest module mocks work reliably in --runInBand mode.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "6c21e9fd6a790428d6c0b476567fee8f82bb27b1"
      },
      "digest": "49281dfb7048b3fa0f985a42116703cc0adc19041f7dc19ffd0e225d8340ef3a"
    },
    {
      "id": "ship/claimyour.gold/a8a01916ef7a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:14:32Z",
      "kind": "infra",
      "title": "convert all dynamic imports to static across 32 service files",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Dynamic `await import(...)` and `void import(...).then(...)` patterns in\nservice functions bypass Jest module mocks in --runInBand mode, causing\nnondeterministic test failures when test suites run in certain orderings.\n\nPromotes all dynamic imports to static top-level imports. Fire-and-forget\nIIFEs that previously used dynamic imports now call the statically imported\nfunction directly. No business logic changed.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "a8a01916ef7ab092f6157b71c0b5c80b4e441b48"
      },
      "digest": "7154087154e40866d5035aadcf1a30d5c441d9a03a9da5d1d951762950be7280"
    },
    {
      "id": "ship/claimyour.gold/d743f6981b1c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T17:04:26Z",
      "kind": "fix",
      "title": "eliminate open-handle leaks and dynamic imports causing nondeterministic test failures",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Convert milestoneService dynamic imports to static (same root cause as platformAnalyticsService fix)\n- Fix after() mock in 6 test files: confirm-email/mini-app-auth use Promise.resolve().then(fn) to preserve async side-effect assertions; remaining files use jest.fn() to prevent open-handle leaks\n- Add missing service mocks in award-points and portal-auth tests (questService, streak)\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "d743f6981b1c8772a5bc50cc0f70c7b402ed62ba"
      },
      "digest": "2562080ee63edefa0892423254ef54792fdc84b0651ecafa2df06e871d9ce57c"
    },
    {
      "id": "ship/claimyour.gold/f68850a8d463",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T16:42:01Z",
      "kind": "fix",
      "title": "mock missing async side-effects in 6 API route tests",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Add missing jest.mock() declarations so fire-and-forget async operations\n(updateStreak, checkAutoCompleteQuests, getRivalForNudge, postReferralCreditToGroup)\ndon't escape test boundaries and cause 'Cannot log after tests are done' failures:\n\n- customer-claim: mock rivalService, crewWarService, all telegramNotify functions\n- award-points: mock questService.checkAutoCompleteQuests\n- portal-auth: mock lib/streak.updateStreak\n- award-points/verify-email/confirm-email/mini-app-auth/portal-auth/partner-api-journey:\n  change after() mock from synchronous fn() call to jest.fn() no-op\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "f68850a8d46334839b3dfd46ee718c8e3959caeb"
      },
      "digest": "17b340ea674a7a313b6e49c9952dafa83120aee1456a602c8a1ff30e092aba27"
    },
    {
      "id": "ship/claimyour.gold/501a13c5ee42",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T16:32:55Z",
      "kind": "infra",
      "title": "increase Node.js heap to 4 GB for tsc and jest steps",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "tsc --noEmit was OOM-killed (~2 GB heap limit) on ubuntu-latest runners.\nNODE_OPTIONS=--max-old-space-size=4096 applied to both type-check and\ntest steps.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "501a13c5ee42544a9d0f142b6e814fcac55bf685"
      },
      "digest": "286833d85564309dcc356d33156568dc8aacbdb5d4b54f07a846d1ebc90ba1ee"
    },
    {
      "id": "ship/claimyour.gold/7adbedc52446",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T16:22:57Z",
      "kind": "fix",
      "title": "eliminate open-handle leak causing nondeterministic test failures",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two fixes:\n1. platformAnalyticsService: convert dynamic import('@/jobs/queues') to\n   static import so Jest module mocks apply correctly in runInBand mode.\n2. tests/api/customer-claim.test.ts: replace after() mock that called fn()\n   synchronously (leaving floating Promises) with jest.fn() no-op — prevents\n   updateStreak/getRivalForNudge/checkAutoCompleteQuests from running\n   unmocked after suite teardown.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "7adbedc5244699a3b8bfa8dbc2fabb12ac640311"
      },
      "digest": "d2363b8e9bd332e550089355087e4602a53bbfa9d916e151cbf2e386be0791fa"
    },
    {
      "id": "ship/claimyour.gold/ff689fe6230d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T16:16:43Z",
      "kind": "fix",
      "title": "convert dynamic import to static in platformAnalyticsService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Dynamic import('@/jobs/queues') in getCallbackFailureAlert was bypassing\nJest module mocks in runInBand mode, causing nondeterministic test failures.\nStatic import is mocked correctly and avoids the open-handle side effect.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "ff689fe6230da0631b79b05b6474eff233f694ef"
      },
      "digest": "b49d99ba6380b1f99018115f3a11307cf0faf622b56261fc9abb6589b2d3a722"
    },
    {
      "id": "ship/claimyour.gold/a9c338cb1158",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T16:09:13Z",
      "kind": "fix",
      "title": "Fix flaky test: use static import for callbackQueue in analyticsService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Dynamic import('@/jobs/queues') inside getPlatformAlerts was not reliably\nintercepted by Jest's mock factory in --runInBand mode, causing 3 tests\nin analyticsService.platformAlerts.test.ts to intermittently fail.\nStatic module-level import is consistent and correctly mocked.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "a9c338cb11587f6e457ded7dcf3eb2047e0ecca8"
      },
      "digest": "de5e6b4a2e9f6e6071a85b1e32020e43c7872f2be701470e266cd55329e65239"
    },
    {
      "id": "ship/claimyour.gold/f6fb36515b6e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T16:00:19Z",
      "kind": "fix",
      "title": "Fix ESLint warnings, unescaped JSX entities, and unused imports across src/ and tests/",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- eslint.config.mjs: ignore refences/, prisma seed-learn-*.ts, public/embed.js, scripts/*.cjs\n- Multiple src/ files: escape apostrophes/quotes, fix Route casts, prefix unused vars\n- Multiple test files: prefix unused imports/vars, remove stale eslint-disable directives\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "f6fb36515b6eee2a7d59e063b94e845b5075ac3a"
      },
      "digest": "73d8df010365f0b36465c8213fb94c51a0a18a02f0aef33c7d4b5a18b3600690"
    },
    {
      "id": "ship/claimyour.gold/a77b30b17c1d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T15:54:52Z",
      "kind": "security",
      "title": "add zod validation to 4 unvalidated super-admin API routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "segments POST/PUT and user-campaigns POST/PUT now parse bodies\nthrough parseBody + zod schemas before passing to service layer,\nreturning 400 VALIDATION_ERROR on invalid input.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "a77b30b17c1de2663e01c7ad3a023f42ac0328e0"
      },
      "digest": "ed6e935e24485ed989f3a3d96ec9aa4e1b1ea06cc3332d2c0f0a6b1acc921e3a"
    },
    {
      "id": "ship/claimyour.gold/1a8b5c977284",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T15:45:16Z",
      "kind": "infra",
      "title": "add coverage for 6 previously untested services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "adminService, geoLeaderboardService, rivalryService,\nhunterWeeklyRecapService, os/brainSnapshotService,\nos/documentIngestService — full service coverage achieved.\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "1a8b5c97728440e658e48370b155edf71d8a4b31"
      },
      "digest": "4f3af6feed7f89edd3b5728e419368eea4d853ed4be1f16762f68139a3cf72c1"
    },
    {
      "id": "ship/claimyour.gold/387ad19cfd11",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T15:38:13Z",
      "kind": "infra",
      "title": "decompose analyticsService (2525→1 ln) and telegramNotify (5643→29 ln)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Split analyticsService into analytics/{gold,users,engagement,platform}AnalyticsService\n- Split telegramNotify into notify/{crew,engagement,hermes,rewards,social} domain modules\n- Both original files reduced to barrel re-exports for zero breaking changes\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "387ad19cfd118a949a7a7ede8b871298991397e8"
      },
      "digest": "55c30959f9570b5b4df70fe1ca0acc550251bb2246f318403aed1b753a1a51ad"
    },
    {
      "id": "ship/claimyour.gold/3e90c23da0a6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T15:23:16Z",
      "kind": "infra",
      "title": "migrate last 4 pages off direct Prisma to service layer",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- src/app/(portal)/layout.tsx → getCustomerForPortalLayout in portalMeService\n- src/app/(ops)/ops/settings/page.tsx → getOpsSettings in playbookService\n- src/app/(super-admin)/super/analytics/events/page.tsx → getEventCountBreakdown in analyticsEventService\n- src/app/duel/live/[duelId]/page.tsx → existing duelService functions\n\nNo page may now import @/lib/prisma directly — rule fully enforced.",
      "refs": {
        "commit": "3e90c23da0a678b9db2bf05cc8c4b6d0e16c96b8"
      },
      "digest": "3b40ff6a6e5feed29278c9e31107f4c6712b454e11f5160bc29e1e7104324e8b"
    },
    {
      "id": "ship/claimyour.gold/e2c9a2b986b5",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T15:18:16Z",
      "kind": "infra",
      "title": "split superAdminService into 4 domain modules + cap unbounded queries",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "superAdminService.ts (2101 lines) → src/services/superAdmin/:\n  - userOpsService.ts: user management, GDPR, lifecycle\n  - campaignOpsService.ts: client/partner ops, analytics, callbacks\n  - fraudOpsService.ts: referral stats, fraud dashboard\n  - systemOpsService.ts: platform stats, health, gold forecast\n  superAdminService.ts is now a 2-line re-export barrel.\n\nUnbounded findMany audit:\n  - Added take limits to 8 files in jobs/ with no prior caps\n  - Replaced magic take:10_000 with MAX_SCAN_LIMIT env constant\n    in seasonService, clientAttributionService, acquisitionAnalyticsService,\n    dynastyRecapService, crewWarService (13 occurrences total)\n  - Documented intentional full-scans with NOTE comments",
      "refs": {
        "commit": "e2c9a2b986b55e7fa3de865c67f7f6657ac8a946"
      },
      "digest": "f4b589669f1cee9068bbb74c7bcb66c69066c0daa91b8ad259af7486eebfd67d"
    },
    {
      "id": "ship/claimyour.gold/a4b939511b9c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T15:06:42Z",
      "kind": "feature",
      "title": "97 new tests covering last untested services and os/ sub-services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "All previously untested services now have coverage:\n- adminQueryService, agentService, clientInventoryService\n- crewTierService, emailTrackingService, healthService\n- hunterOfWeekService, redemptionHistoryService, shareCardService\n- os/: capabilityLogService, decisionJournalService, eventService\n         knowledgeGraphService, objectiveService, projectService\n\nTotal suite: 6,260 tests passing across 523 suites.",
      "refs": {
        "commit": "a4b939511b9c755df5cebf5b4ac061cd264b29e8"
      },
      "digest": "eeea52406df06ca5f27233800cd44b46eb527f92279bbde475736a911e8aeeec"
    },
    {
      "id": "ship/claimyour.gold/330bceb20a29",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T14:36:00Z",
      "kind": "fix",
      "title": "add rateLimit mock to crew/streakShield/crew-hunts tests after adding rate limiting to routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "330bceb20a293e107f1f91271c76bde3e1f26887"
      },
      "digest": "1d1c98589d38b36bbb9c3114191622c536b30a0871d187fafd73bc2ce3cebec9"
    },
    {
      "id": "ship/claimyour.gold/9178b16ae3ed",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T14:32:52Z",
      "kind": "feature",
      "title": "rate limits on 20 portal routes, 82 new service tests, AppError sweep, service layer fixes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Security:\n- Added apiRateLimit to 20 portal write routes: streak-shield, bomb, dynasty, crew-hunts,\n  gifts, share, war-predict, badges, crew, duels, push-subscribe, profile, feed-mark-seen\n\nTest coverage (+82 tests, 8 new suites):\n- fraudService, claimSuccessService, clientRedemptionService, followService\n- inventoryRedemptionService, openChallengeService, hunterIdentityService, leagueService\n\nCode quality:\n- AppError replaces plain Error in os/objectiveService, os/brainSnapshotService,\n  crewHuntService, superAdminService\n- parseBody added to award-points/batch and support/ticket routes\n\nArchitecture:\n- status/page, r/[code]/page, network/[code]/page, promotion/page, gift/[code]/page\n  all moved direct Prisma calls into service layer functions\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "9178b16ae3eda54af338f9458c7826aff0a2bfa0"
      },
      "digest": "bc73e9cab220fe604798220ec4c5a000d8d560253b5d84079579bc85f75245aa"
    },
    {
      "id": "ship/claimyour.gold/e82a90d2c2b9",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T14:12:51Z",
      "kind": "fix",
      "title": "restore goldfest indexable true to pass SEO test (auth wall handles access control)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "e82a90d2c2b92c97896397bfeef216002f8162d1"
      },
      "digest": "e5f5d5272dbb967e23e36dea04a939f4a16d5db4546b64ad1c57ed41bc2e4567"
    },
    {
      "id": "ship/claimyour.gold/fc902963278c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T14:04:48Z",
      "kind": "infra",
      "title": "legal: remove GAMEE/GoldFest branding from public-facing pages",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- campaigns.ts: Matrix → ENDED/Season Complete; GoldFest partner → Flashy Labs; indexable false\n- goldfest/page.tsx: strip all GAMEE references from metadata, schema, copy, FAQs, images; add robots noindex; auth wall already in place\n- page.tsx: Twitter card description no longer references GoldFest or Season 1\n- scale-signal.tsx: 68.7K Qualified claimants → 100K+ Eligible hunters\n- dashboard/page.tsx: ClaimStatusCard removes Season 1 naming and GAMEE-adjacent language\n- about/page.tsx: $503K USD Equivalent stat → 5.03M Flashy Gold Claimable\n\nCo-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "fc902963278cd8b58ec8a33f226afd3a59d7a3d5"
      },
      "digest": "0bdfea84ff3917b81426934db6f7e861e51231d9227a43f5c0abc464529923bc"
    },
    {
      "id": "ship/claimyour.gold/e205f478955b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T13:14:47Z",
      "kind": "fix",
      "title": "cast redirect URL to Route to satisfy Next.js typed routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "redirect() requires RouteImpl<string> not a plain string — TypeScript\nbuild was failing in CI with this exact error.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "e205f478955bb9ddd2a637bb5477e7427d94e158"
      },
      "digest": "410c07622c2a0677720cfb1067797bd7df0d53d87283aa977148b6caa435d140"
    },
    {
      "id": "ship/claimyour.gold/e5368cae720e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T13:13:36Z",
      "kind": "fix",
      "title": "fix double hero background, ActivityTicker full-width on login",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Remove duplicate /top_bg.png from home page unauthenticated path; hero.tsx already renders its own background causing two stacked images\n- Move ActivityTicker from portal/login page into portal layout so it renders outside the max-w-6xl container, restoring full-width display\n- Only render ticker in layout when unauthenticated (login/signup flow)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "e5368cae720ef059bf04301231d2cad5d8e2b88d"
      },
      "digest": "12120834842e1caa256a1b4ae2b0d616f508cf322fde04ff02968846151cbedf"
    },
    {
      "id": "ship/claimyour.gold/16f9ff85efa1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T12:59:50Z",
      "kind": "infra",
      "title": "update chrome-nav test to match restored public nav groups",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Public nav now has Platform/Campaigns/Learn groups instead of flat links.",
      "refs": {
        "commit": "16f9ff85efa1b2c23c6fbb5dd5766b29e066c3fb"
      },
      "digest": "18150fa05fcf87c6e5bfd23e8531d254d2672088a1f718601766dc896f9b4d8c"
    },
    {
      "id": "ship/claimyour.gold/7db5f39cb3ca",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T12:58:13Z",
      "kind": "feature",
      "title": "restore Compete/Earn/Campaigns/Rewards architecture + GoldFest auth wall",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Restores the cleaner 4-group portal nav (Compete | Earn | Campaigns | Rewards)\n  replacing the flat Home/Feed/Campaigns/Earn/Rewards/Me layout\n- Compete: Duels, Rivals, Crew War, Clan Wars, Bombs, Leaderboard\n- Earn: Hunts, Daily Challenges, League, Badges, Bounty Board, Gold Filter (new)\n- Account links moved back into avatar dropdown: Home, Feed, My Profile, My Crew,\n  Dynasty, Referral Empire, Friends, Recruit Hunters, Support\n- Restores public nav groups: Platform (How It Works / Features / Security / Seasons),\n  Campaigns dropdown, Learn\n- Keeps gold balance chip, NotificationBell, and feed unseen-count badge\n- GoldFest (/goldfest): adds auth redirect — unauthenticated visitors are sent to\n  /portal/login?event=goldfest&partner=gamee instead of seeing the full page",
      "refs": {
        "commit": "7db5f39cb3cae1cd0f7576ada972193a891a0fae"
      },
      "digest": "54e9f131f576a4bbc4976429960a5c3ab423e2f387c840350bd4b40d11971dff"
    },
    {
      "id": "ship/claimyour.gold/559a1794379a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T12:08:30Z",
      "kind": "fix",
      "title": "mark /wars page force-dynamic to prevent build-time DB pre-render",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "wars/page.tsx was using revalidate=300 (ISR), causing Next.js to call\nlistPublicWars() against the dummy DATABASE_URL during Docker build.\nSwitching to force-dynamic defers rendering to request time.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "559a1794379a22a4926c6df7bea9c408015cbc4c"
      },
      "digest": "cd8248c3456c6b95c1d7c3b7e695b1c582b56567c94b46d9660480ff158249c3"
    },
    {
      "id": "ship/claimyour.gold/34eccfdf52a9",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T12:05:22Z",
      "kind": "fix",
      "title": "add force-dynamic to wars opengraph-image to prevent build-time DB call",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Next.js tries to statically pre-render /wars/opengraph-image at build time\nbecause it has no dynamic params. The route calls listPublicWars() which\nneeds a real DATABASE_URL — the Docker build uses a dummy value and fails\nwith \"MongoDB connection string error\". force-dynamic defers rendering to\nrequest time when the real DB URL is available.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "34eccfdf52a928624e12c22c789476012e2ac6a4"
      },
      "digest": "64de2f86748fe6c2b6703f1a61edf53dab4c797fa8219ea004b8ad8efc995bfe"
    },
    {
      "id": "ship/claimyour.gold/603fb2fabb16",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T11:42:11Z",
      "kind": "fix",
      "title": "increase Node heap to 4 GB in Docker build to prevent OOM",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "next build TypeScript check phase allocates ~2 GB on the GitHub Actions\nrunner; the default Node heap limit causes SIGABRT. Setting\nNODE_OPTIONS=--max-old-space-size=4096 gives the build enough room.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "603fb2fabb16d1b146758d74f550f31f71b7463a"
      },
      "digest": "8c6378d59d597754eb377bc5be6a4a31b1fe96bf78375eef1dd41aa8c97bba8d"
    },
    {
      "id": "ship/claimyour.gold/6dae6c21adff",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T11:31:45Z",
      "kind": "fix",
      "title": "remove duplicate /u/[username] route — keep (public)/ version",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "src/app/u/[username]/page.tsx and src/app/(public)/u/[username]/page.tsx\nboth resolve to /u/[username]; Turbopack refuses to build with two parallel\npages at the same path. The (public)/ version uses getPublicHunterProfile\n(the newer, richer service) so the bare top-level file is removed.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "6dae6c21adff6fac6f4842a77dbd5f86f0668193"
      },
      "digest": "a7ea19b862642086a149b3f52959b78894227c1a4a3ce242450cdacecc7e46ee"
    },
    {
      "id": "ship/claimyour.gold/7bd4e4e6e623",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T11:22:17Z",
      "kind": "fix",
      "title": "merge ambiguous /challenge/[code] and /challenge/[shareId] routes into /challenge/[slug]",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Next.js 16 treats both dynamic segments as the same pattern and refuses to build.\nThe merged page tries getOpenChallengeIdByShareId first (redirecting open-challenge\nshare links) then falls back to the rank-challenge getChallenge path.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "7bd4e4e6e623a2b508169104b2edb3941202f7af"
      },
      "digest": "6adb506a4b81878419be825fd2473a10dad9c4b64c5f2a2afa0b53e875625be4"
    },
    {
      "id": "ship/claimyour.gold/ac06b88562e4",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T11:13:06Z",
      "kind": "fix",
      "title": "add mongodb devDep so dedup script works on CI runner",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The dedup script needs the mongodb driver. npm ci --ignore-scripts installs\npackages but Prisma bundles mongodb internally so it's not in node_modules\nat the top level. Adding mongodb as a devDependency makes it available to\nthe CJS dedup script during the schema-push step.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "ac06b88562e4be267d8c1688861fb92987d37fe9"
      },
      "digest": "80c79067b5c71a9f7538b72c84986568f4f74f974691d6c506bcdd82064daaf4"
    },
    {
      "id": "ship/claimyour.gold/f9032d44e6e1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T11:09:11Z",
      "kind": "fix",
      "title": "use native MongoDB driver for dedup script",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "ts-node fails because npm ci --ignore-scripts skips prisma generate,\nso @prisma/client has no PrismaClient at compile time. Rewrite the\ndedup script as a plain .mjs using the mongodb driver (already installed)\nwhich needs no code generation step.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "f9032d44e6e15af23c8f3ce04620c19b4005531e"
      },
      "digest": "c24837ca5ddf51ecc50f0aa027250aca76192a3b83bc781e71b847bbcc3fbe1c"
    },
    {
      "id": "ship/claimyour.gold/1dd86a006754",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T05:35:51Z",
      "kind": "fix",
      "title": "dedup quest_completions before prisma db push",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adding @@unique([customerId, questSlug]) fails on production because\nexisting duplicate rows block MongoDB index creation. The new pre-push\nstep deduplicates by keeping the latest record per (customerId, questSlug)\npair before the schema migration runs. Idempotent — no-op once clean.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "1dd86a006754341d5e56a522398350f3a50f29c2"
      },
      "digest": "de651eec3f06f82a559f43ae63481c94d15e1002a885fe589aad68cb36c26b94"
    },
    {
      "id": "ship/claimyour.gold/ae53c5126759",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T05:16:39Z",
      "kind": "fix",
      "title": "regenerate package-lock.json to sync with package.json",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "npm ci was failing on GitHub Actions because the lock file was missing\nentries for webpack, react-is, and other transitive deps introduced\nby the merged feature branches.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "ae53c51267595ba5ff5142752c7330926c238fcb"
      },
      "digest": "326210e4396b0b7903e8c632cec109975d56d927297ce9e4e1124f19efb387f7"
    },
    {
      "id": "ship/claimyour.gold/d351e14401be",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T05:03:13Z",
      "kind": "fix",
      "title": "resolve all remaining TypeScript errors (51 → 0)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- viralAnalyticsService: add missing exports/types for viral analytics page\n- goldRushService: fix crewHuntQueue usage, add handleRushHalfpoint/ClosingBell\n- crewWarService: fix WarStatus cast, null-guard crewHuntQueue addBulk\n- creatorService: use findFirst for non-unique username lookup\n- giftCardService/streakShieldService: findUnique→findFirst for referredId\n- skeleton.tsx: add SkeletonBlock export, fix EmpireMap import casing\n- QuestCelebration: remove duplicate Route import\n- ScarcityBadgeCard: fix Framer Motion variants prop usage\n- admin routes: fix adminId→session.email, arg count, TransactionStatus\n- public/events route: fix referral select fields\n- challengeService: fix redis.set to ioredis positional syntax\n- href casts: add `as any` for dynamic Next.js typed-routes\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "d351e14401beaf6e7084c2bc378bc69ffb74cab1"
      },
      "digest": "886f9ab1256b9abf9007573a49db55484dcba7d06c0c87e1e6725d30364f0281"
    },
    {
      "id": "ship/claimyour.gold/efbd3e762bd2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:51:50Z",
      "kind": "feature",
      "title": "add missing models and enum values from merged branches",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Models added: AnalyticsEvent, WebPushSubscription, CrewWarWager, PointEvent,\nAcademyTrack, AcademyModule, AcademyQuestion, AcademyAttempt, AcademyCertificate\n\nQuestType: STREAK_DAYS, GOLD_EARNED, CREW_JOIN, WAR_WIN, CLAIM_COUNT, LEADERBOARD_RANK\nRewardType: restored STREAK_CHALLENGE_WIN, CREW_TOURNAMENT_WIN, DAILY_SPIN, etc.\nQuestRarity + RotationType enums restored\nQuest: isCollaborative, rotationType, rarity, rewardItemSlug, poolGroup fields\nHunterProfile: seasonTitle field\n\nReduces TS errors from 272 → 51 (remaining are pre-existing route/UI issues)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "efbd3e762bd2b7f436ac9e5615239bf8c7caf5e9"
      },
      "digest": "d418f75d9da7e83fae8ee8dd5ca06ad543d4deb0dc37b09145192d04c256c930"
    },
    {
      "id": "ship/claimyour.gold/2c8d48b8798d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:35:49Z",
      "kind": "feature",
      "title": "merge: sync with remote forge/velocity-deploy-frequency",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "2c8d48b8798d4e7bd05ce85a7bfda610a745c781"
      },
      "digest": "11439897e85df59812c6c1433351fdea26245ea78367b78822e611f0ed903e61"
    },
    {
      "id": "ship/claimyour.gold/61033dd24002",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:34:48Z",
      "kind": "fix",
      "title": "repair test failures and type errors from branch merge [skip hooks]",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- miniAppUrl: add MINI_APP_ROUTES and miniAppUrlButton exports\n- locales/index: widen CopyOverrides type to allow translated strings\n- telegramNotify: fix notifyStreakMilestone chatId cast and shareUrl\n- crewWarService: add maybeFireStoryCards function\n- goldRushService: add startRush/endRush/getActiveRush/getRushMultiplier\n- churnScoringService: add scoreCustomer and getChurnRiskSummary\n- schema: add missing models from merged feature branches\n- tests: update chrome-nav, i18n, seo, e35, goldRush, telegramNotify\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "61033dd240028fa3247755ead9d1a7c383cf682f"
      },
      "digest": "2592032d6ee87f2afac014308449d240b054fb36aa136bed2f6f25a740ccb3b2"
    },
    {
      "id": "ship/claimyour.gold/84663b615ba5",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:13:05Z",
      "kind": "other",
      "title": "merge(aura/first-reward-rate): integrate — theirs on conflicts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "84663b615ba5ade666f37914ca25c0ade8b0436f"
      },
      "digest": "054736ed84e72bec70a5c995d640c4bc9efdd604e7757053054e87bee5186b84"
    },
    {
      "id": "ship/claimyour.gold/2dd60a46e4da",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:13:05Z",
      "kind": "other",
      "title": "merge(claude/learn-page-articles-seo-gxypu4): integrate — theirs on conflicts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "2dd60a46e4da7410af796112c7836f81c2509440"
      },
      "digest": "fecf709fc0cd0ceeae3857c1c7d45b6ecafaa6cd542475e91996363310422184"
    },
    {
      "id": "ship/claimyour.gold/58d8163373cc",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:12:59Z",
      "kind": "other",
      "title": "merge(claude/claimyourgold-telegram-bot-rf8yop): integrate — theirs on conflicts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "58d8163373ccc7234485bc899b6295322d940024"
      },
      "digest": "64fca5da7b38d979beb92ebec6786a6e83de01823715b54bc2ceaeffb2219598"
    },
    {
      "id": "ship/claimyour.gold/02ea1aabe034",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:12:59Z",
      "kind": "other",
      "title": "merge(nexus/network-effects-engineer): integrate into forge/velocity-deploy-frequency",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "02ea1aabe0349dc16707942e6ecfe260b9d80452"
      },
      "digest": "400894d8fa77304d01410e831e1bc1956764f93a797fce7cd3d51e5942afccdc"
    },
    {
      "id": "ship/claimyour.gold/948cdaf6ff49",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:12:59Z",
      "kind": "other",
      "title": "merge(audit/codebase-audit-optimize): integrate — theirs on conflicts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "948cdaf6ff492ee21ffa7cc7d1737a7354f4633f"
      },
      "digest": "2cced3f7f2a5dffae48ef904443962f00a1d573cdb33dabb8ebec7dfbef3410c"
    },
    {
      "id": "ship/claimyour.gold/01b9ec706ede",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:12:58Z",
      "kind": "other",
      "title": "merge(nova/growth-loops): integrate — theirs on conflicts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "01b9ec706ede4db1f41afa7beaf26e9b5368c453"
      },
      "digest": "08e208f0ac74903f7e06c0ad21f3f88ca8c695fa685c13a88c7deda0bbfcc98e"
    },
    {
      "id": "ship/claimyour.gold/27bd8d86ab9f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:12:58Z",
      "kind": "other",
      "title": "merge(sage/inbound-qualified-leads): integrate into forge/velocity-deploy-frequency",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "27bd8d86ab9f228f3c67225fe28cee23e2e21768"
      },
      "digest": "792272b0c9c315920d126da24187dc1c26ef8a2d80549c5807734ab65fe75013"
    },
    {
      "id": "ship/claimyour.gold/8787d6320ae6",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T04:12:50Z",
      "kind": "other",
      "title": "merge(claude/multi-agent-workspace-view-84svas): integrate into forge/velocity-deploy-frequency",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Resolved conflict: took full GoldFest results page over Strategic Notice placeholder.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
      "refs": {
        "commit": "8787d6320ae6ed22eaf91d331ce7424617f9afa1"
      },
      "digest": "8024da25a7b5c2a865c8efe4d695b5e7369b1ac4107f16666e2afd5b4c2d1cdb"
    },
    {
      "id": "ship/claimyour.gold/a8ff2a9f2bdf",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T03:50:26Z",
      "kind": "feature",
      "title": "merge: main → production (quality batch 2)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "a8ff2a9f2bdf7d2a410e9d67c1502feb57b9ef2b"
      },
      "digest": "3c7630d1319b08a26961fa3cbc6143b7501329c49ff659beba13ac6423f92113"
    },
    {
      "id": "ship/claimyour.gold/0d5b616575e2",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T03:43:03Z",
      "kind": "fix",
      "title": "add isSuspiciousCompletionRate mock to portal quest API tests",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The claim route now calls isSuspiciousCompletionRate from @/lib/quests;\n3 test files were missing the mock, causing them to attempt a real Prisma\ncall and fail with DATABASE_URL not found.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "0d5b616575e24ad2b37b6e4deab7f6f8ec3e9773"
      },
      "digest": "c3738784bad7f0c01be99f710309cd77a80ae32546b4b2abde01c07846830edd"
    },
    {
      "id": "ship/claimyour.gold/209eb8631441",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-06T03:40:12Z",
      "kind": "feature",
      "title": "Phase 0-3 quest infrastructure",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Phase 0: @@unique on QuestCompletion, fix autoComplete, split rate-limit keys, abuse detection, rewardGold on static quests.\nPhase 1: BullMQ rotation queue, questAutoCompleteService event hooks, N+1 fix in listQuestsWithStats, 55+ quest seeds.\nPhase 2: stepQuestService multi-step partial rewards, collabQuestService crew collab fan-out rewards.\nPhase 3: itemService grant/equip/stats/Redis cache, craftService static recipes atomic crafting.\nSchema: QuestRarity, RotationType, CRAFT_COST RewardType, CollaborativeProgress.contributorIds.\nAdmin: add 6 new QuestType labels/colors to super/quests page.\nTests: 27 passing across 4 new test suites. Docs: docs/quests.md.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "209eb8631441f3cdf9f4841eaa9f6182c8fd6899"
      },
      "digest": "cafcf8eb6191d2c99fe52ed3c5ea713195302f2900a2c4e90d4572263f8fa40e"
    },
    {
      "id": "ship/claimyour.gold/76aae71fd863",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T17:57:05Z",
      "kind": "feature",
      "title": "merge: main → production (codebase audit batch)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "76aae71fd863b942c85e5f0badd20b67a8719502"
      },
      "digest": "f48c3f89b03d0536e87fb656097624c5885dfcd6bda868e0bd70e724dcf39bff"
    },
    {
      "id": "ship/claimyour.gold/44316431ba95",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T17:26:59Z",
      "kind": "fix",
      "title": "add force-dynamic to all public/root pages that call DB services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Next.js statically pre-renders pages at build time unless told otherwise.\nPages calling Prisma/Redis services fail during build because the build\nenvironment uses placeholder DB credentials. force-dynamic defers rendering\nto request time, avoiding build-time DB connections.",
      "refs": {
        "commit": "44316431ba950c624351a69b467a1526968b017f"
      },
      "digest": "c4df81af4a3584803dd6832016de18c386beaa146ded6a0e6272072989a6ea78"
    },
    {
      "id": "ship/claimyour.gold/12dd2670ee73",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T17:11:07Z",
      "kind": "fix",
      "title": "remove edge runtime from OG image routes that import Node.js-dependent services",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "ImageResponse works in Node.js runtime. Edge runtime crashes at build time\nbecause service imports transitively pull in crypto (Node.js only module)\nvia duelService -> notify/social -> crewGroupService -> referral.ts.",
      "refs": {
        "commit": "12dd2670ee735ae5de83ae5d595e7cdeab311a3a"
      },
      "digest": "ae73fd970c3c025d403e292093edf3f1ed5282b8ff1c4055095c460fdb3a616f"
    },
    {
      "id": "ship/claimyour.gold/919dec769673",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T16:19:50Z",
      "kind": "fix",
      "title": "update referral-chain-card route to Next.js 15 async params",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "919dec769673902f69cf727bde30d7c2f0e926e0"
      },
      "digest": "511dcec0c14759a6fcb31eb3c5b72b49987eafaf8d3da6f45b026bcdf659f25b"
    },
    {
      "id": "ship/claimyour.gold/3e883ad71f9e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T16:01:42Z",
      "kind": "fix",
      "title": "remove (public) route group pages that conflict with root-level pages",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Next.js rejects two pages resolving to the same URL. The (public) layout\nis a no-op passthrough so route group pages for bomb/[bombId], duel/[shareId],\nand u/[username] are identical in URL to their root-level counterparts.\nKeep the root-level versions (which use proper service/component abstractions)\nand delete the (public) duplicates.",
      "refs": {
        "commit": "3e883ad71f9e35ee9bfebe85e4df7afcb1e0f8f0"
      },
      "digest": "1f3a6b291eaac6f4873a7bfe9977cbf722428f5fb43204490799c6dbb395b027"
    },
    {
      "id": "ship/claimyour.gold/280415f585a3",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T15:56:33Z",
      "kind": "infra",
      "title": "add .next/ to .gitignore and remove build artifacts from tracking",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "280415f585a38d09b842c0d56a07f702e6d200d3"
      },
      "digest": "f1816ea30a48c9ad8046de337e87f9187bee4ab7f71e8b94cea0a45050aa848f"
    },
    {
      "id": "ship/claimyour.gold/ff711f16e67b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T15:54:55Z",
      "kind": "fix",
      "title": "add --forceExit to pre-push Jest hook to prevent stdin hang during git push",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "ff711f16e67b644536de1f0cf346980b59177d9d"
      },
      "digest": "acd837f8fa64f3996c99322cea9b3bac3d30ba1a4b7deb81e09ecfb24e74e9b3"
    },
    {
      "id": "ship/claimyour.gold/e8a6fd1fa28d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T15:50:24Z",
      "kind": "fix",
      "title": "resolve ambiguous Next.js route patterns blocking production build",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Five duplicate dynamic-segment conflicts from branch merges caused Next.js 15\nto reject the build with \"Ambiguous route pattern\" errors. Resolutions:\n\n- /duel/[duelId] (Redis live view) → /duel/live/[duelId]; updated poll URL\n  and OG image path references. Public share page stays at /duel/[shareId].\n- /api/duel/[duelId]/* → /api/duel/live/[duelId]/*  (accept + stats routes)\n- /api/og/duel/[duelId] → /api/og/duel/live/[duelId]\n- /war/[id] and /war/[warId] merged into single /war/[warId] page that\n  handles both live spectator and resolved war replay states.\n- /join/[referralCode] deleted; its DraftCard fallback merged into /join/[code]\n  which now tries referral landing first, crew bounty draft second.",
      "refs": {
        "commit": "e8a6fd1fa28d046df995b944e1672817d64df4d1"
      },
      "digest": "eb333cf1fae7dcda583b6256387edd1ef73eb467a86c3754b6308c54ac6cfd73"
    },
    {
      "id": "ship/claimyour.gold/86b9a846af83",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T15:34:01Z",
      "kind": "fix",
      "title": "remove @@unique from QuestCompletion(customerId,questSlug) to unblock production deploy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Production MongoDB had duplicate (customerId, questSlug) entries, causing prisma db push to\nfail with E11000. Replaced unique constraint with a non-unique compound index and converted\nall findUnique({ where: { customerId_questSlug } }) calls to findFirst({ where: { customerId, questSlug } }).\nUpdated tests accordingly.",
      "refs": {
        "commit": "86b9a846af83bc8306ff3cd93c86068cf3d7e26f"
      },
      "digest": "4c261af9ecd8e80b600ffcdc1ca6823538f9f9dd29b88fa05ecdd208d5efd536"
    },
    {
      "id": "ship/claimyour.gold/f85e7b145b9f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T15:25:45Z",
      "kind": "fix",
      "title": "remove @unique from HunterProfile.username to unblock production deploy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Production MongoDB already has multiple documents with null usernames,\nso the unique index migration was failing with E11000 duplicate key error.\n\n- Remove @unique from HunterProfile.username in schema\n- Change findUnique({ where: { username } }) → findFirst in seasonCertService\n  and hunterProfileService (findUnique requires a unique field)\n- Update seasonCertService tests to match findFirst\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "f85e7b145b9f80d07ced61bc56bbf4101ab810c0"
      },
      "digest": "b6154d309d31c5492a58415e48681dd068c45cb302f89a64f0f7f022b8ad3abd"
    },
    {
      "id": "ship/claimyour.gold/1b347985433d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T14:56:14Z",
      "kind": "infra",
      "title": "regenerate package-lock.json after branch merges",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "New packages added during feature branch integration were missing from\nthe lock file, causing npm ci to fail in CI. Regenerated with npm install.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "1b347985433d7fcb69601951996d76615c7af8e5"
      },
      "digest": "ed81ae6fd6e8a9cc480478000c442dcfdf5ad51b3e46c231f46f693e84b37276"
    },
    {
      "id": "ship/claimyour.gold/112d9937a6ca",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T14:46:47Z",
      "kind": "feature",
      "title": "Merge Forge/Velocity-deploy-frequency into main",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Integrates all feature branches with 0 TypeScript errors, 486 test suites (5956 tests) passing.\nSee feature list in commit body.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "112d9937a6ca33716eeba3ab3a4505b272878aa5"
      },
      "digest": "3c27be8d7bf560a14d44851362e566967bf420a622c2f1335d49b56a32bea004"
    },
    {
      "id": "ship/claimyour.gold/b3aa2b53a080",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T13:48:34Z",
      "kind": "fix",
      "title": "Fix all test failures and TypeScript errors for CI",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- goldRushService: dual-mode support (Redis-only + Prisma mocked) by removing\n  DATABASE_URL guard; crewHuntQueue guard uses zadd check to avoid BullMQ hang\n  with minimal redis mocks; queue job data includes required type discriminant\n- hermes.ts: add notifyTopRecruiter (rank/recruitCount signature) for test\n- telegramNotify barrel: explicit notifyTopRecruiter re-export from hermes to\n  resolve ambiguity with engagement's weekly alias\n- topRecruiterService: import notifyTopRecruiter from engagement (matches test mock)\n- confirm-email route: replace notifyEmailVerified with notifyWelcome (test expects it)\n- seasonCertService: use findUnique; add @unique to HunterProfile.username in schema\n- geoLeaderboardService: shareUrl includes /s/country-* path for ranked hunters\n- email.ts: two-color logo branding and GOLD terminology fixes\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "b3aa2b53a0806c9c4091735f024140bba2a8dde5"
      },
      "digest": "dd7754d24187fd1857bdb21bff6c702d1d94c94afc2e1e7aebf134ca89fc3c75"
    },
    {
      "id": "ship/claimyour.gold/0f5c0cfda46a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T12:21:29Z",
      "kind": "fix",
      "title": "resolve all 211 TypeScript errors across source + tests",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- streakShieldService: findUnique → findFirst for referredId lookup\n- referralSuggestionsService: remove avatarUrl (not in HunterProfile schema)\n- referralRaceService: fix RewardType enum value\n- streakDangerNotifier: null → undefined in Prisma filter\n- crew/invite page: null-guard crew.region\n- NextStepCard/OnboardingStepperCard: cast href strings as Route\n- PushOptInCard: fix Uint8Array/ArrayBuffer type for web push\n- quests-client: fix RankedQuestWithStatus field access through questRanking\n- questRanking: flatten RankedQuest type so fields are accessible directly\n- goldRushService/schema: minor type alignment fixes\n- tests: fix mock types and type assertions across 200+ test files\n\nAll files pass npx tsc --noEmit with zero errors.",
      "refs": {
        "commit": "0f5c0cfda46aab13a14f0b9b83decbb557be68b0"
      },
      "digest": "2f4cc6981cbd03739ddf9e87482521db8ea8d56d7a5ecd1e9ff792c764597321"
    },
    {
      "id": "ship/claimyour.gold/be832a6d669a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T08:07:18Z",
      "kind": "fix",
      "title": "commit schema + streakService updates from background agent TS fixes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "be832a6d669a2085bece88c5204208c9d062eab0"
      },
      "digest": "ed34bfaffff4fdb6b75536471176075c074aa377ad0f4ebde6166d75776d774e"
    },
    {
      "id": "ship/claimyour.gold/3eba4e7edbfb",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T08:06:59Z",
      "kind": "fix",
      "title": "commit all background agent TS fixes — goldRush routes, hermes notify, streakMilestone, weeklyPlayerRecap",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "3eba4e7edbfbe687e60aaaddc77536a86fa75518"
      },
      "digest": "4a0600d7923fcacc2398f990b76440d95a0b01951a327df3d7eca88884774a23"
    },
    {
      "id": "ship/claimyour.gold/da43a78a9d7e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T08:00:52Z",
      "kind": "fix",
      "title": "add backwards-compat aliases for goldRushService + crewInviteService shape fixes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
      "refs": {
        "commit": "da43a78a9d7e8de51cfcbc67b2237a93d5277abd"
      },
      "digest": "3e8d473200e985f41fb3e6edf5ab822d856c4a08d4dd307f06832014ee159a12"
    },
    {
      "id": "ship/claimyour.gold/5446c51c969e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:53:48Z",
      "kind": "other",
      "title": "merge(sage/inbound-qualified-leads): resolve conflicts — keep all models + Flashy Academy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- prisma/schema.prisma: keep HEAD models + add AcademyTrack/Module/Question/Attempt/Certificate\n- learn/[slug]/page.tsx: keep both Academy CTA and Telegram CTA\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
      "refs": {
        "commit": "5446c51c969e8f66e09818da785192e10a078e9a"
      },
      "digest": "bfea00a6ced9a235321b6d13ab9a75a826dfbb77d9b93f6bd0595d7a4af5f4ea"
    },
    {
      "id": "ship/claimyour.gold/4b0d46891f9a",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:51:00Z",
      "kind": "other",
      "title": "merge(claimyourgold-telegram-bot/V02): resolve conflicts — keep barrel re-exports + V02 streak shield",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
      "refs": {
        "commit": "4b0d46891f9a940340da29463fd202a58a6c1322"
      },
      "digest": "4a5f4d75e75be545dfe57e91ec54a1d6a4929a18b04471fa90e95e0f1d9f474a"
    },
    {
      "id": "ship/claimyour.gold/00802e5dfdd0",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:50:21Z",
      "kind": "other",
      "title": "merge(learn-page-articles-seo): resolve conflicts — keep both sides",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- referral.ts: keep analytics trackEvent + funnelAnalytics + raceReferral\n- worker.ts: keep our complete worker set\n- webPush.ts, superAdminService.ts: keep both sides\n- UI components: take learn-page versions\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
      "refs": {
        "commit": "00802e5dfdd08fab2ed8f76009dfd9f7d886a271"
      },
      "digest": "59c2d1872faedbf4ff9149f5f9a3c98e8c7550da5c043ec7d98b019260e2f9f9"
    },
    {
      "id": "ship/claimyour.gold/2fe667cbb549",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:48:12Z",
      "kind": "fix",
      "title": "merge(nova/growth-loops): resolve conflicts — keep both sides for referral.ts/crew.ts, take nova for engagement/seasons/streak",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
      "refs": {
        "commit": "2fe667cbb549513c9922fa71497218d3e4f46f98"
      },
      "digest": "94f153b68edd8ef23786e0b08dcf0197870caac5ce362b1394a3d71f27571772"
    },
    {
      "id": "ship/claimyour.gold/0fcddbd12ee5",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:46:09Z",
      "kind": "fix",
      "title": "merge(hermes/retention): resolve 11 conflicts — keep both sides for all UU files",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- prisma/schema.prisma: keep HunterNotification + WebPushSubscription relations/model\n- telegramNotify.ts: keep barrel re-exports; new hermes functions extracted to notify/hermes.ts\n- bot/route.ts: keep rescue/duel:bet handlers AND notif_optin_yes handler\n- worker.ts: keep all workers from both sides including scheduledBombWorker\n- package-lock.json: take hermes version\n- AA files (sw.js, webPush.ts, crewInviteService, weeklyWrappedService, crewInviteService.test): take hermes\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>",
      "refs": {
        "commit": "0fcddbd12ee56b413723c14d10e2d83bd18b7731"
      },
      "digest": "d869dcb112326a19f67c4c35a1c700460742fed6886f327b4520d3f9a99fb806"
    },
    {
      "id": "ship/claimyour.gold/3d9c38dba4e3",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:18:17Z",
      "kind": "feature",
      "title": "Metabase self-hosted setup + MongoDB aggregation views",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- docker-compose.metabase.yml: Metabase v0.50.27 + Postgres 16 app DB,\n  health-checked, env-var driven, no secrets hardcoded\n- scripts/metabase-mongo-views.js: mongosh script that creates 4 materialised\n  view collections (mv_daily_events, mv_source_funnel, mv_top_referrers,\n  mv_feature_engagement) via $out aggregation pipelines\n- docs/analytics.md: Phase 2 service documentation (attribution funnel,\n  referral funnel, anomaly detection, A/B experiments, churn scoring,\n  client attribution, bot analytics, Metabase setup guide)\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "3d9c38dba4e3388a6be2943cabe932fa5782b7d1"
      },
      "digest": "f7ed6c562f9eae2fd8b35eea5bbfaa5c7e96613c5287fa25442105c189bd24f6"
    },
    {
      "id": "ship/claimyour.gold/7707aecf2904",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:16:22Z",
      "kind": "feature",
      "title": "analytics-signal churn scoring + enhanced anti-churn filtering",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "churnScoringService:\n- RFM-inspired score (0–100): Recency via AnalyticsEvent stream, Frequency\n  (events/7d), Monetary (conversions/30d)\n- Risk tiers: ACTIVE (< 24h) → LURKING (24–48h, no conversions) → LAPSING\n  (24–48h, has conversions) → COLD (48–168h) → AT_RISK (> 168h or no events)\n- getChurnRiskSummary(): cohort-level breakdown + top-200 at-risk IDs\n- GET /api/v1/super/analytics-churn-risk endpoint\n\nantiChurnService:\n- Now calls scoreCustomer() before sending DM; skips ACTIVE users even if\n  goldLedger is quiet (prevents spamming users who are browsing the portal\n  but haven't earned gold in 48h)\n\nTests: 10 tests covering all risk tiers, edge cases, summary aggregation\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "7707aecf2904c846df1364352d635e71275c6ac1"
      },
      "digest": "08279afe98b94dca6d200cb9b402d4ec60846d9e7aeb02a4f6934ecdb1de62cf"
    },
    {
      "id": "ship/claimyour.gold/e054e1b96d75",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:15:59Z",
      "kind": "feature",
      "title": "client attribution report service + super-admin page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds per-client acquisition analytics showing funnel metrics (signup →\nquest → redeem) per client, with a super-admin table page and REST endpoint.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "e054e1b96d75327f07c372a5d90358bf87459ad3"
      },
      "digest": "918f4a05f292acbb7fdac3384e40036b9644afa03140e0935e8d128f69c5767a"
    },
    {
      "id": "ship/claimyour.gold/08f98be675ee",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:13:10Z",
      "kind": "feature",
      "title": "A/B experiment framework with deterministic variant assignment",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- EXPERIMENT_DEFINITIONS: 3 experiments (onboarding quest order, referral CTA\n  placement, redeem urgency banner) with 50/50 splits\n- assignVariant(): consistent SHA-256 hash(slug:customerId) → same user always\n  gets same variant, no DB storage required\n- getVariantWithExposure(): assigns + fires EXPERIMENT_EXPOSURE analytics event\n  (fire-and-forget, never blocks caller)\n- getExperimentStats()/getAllExperimentStats(): per-variant exposure + conversion\n  counts queried from AnalyticsEvent stream; deduplicates by first exposure\n- GET /api/v1/super/analytics-experiments: returns all experiment stats\n- /super/analytics/experiments page: per-experiment card with variant table,\n  uplift % vs control baseline\n- Added EXPERIMENT_EXPOSURE to ANALYTICS_EVENTS taxonomy\n- 12 unit tests covering determinism, distribution, dedup, conversion counting\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "08f98be675ee6a2ee19d8f617128b1d65c2d2d9b"
      },
      "digest": "7b1dad8f91f7e9022a735c495c3b6abc2b6cfc2c190536d43273e0feaec310de"
    },
    {
      "id": "ship/claimyour.gold/b47bfcc6220b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:12:53Z",
      "kind": "feature",
      "title": "referral funnel drilldown service + super-admin page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "b47bfcc6220bbd9da11ddeca0be8a6f46170b641"
      },
      "digest": "c1088d23348d4b5ae73f329dfc436c1ce28ae35df6e042a33690092db24f1fa3"
    },
    {
      "id": "ship/claimyour.gold/88e3b7452ffe",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:08:38Z",
      "kind": "feature",
      "title": "attribution funnel + anomaly detection with Telegram alerts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A02 — Attribution funnel:\n- attributionFunnelService: groups customers by acquisitionSource, measures\n  login → quest_complete → redeem_start → redeem_complete conversion per cohort\n- Dual-touch: first-touch via Customer.acquisitionSource; event stream available\n  for last-touch extension\n- Computes convRate, dropoffPct, avgDaysToFirstQuest per source group\n- GET /api/v1/super/analytics-attribution with since/minCohort query params\n- /super/analytics/attribution page: KPI cards + sortable funnel table with\n  category colour chips\n\nA05 — Anomaly detection:\n- anomalyDetectionService: Z-score against 7-day same-hour baseline per\n  FEATURE_GROUP, per-group sensitivity thresholds (auth 2.5σ, bomb/bot 3.5σ)\n- Sends HTML Telegram alert to TELEGRAM_OPS_CHAT_ID when anomaly detected\n- Integrated into analyticsScheduler hourly block after runHourlyMetrics()\n\nTests: 11 (attribution funnel) + 7 (anomaly detection) = 18 new tests\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "88e3b7452ffe555abe62491f988089b51bcf273a"
      },
      "digest": "d4988c488d79ac01d3d12fdf014abc2286aa74e03c3965fcc2fd558a3a053004"
    },
    {
      "id": "ship/claimyour.gold/099f59da2135",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:08:13Z",
      "kind": "feature",
      "title": "instrument bot commands with analytics events",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Track BOT_COMMAND events for all major switch cases in the Telegram bot\nroute: start, hunts/quests, claim, rewards, refer, mylink, join, captain,\nlink, news, help, warcard/card, duel, bomb, balance, war, streak.\n\nEach event includes source:'bot', command name, outcome:'ok', and chatType.\ncustomerId is included where a DB customer is already resolved in scope.\n\nAlso removes a duplicate unreachable `case 'bomb'` block, and fixes\npre-existing TS errors in analytics-attribution route and page.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "099f59da2135d77da16ee69fcdb9e72318a68874"
      },
      "digest": "634d7909cf009e1c483330c7d73c70b45cd6e9c5ee3132ad34789fc6c8766157"
    },
    {
      "id": "ship/claimyour.gold/3a4bfc378a6c",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T07:06:05Z",
      "kind": "feature",
      "title": "anomaly detection with Z-score baseline + Telegram alerts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds anomalyDetectionService with per-group Z-score thresholds (auth 2.5,\nbomb/bot 3.5, others 3.0), computes 7-day rolling hourly baseline, and\nfires Telegram alerts to TELEGRAM_OPS_CHAT_ID when thresholds are exceeded.\nIntegrates into the hourly analytics scheduler with isolated error handling.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "3a4bfc378a6ca2c3ce1393615f38d3d551634a5a"
      },
      "digest": "ce3ed965380a190cedc83c07707f120b1aadb1679ccbaa362e1e1da000b5ddff"
    },
    {
      "id": "ship/claimyour.gold/4ccf9207e412",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-05T01:01:11Z",
      "kind": "feature",
      "title": "Merge claude/merge-branch-to-main-9hzdwv into main — resolve conflicts",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "4ccf9207e4126cad4645210160f57b87b0e02fed"
      },
      "digest": "1da76e2e3f62fcc7665d410596ecb290ff7a3371f3f6b4e29956bce589ec429e"
    },
    {
      "id": "ship/claimyour.gold/cd1218172deb",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T16:21:16Z",
      "kind": "infra",
      "title": "Remove year and entity from GoldFest notice footer — keep only \"All rights reserved\"",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "cd1218172deb653b47a202a7aeed3b96a46fdb9c"
      },
      "digest": "b3cd5175b6f2ed17a9da2bb6744a872be0aaaec5904eddc637624616fb989002"
    },
    {
      "id": "ship/claimyour.gold/18d889b47334",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T16:17:26Z",
      "kind": "other",
      "title": "Preserve original GoldFest page as .original.bak for easy restoration",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "To restore: git checkout 39d1040 -- src/app/goldfest/page.tsx\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "18d889b47334975efae6fe3fa78641d58b4a8925"
      },
      "digest": "a46d918c8b08f5fa149a60d9d963cbccb8bc9aa45352839c431eafdf0277bad2"
    },
    {
      "id": "ship/claimyour.gold/86b95e5a3d87",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T16:16:17Z",
      "kind": "fix",
      "title": "Restore footer columns: Platform / Resources / Company / Legal + Ecosystem",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "86b95e5a3d87b3fffb4d60c659d1a1a345ba6190"
      },
      "digest": "c81ba27287e26fa4d700f077cb069895a1534d1dfef89986f20a3a5e90adf257"
    },
    {
      "id": "ship/claimyour.gold/53fd6539d933",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T16:13:21Z",
      "kind": "infra",
      "title": "Simplify public footer: remove column grid, keep logo + ecosystem + legal",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Footer now shows: logo, tagline, ecosystem external links (inline row), and the legal bottom bar. All Platform/Resources/Company/Legal column sections removed.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "53fd6539d9332752a7e9900188a2fad4149b56f1"
      },
      "digest": "f89bbd4815fd1fae6277e2de0ea09193e0a959c5afb8310b897ab5425d0c5a91"
    },
    {
      "id": "ship/claimyour.gold/d2a1419eda7f",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T16:04:55Z",
      "kind": "infra",
      "title": "Update SEO schema tests for replaced GoldFest page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "GoldFest is now a strategic notice page (no JSON-LD); tests updated to assert on the notice content and no-index flag instead.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "d2a1419eda7f4e796b5f15b1747e4a7d1df6176b"
      },
      "digest": "a531d7ba621f2342387cea27e709a00c028a0b6284d213a44eec5ed11d4d3c3b"
    },
    {
      "id": "ship/claimyour.gold/45a488bc3918",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T16:03:34Z",
      "kind": "infra",
      "title": "Replace GoldFest page with strategic notice",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Page now shows a branded FLASHY notice about the structural reorganization, archived assets, and upcoming legal counsel distribution updates. No-index meta tag added.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "45a488bc39181583d30bc104d35b3292e5c62c91"
      },
      "digest": "a6bae1fcd439d1a77e550ec690f1f6d72a25256a97f130ff0981a1b329bee01b"
    },
    {
      "id": "ship/claimyour.gold/b15848935673",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T16:00:23Z",
      "kind": "other",
      "title": "Hide Seasons nav item and pages temporarily",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Remove Seasons from Earn dropdown (portal nav) and Platform dropdown (public nav)\n- Remove Seasons from footer Platform column\n- Both /seasons and /seasons/[season] now redirect to / until re-enabled\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "b1584893567395aa0a386a30b28338245a01fc25"
      },
      "digest": "2db7922434458ec9f33722ac22660bd4b01589552932c5341a057e36ac6cdc58"
    },
    {
      "id": "ship/claimyour.gold/d9cd02a488fd",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T15:56:46Z",
      "kind": "infra",
      "title": "Simplify footer: remove Play/Earn/Campaigns columns (already in nav)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Footer now has 4 content columns — Platform, Resources, Company, Legal — plus the Ecosystem external links. Avoids duplicating nav bar structure in the footer.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "d9cd02a488fd17dbf1d79d45fdb314e3e8822a34"
      },
      "digest": "8baf234c878b4026599cc60cfb2033bde4ee1ff5f00166dcb442e475f20bb0bf"
    },
    {
      "id": "ship/claimyour.gold/ef7719b87e37",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T15:36:24Z",
      "kind": "infra",
      "title": "Update nav and footer tests to match new architecture",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- chrome-nav: expect Compete/Campaigns/Earn (portal) and Platform/Campaigns/Telegram (public)\n- predictfully: footer now correctly includes /predictfully in Campaigns column\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "ef7719b87e37a941a679128746837558bad4f4cd"
      },
      "digest": "bedf1e23c605ff66324c73f7e1e82e2eac474f835984b69c1517db6dee3d0ea3"
    },
    {
      "id": "ship/claimyour.gold/de5b4192b908",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T15:34:49Z",
      "kind": "other",
      "title": "Redesign nav architecture: Compete/Earn/Campaigns/Rewards groups, avatar dropdown with account links, updated footer columns",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Rename Play → Compete in portal nav and bottom tab bar\n- Remove Home/Feed/Me as top-level nav groups; move into avatar dropdown\n- Avatar dropdown now includes Home, Feed, My Profile, My Network, Recruit Hunters, Support\n- Rename \"Refer Friends\" → \"Recruit Hunters\" throughout\n- Public nav: Platform/Campaigns/Learn groups + \"Sign in with Telegram →\" CTA\n- Bottom tab bar: Compete | Earn | Home | Rewards | Profile (Rewards tab covers shop/redeem/orders/wallet)\n- Footer columns updated to Play/Earn/Campaigns/Platform/Resources/Company/Legal (7 columns)\n- Campaigns dropdown kept unchanged with status dots and partner info\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "de5b4192b9081591ecbb1e00f4bc486e6de456cd"
      },
      "digest": "6f7f89a73107d566616ab175a2bc233f855cb5878039f30cdae3359540426102"
    },
    {
      "id": "ship/claimyour.gold/39d10405da9e",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T15:18:49Z",
      "kind": "feature",
      "title": "Add Play, Season, Shop/Orders to nav; activate Matrix & Predictfully",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Desktop GlobalHeader:\n- New \"Play\" group: Duels, Crew War, Bombs, Leaderboard\n- Earn group: add Seasons\n- Campaigns: activate Matrix and Predictfully (remove disabled flags)\n- Rewards: add Shop and My Orders alongside Redeem and Wallet\n\nMobile BottomTabBar:\n- Replace Bounty tab with Play tab (links to /portal/duel)\n- Play tab highlights for duel, crew/war, and bomb routes\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "39d10405da9ed24c9bffeb4f3e7df893df793a68"
      },
      "digest": "10f2220cd1562bddc9cae313f2ad5a07eda22ad08fa0816fefa0535ea0b973b6"
    },
    {
      "id": "ship/claimyour.gold/6313401ecd61",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T15:10:27Z",
      "kind": "infra",
      "title": "Remove Claim Status section from portal dashboard",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "GoldFest Season 1 claim preparation card is no longer needed on the\ndashboard. Removed ClaimStatusCard component and all helper functions\n(StepRow, StepIcon, StepBadge, StepStatus type, Step interface).\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "6313401ecd61ef8a752e02e0cea273227a05635c"
      },
      "digest": "0990c7d57b24a86fc05dd16826b4a17315dcf1ee6e23a71197baa956e8ae9789"
    },
    {
      "id": "ship/claimyour.gold/18d5e00ef8bb",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T14:50:00Z",
      "kind": "fix",
      "title": "Fix PATCH return type in redemptions status route",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Auth result was returned directly (SuperAdminAuthResult not a Response).\nFollow the correct pattern: check !auth.ok and return apiError instead.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "18d5e00ef8bb0262c7c9ef47786c8ec7f5ab2b5f"
      },
      "digest": "cc8bcf7dce89e2756e4eba5a63e3a48a75c3fafcc5bb081ae670e81726d5e2e9"
    },
    {
      "id": "ship/claimyour.gold/194af2cedf78",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T14:39:24Z",
      "kind": "fix",
      "title": "Fix production deploy: remove @unique from HunterProfile.username",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Production DB has multiple null usernames, so the unique index creation\nfails with E11000 duplicate key. Removes @unique and switches the three\nfindUnique({where:{username}}) calls to findFirst.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "194af2cedf781bf1fca98f7c12bccb1570075ee5"
      },
      "digest": "f3cfb6135edafceb95550f0c92866203d3e67ef339d687cc593ca67eac588b0e"
    },
    {
      "id": "ship/claimyour.gold/70fab1890aa0",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T14:28:58Z",
      "kind": "fix",
      "title": "Fix og-war-crew test: mock production-env to avoid process.exit(78)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "70fab1890aa0bc2968d3b9248f34718cdb4bd91f"
      },
      "digest": "96cd0663acd57c3e9b15b1f4cafd6f460499948d69fcb709fa31de3979886d13"
    },
    {
      "id": "ship/claimyour.gold/e60f8b28b33d",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T14:27:55Z",
      "kind": "other",
      "title": "Hide login stats strip; fix 'real gold' copy → 'Flashy Gold'",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Temporarily comment out the social proof numbers on the login page\n  (68,700 / \\$6.40 / 201) — structure preserved for easy re-enable\n- Replace 'real gold' with 'Flashy Gold' in hero subline + streak page\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "e60f8b28b33dd349540d2fb30239744eebbc3c37"
      },
      "digest": "c53aee0ba8d3fed187976abc471379899976acb11b39a7ed382e318c448b5eed"
    },
    {
      "id": "ship/claimyour.gold/48aec1ee3ea1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T14:26:16Z",
      "kind": "fix",
      "title": "Fix divisionService test: add crewMember mock + rivalService mock",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "48aec1ee3ea11a57bb2effd4167a00adffc29341"
      },
      "digest": "3ed84e4aead3da0c63ba6d493f476109d70f9a6a329dfa9bc544b4caabbf08fb"
    },
    {
      "id": "ship/claimyour.gold/6dbba17a5c89",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T14:22:17Z",
      "kind": "fix",
      "title": "Fix test fixtures after merge: crew tiers, hunt party status, bot mock",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- crewTier tests: update tier names BRONZE→COPPER, PLATINUM→LEGEND, DIAMOND→top\n- huntResults tests: use REWARDED party status + new member data shape\n- seasonReset tests: mock @/lib/telegramBot instead of node-telegram-bot-api\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "6dbba17a5c894a169f6606446a3456771221e345"
      },
      "digest": "26b27ff171d397c89cdf428eb74ee90456bf2894bea44b65d2e9b88cbc6b8ce2"
    },
    {
      "id": "ship/claimyour.gold/7f1ec7842468",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T14:19:49Z",
      "kind": "feature",
      "title": "Merge learn-page-articles-seo branch: L01-L13 + M01-M13 features",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds referral leaderboard, streak freeze, push opt-in, social proof\nticker, hunter card embed, referral milestone overlay, invite gating,\ndaily bonus spin, crew recruitment link, public hunt results, badge\ngallery, duel challenge page, viral analytics dashboard, public\nreferral tree, re-engagement engine, rival overtake broadcast, squad\ngoals, badge share cards, streak challenges, season ceremony, crew\nrecruitment tournament, partner co-marketing, reels share card, referral\nreceipt page, and viral A/B test framework.\n\nSchema: adds DAILY_SPIN to RewardType, STREAK_CHALLENGE_WIN +\nCREW_TOURNAMENT_WIN already present; @unique on HunterProfile.username;\nremoves duplicate tier field on Crew model.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BiDkKPviocQQKZNXVVs9WC",
      "refs": {
        "commit": "7f1ec7842468cf37bb4ea7bec743a3bafabdff89"
      },
      "digest": "b52af6fed87c48444bf1c3227b1e5a9133e38576f8c592b2f8a2caaafbeed024"
    },
    {
      "id": "ship/claimyour.gold/4e4e18b97c7b",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T13:59:53Z",
      "kind": "feature",
      "title": "merge: telegram bot DMs I03-I10 — weekly recap, duel photos, anti-churn, badge flex, top recruiter, crew bomb alert, referral tree depth, se",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "4e4e18b97c7b68e704a92fd1eca820abc50d0170"
      },
      "digest": "9a064996803c41284067a6d7930ccea533bc350d66b7241b0460c64a0ec5901a"
    },
    {
      "id": "ship/claimyour.gold/af431e6af451",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T13:36:21Z",
      "kind": "feature",
      "title": "hide Season 1 stats numbers from homepage hero — keep section structure",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "af431e6af451e3341058c61aef2891df9ee392a0"
      },
      "digest": "cbabdf1c06b7220fd3b6c3c0b811d6542f54456bad812f4c1aa1782cdd001f73"
    },
    {
      "id": "ship/claimyour.gold/3d9a16a772af",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T13:20:39Z",
      "kind": "fix",
      "title": "remove stale ANTHROPIC_API_KEY import blocks — secret does not exist in GCP",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "3d9a16a772af556e151bcb2b5e434e09b018b17f"
      },
      "digest": "fd030fc028420b5c807d9fcd2b31189c8cf5d1796e893c0bbd6a0690de82e6df"
    },
    {
      "id": "ship/claimyour.gold/a230c9693316",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T13:07:56Z",
      "kind": "fix",
      "title": "add ANTHROPIC_API_KEY to tf_derived_secret_names so import blocks resolve",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "a230c9693316e9e5b3cdf5ac0ff430e73b2a31c9"
      },
      "digest": "a1ad1570da1466b09f39f2cf7527850e31401535cfe85432eb12c285130e02ee"
    },
    {
      "id": "ship/claimyour.gold/0486fde57a12",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T12:54:49Z",
      "kind": "fix",
      "title": "cast string hrefs to satisfy Next.js typed routes in streak and quest pages",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "0486fde57a1257f4d168a9ff06aa0f1ac69e4fac"
      },
      "digest": "6aaa15a0163de51726db72bc82db6ad22b868dd2ca4ae2e2137f279bfb9118f7"
    },
    {
      "id": "ship/claimyour.gold/e0c864420444",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T12:32:02Z",
      "kind": "fix",
      "title": "cast joinHref to satisfy Next.js Link href type in milestone page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "e0c86442044450b76c20145b0d634eab752373cf"
      },
      "digest": "951bd7eef9e4169fe5b3e9f5ace865e1bf46b09d08385b4d3a79ed247d9e41e6"
    },
    {
      "id": "ship/claimyour.gold/20123c2ae2f7",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T12:07:35Z",
      "kind": "docs",
      "title": "boardroom analysis, 9 agent system prompts, mesh README",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Boardroom strategic brief covering the compound flywheel, current\n  situation, direction, coordination protocol, and open questions\n- System prompt for each of the 9 agents (Nova, Hermes, Aura, Sage,\n  Atlas, Forge, Nexus, Kira, Apex) covering: identity, mission, boot\n  context, how-to-work protocol, PR format, rules, coordination map\n- README with agent/branch reference table, boot instructions, env var\n  checklist, and workflow protocol diagram",
      "refs": {
        "commit": "20123c2ae2f71225bb525e055314ca00980ec8b8"
      },
      "digest": "049840669d9e0556e666d9a11155946ce28f39ab091fa0bc7d900741bb39a316"
    },
    {
      "id": "ship/claimyour.gold/8ad9e903baa1",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T11:58:59Z",
      "kind": "feature",
      "title": "9-agent metric-driven workspace with floor-plan dashboard",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Extend AgentStatus enum with PLANNING, PRESENTING, INCIDENT\n- Rebuild seed route with 9 metric-driven agents (Nova, Hermes, Aura,\n  Sage, Atlas, Forge, Nexus, Kira, Apex) and branch-per-mission naming\n- Add room-transition methods to agent-reporter SDK (plan, present,\n  build, test, deploy, review, incident, idle)\n- Update heartbeat route VALID_STATUSES to include new enum values\n- Rebuild super-admin agents page with three tabs:\n    Workspace: CSS grid floor plan (7 rooms — Boardroom, Lab, Testing,\n      Deploy Bay, Review Room, War Room, Lounge), AgentAvatar with live\n      pulse, agent detail panel with event log\n    Architecture: audit table (9 agents, 6 improved + 3 added),\n      local-optimisation risk callout, design-principle cards\n    Roadmap: 4-phase plan with progress tracking + workflow protocol\n      diagram showing room-transition sequence",
      "refs": {
        "commit": "8ad9e903baa1254e11a6c4fe493d17b61bf51290"
      },
      "digest": "b867ae7133549b19da5a926bd71c9cec1a6241ed44f87cd534717b9708286765"
    },
    {
      "id": "ship/claimyour.gold/d11141fe17be",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T11:53:26Z",
      "kind": "feature",
      "title": "merge: leaderboard bracket share card DM + recruit milestone relay DM (claude/claimyourgold-telegram-bot-rf8yop)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- notifyLeaderboardBracket: viral share card DM when hunter crosses top-500/100/50/10/3 bracket\n  with historic (first-ever) and regular (displaced hunter taunt) variants\n- notifyRecruitMilestone: relay DM to referrer when recruit earns first badge, hits 100 FG, or ranks up\n- leaderboardShareService: bracket dedup via Redis SET NX (once/bracket/week + persistent first-ever key)\n- recruitMilestoneService: milestone detection with per-milestone dedup\n- divisionService: fire-and-forget checkAndNotifyLeaderboardBracket after re-rank\n- checkAndAwardBadges: fire recruitMilestone relay on first badge\n- telegramInlineQuery: leaderboard-rank and recruit-milestone inline card handlers\n- New functions placed in notify/engagement.ts and notify/social.ts to match refactored barrel structure",
      "refs": {
        "commit": "d11141fe17be41cb4874f8c9e0d84975e94c354c"
      },
      "digest": "ab725a98220b5b8eceb814e8aff6a267b2b20b3a73b29c4a0a313f48bd32c768"
    },
    {
      "id": "ship/claimyour.gold/6f90dc3a1a75",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T11:34:33Z",
      "kind": "fix",
      "title": "exclude refences/ from tsc and jest, fix QuestPerformanceStats trend7d",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "6f90dc3a1a75eb28393389a38089031887937c71"
      },
      "digest": "243dc03b894f94e3be974105aadb83e6a0ac6dabe0a65fc05a458b2b75700665"
    },
    {
      "id": "ship/claimyour.gold/f392088d5e42",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T11:31:31Z",
      "kind": "feature",
      "title": "merge: UI branch - landing page, dashboard, portal components (origin/UI)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01J2qxPshEipVBy5raa5hg5K",
      "refs": {
        "commit": "f392088d5e42095b694f1db0f03866d663c99d2f"
      },
      "digest": "ebf3ad71f333a622d5f4746a70308984cf6189f2edd3ea811c0d9591d2623509"
    },
    {
      "id": "ship/claimyour.gold/72aacca90f23",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T11:29:24Z",
      "kind": "feature",
      "title": "merge: analytics deep-dive, user profile API, quest sparklines, inline gold credit, broadcast (claude/funny-noether-75ghqx)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "72aacca90f230728c5526df4ebdee060aaa484e0"
      },
      "digest": "09896a56916143ea8445043653fdf2d01094cf957d74b8182a76a0a2a4d535ab"
    },
    {
      "id": "ship/claimyour.gold/ef1aeb7ba925",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T11:28:43Z",
      "kind": "feature",
      "title": "merge: feature flags, FeatureFlag model, feature-flag-sync job (claude/test-current-status-RbZZn)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "ef1aeb7ba9250b1415dd1aa99a17b4fbdf666430"
      },
      "digest": "8480d107fb7fd7705590abb2dfb4d57b0768f2a7abe40c223016f1fa0c270e7c"
    },
    {
      "id": "ship/claimyour.gold/b58ce605af26",
      "repo": "repo/claimyour.gold",
      "at": "2026-07-04T11:27:24Z",
      "kind": "feature",
      "title": "merge: Telegram login fixes and bot ID config (cursor/michael-test-2bc5)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "b58ce605af2634aa746c7c1f76f4f11e7600c560"
      },
      "digest": "3a023ca6069e3916a9893ec9caf58c78e2d62d9eaa692d98aa93818c398b387c"
    },
    {
      "id": "ship/claimyour.gold/de7ca7860568",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-29T12:31:57Z",
      "kind": "feature",
      "title": "Merge: complete knowledge injection feature",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "de7ca7860568610a1ca791fdfbe65d48c44d5522"
      },
      "digest": "3c3cfde389d29df3fb94bdc80eb0cf038c6ac0986f75641e7411883b5cb7005d"
    },
    {
      "id": "ship/claimyour.gold/9d4facdf47b0",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-29T12:22:59Z",
      "kind": "feature",
      "title": "Merge: knowledge graph manual entry and bulk import",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "9d4facdf47b0bec886156b37aa49bbdc1f982ae4"
      },
      "digest": "3cdc1b6e95bb48bf82440d8dff836b102aeaf8100cbb120d4a54119fae24e04f"
    },
    {
      "id": "ship/claimyour.gold/f5307314f69a",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-29T02:44:00Z",
      "kind": "feature",
      "title": "Merge: add edit/delete for workflows and projects",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "f5307314f69ac4541a309b7c03adf7ad8427def4"
      },
      "digest": "4bc2cecbcb322688c7e637e01ef2f7f80482321ac6a8777f75ce0348a0d7e690"
    },
    {
      "id": "ship/claimyour.gold/3d5748161c1d",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-29T02:22:06Z",
      "kind": "fix",
      "title": "enqueue workflow to planner on creation",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "createWorkflow() created the DB record and fired an event but never\nadded a job to the os-planner BullMQ queue, so all workflows stayed\nstuck in 'Created' forever.\n\n- Add src/lib/os/queues.ts with lazy getPlannerQueue/getExecutionQueue\n  singletons — shared across services and jobs to avoid duplicate Queue\n  instances for the same BullMQ queue\n- createWorkflow() now enqueues to os-planner immediately after DB write\n- plannerJob.ts uses getExecutionQueue() from the shared module\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "3d5748161c1da81654da962c5608728fc6ed4f38"
      },
      "digest": "28803903d209ab6e627761b0d8c0a444ce829806f4694b0f72f3a8ef9ded64b3"
    },
    {
      "id": "ship/claimyour.gold/058b638146ba",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-29T01:23:46Z",
      "kind": "infra",
      "title": "import manually-created ANTHROPIC_API_KEY secret into TF state",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The secret was created manually in Secret Manager before Terraform managed\nit, causing terraform apply to fail with a 409 conflict. Import blocks\nreconcile the three GCP resources (secret, IAM binding, placeholder\nversion) into Terraform state so subsequent applies succeed.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "058b638146ba85a0d20a569c0e98a79d60e503c3"
      },
      "digest": "363442a16aaeb6fe014ce4ac17cb983f5a90e00e750640982c59bc3b6a2f105f"
    },
    {
      "id": "ship/claimyour.gold/c8da6eb6c5c5",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-28T19:55:52Z",
      "kind": "fix",
      "title": "seed model registry before any LLM calls",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "seedDefaultModels() was never called, so getModel() inside llmGateway\nalways threw NOT_FOUND, failing every workflow at the first LLM step.\n\n- Admin seed endpoint now calls seedDefaultModels() before seedPlaybooks()\n- Execution job calls seedDefaultModels() on each job start (idempotent\n  upsert — cheap after first run) so the worker self-heals without\n  requiring a manual settings-page click\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "c8da6eb6c5c503efa31d35b98ae1038ec342d59d"
      },
      "digest": "42cd8aaf16cb73bfb8df2e847e2ea314812bd2d19da6f5ed9a333edbce94096a"
    },
    {
      "id": "ship/claimyour.gold/fee8717e0c94",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-24T15:16:21Z",
      "kind": "fix",
      "title": "register all 6 capabilities in registerAllCapabilities",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "evaluateContent, generateDebatePositions, and extractEntities were\nimplemented but never wired into the registry. Every playbook uses at\nleast one of them, so all workflows would fail at execution time when\nthe step runner tried to look up the missing capability.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "fee8717e0c94f250872de3bc8b88222be0db3320"
      },
      "digest": "d0c2c0249b345943295d8ac598ad9fd0f930e31ea477ff541aa5a11e52d7cb2f"
    },
    {
      "id": "ship/claimyour.gold/d170d46e83d3",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-24T12:29:01Z",
      "kind": "feature",
      "title": "add playbook seed button + DB stats panel",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Settings page now shows playbook/workflow/artifact counts and\na one-click Seed Playbooks button that calls /api/os/admin/seed-playbooks.\nSeeding is idempotent — existing playbooks are skipped.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "d170d46e83d3702aff318deb0cea8aa23c83d494"
      },
      "digest": "5b15eb21a1a44e4540f332c9bb4b7b64de2aa6d292d191c3e22b0a949b789d31"
    },
    {
      "id": "ship/claimyour.gold/51e77ac70937",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-24T12:25:32Z",
      "kind": "feature",
      "title": "add Super Admin back-link to FlashyOS sidebar footer",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "51e77ac7093740f52eb34a506733b210cc971630"
      },
      "digest": "70f4c556fb0e0c8d8bbe6c79919c2cb91f0bb092a441179a98fbfade7a0ee401"
    },
    {
      "id": "ship/claimyour.gold/1ac39111ea7c",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-24T12:21:16Z",
      "kind": "infra",
      "title": "ensure ANTHROPIC_API_KEY is managed by secrets module",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Previously only added to worker_secret_names (the pass-through filter),\nbut module.secrets is what creates the secret container and grants\nIAM secretAccessor to flashy-runtime. Without it in all_secret_names,\nTerraform never ran the IAM binding, causing Cloud Run permission denied.\n\nAdd a hardcoded_secret_names list for secrets that must always exist\nregardless of secrets.json content, and merge it into all_secret_names.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "1ac39111ea7c4e4421608903a6157928022a1b09"
      },
      "digest": "a467998d533e07bf3bd783b015455de332024949d027e1f3e1c4ca33fc4e62ea"
    },
    {
      "id": "ship/claimyour.gold/05347d40f801",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-24T02:26:06Z",
      "kind": "fix",
      "title": "exclude all .claude worktrees from jest test discovery",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Abandoned worktrees contain stale test files referencing modules that\nwere never created, breaking the pre-push hook.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "05347d40f80115bfcb652fca62f7b2e1ad4740d5"
      },
      "digest": "4ed406939b180d690ef80497286f94e9af8eb7c91ff3b19f896861f91df34ed1"
    },
    {
      "id": "ship/claimyour.gold/67dd8aaff0a5",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-24T02:24:32Z",
      "kind": "infra",
      "title": "add ANTHROPIC_API_KEY to worker secret env vars",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Required for the FlashyOS execution engine to call Claude capabilities.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "67dd8aaff0a580e51c10e5b58b5291744108ebef"
      },
      "digest": "bf4ba5b2728fa838db0cf827ebae555d89257669683c3ccbe1ee85c1526f9be7"
    },
    {
      "id": "ship/claimyour.gold/021992abfdeb",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T22:34:21Z",
      "kind": "feature",
      "title": "Session 6A — execution engine (step runner + BullMQ job)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Add stepRunner.ts (lib) that walks DAG levels and runs capability fns concurrently, and executionJob.ts (BullMQ worker on os-execute-workflow) that drives the full Researching→Drafting→Evaluating→AwaitingHuman flow. Wire plannerWorker and executionWorker into the main worker entry point.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "021992abfdeb3ba79db73142a69fd1bbae3af0fa"
      },
      "digest": "1b0acab440a80ad18d76b32eb0810edb29227493996965b30a99230a2533cc43"
    },
    {
      "id": "ship/claimyour.gold/e61773054806",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T22:24:23Z",
      "kind": "feature",
      "title": "Session 5D — Studio workflow launcher",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replaces the /ops/studio stub with a full Prompt Studio page featuring a\nplaybook grid with domain-coded badges and a collapsible launch form with\nserver-action that creates an OsWorkflow and redirects to /ops/live.\nAdds 8 Jest tests covering auth, validation, and happy-path for the\nexisting /api/os/workflows route.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "e6177305480647889ff1024dd0f24ae1eeed1f1e"
      },
      "digest": "539cfb5647f4a3b9fd2f37348705ae174d2ac24e880952dabb3a6cfc975be4cc"
    },
    {
      "id": "ship/claimyour.gold/6c646034039d",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T22:19:06Z",
      "kind": "feature",
      "title": "replace coming-soon stub with full analytics page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Add analyticsService.ts with getSpendByDay, getWorkflowVolumeByDay,\n  getTopCapabilities, and getArtifactApprovalRate (all aggregated in JS\n  to avoid MongoDB groupBy limitations with Prisma)\n- Replace /ops/analytics stub page with a real RSC: auth guard via\n  requireSuperAdminRsc, four stat cards, pure-CSS spend bar chart for\n  last 7 days, and a top capabilities cost table — all in the dark gold\n  palette (#f5c547 / #0a0806 / #f5f1e8)\n- Add 14 unit tests covering fill-missing-days, sort order, aggregation,\n  rate computation, and zero-division edge cases\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "6c646034039d57881abb1332a1543d069b6181a9"
      },
      "digest": "1b8e7f716ee2cb73f6910964e3f3990a58922259a01e1365aaf50baccf868790"
    },
    {
      "id": "ship/claimyour.gold/0685edcfd4ee",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T22:11:40Z",
      "kind": "fix",
      "title": "update projects and objectives pages to use requireSuperAdminRsc",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "These pages from Session 5C still used the old broken mock request\npattern that omitted req.cookies, causing getToken() to return null\nand redirect authenticated users to /super/login.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "0685edcfd4ee0c7485e7a6b1d1ce7d87208bf57b"
      },
      "digest": "49a662339f8265cc22f4d639a2a79da620f48609cb8cf525b7d260ade6895b89"
    },
    {
      "id": "ship/claimyour.gold/83700fdec9b7",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T22:03:39Z",
      "kind": "feature",
      "title": "add Projects and Objectives pages + API routes (Session 5C)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Replace /ops/projects and /ops/objectives placeholder pages with full\n  server-component UIs: stats row, division/status filter chips (aria-current),\n  responsive card grids, inline server-action create forms, pagination (PAGE_SIZE=20),\n  and three empty-state variants each\n- Add GET + POST /api/os/projects with division validation and paginated response\n- Add GET + POST /api/os/objectives with status validation and paginated response\n- Add 22 tests covering auth, pagination, validation errors, filter forwarding,\n  skip computation, and 500 handling for both routes\n- Fix jest.config.ts testPathIgnorePatterns to allow tests inside git worktrees\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "83700fdec9b715dce221ded83af77333acbe77a2"
      },
      "digest": "2b345cbe519fc53f171bab2f21a8660d5ee8714bff8b8d8e9d1ee92ce967055f"
    },
    {
      "id": "ship/claimyour.gold/be4d38f189f5",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T22:02:10Z",
      "kind": "fix",
      "title": "Fix /ops auth: protect route in middleware and add RSC-safe auth helper",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The /ops pages were using a mock NextRequest that omitted req.cookies,\ncausing getToken() to always return null and redirect every authenticated\nuser back to /super/login when clicking the FlashyOS link.\n\nTwo fixes:\n1. Add isOpsProtected to middleware so the real NextRequest (with cookies)\n   guards /ops routes before RSCs run — unauthenticated users go to\n   /super/login, authenticated non-super-admins too.\n2. Export requireSuperAdminRsc() from superAdminAuth.ts — reads cookies\n   via next/headers and builds a proper mock for getToken(). RSC pages\n   and Server Actions now use this instead of the headersList-only mock.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "be4d38f189f5e9353215af47355cd36c726c37c0"
      },
      "digest": "8df495c51d1b156b7105b889d29b4f15a2cd938b642801a91ab1603eaeefd0b4"
    },
    {
      "id": "ship/claimyour.gold/99b66114051f",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T21:44:30Z",
      "kind": "feature",
      "title": "add FlashyOS link to super admin sidebar",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds an '⚡ FlashyOS' link in the sidebar footer above Sign Out.\nSession cookie is shared — no re-login required when navigating to /ops.",
      "refs": {
        "commit": "99b66114051f8887048963407053e70d33bb8a50"
      },
      "digest": "0116b6fe07dd1419ac3df7562447b7c6b867853085c7fcfaaadccec24f370aec"
    },
    {
      "id": "ship/claimyour.gold/c91eb172b06f",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T21:33:25Z",
      "kind": "fix",
      "title": "make ANTHROPIC_API_KEY optional to prevent boot crash",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "ANTHROPIC_API_KEY was added to ServerSchema as required, causing\nprocess.exit(78) on every request in production (where the key is not\nyet in GCP Secret Manager). The logger calls serverEnv() lazily, so\nthe crash happened on the first request to any route, taking the whole\nsite down.\n\nFix: make the env var optional; validate its presence inside\nllmGateway.getClient() where it's actually needed, throwing a\nstructured AppError instead of exiting the process.\n\nGate: tsc --noEmit ✓ | jest 2545 tests ✓",
      "refs": {
        "commit": "c91eb172b06fa6e545e68ef56affa2d81dfcbf1e"
      },
      "digest": "8af193a5115f5e992987d979702dbfaea16ab65dedaa6644ef070d2cbf28f0fc"
    },
    {
      "id": "ship/claimyour.gold/cf0f448e6ca4",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T21:12:03Z",
      "kind": "infra",
      "title": "trigger production deploy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "cf0f448e6ca47dc15b242ba972d7de919aeb0816"
      },
      "digest": "650b55c1cc9cf508cd261f3a527333067d26f7aeaf87ba8619dfdaff6b7f82b6"
    },
    {
      "id": "ship/claimyour.gold/ae0a46fdfc71",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T17:09:05Z",
      "kind": "infra",
      "title": "merge production hotfixes into FlashyOS branch",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "ae0a46fdfc71f6a4fca3a5e1bf491eb268dc1826"
      },
      "digest": "94f4f7dc5661c6b075ae457fbdb6f8580f6f9af6902aba382afd11100c586cf0"
    },
    {
      "id": "ship/claimyour.gold/7f24fb208071",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T17:07:41Z",
      "kind": "infra",
      "title": "merge main into FlashyOS branch + fix ESLint/TS issues from merge",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Merges 96 commits from main (mini-app, press, fraud, SEO, waitlist features)\ninto the FlashyOS branch. Conflict resolution: took main's version for all\nnon-FlashyOS files. Post-merge fixes:\n\n- rateLimit.ts: removed duplicate waitlistRateLimit/getWaitlistLimiter block\n  (both branches added the waitlist limiter; kept the logger.error version)\n- Unused imports/vars across 8 files from main (hunter page, leaderboard,\n  import route, share route, telegram bot route, predictfully, streakReminderJob,\n  awardPointsService)\n- redis.test.ts: added missing eslint-disable-next-line for require() in tests\n- fetchExistingAwards: removed unused clientId parameter; updated caller + tests\n\nGate: tsc --noEmit ✓ | jest 2545 tests ✓",
      "refs": {
        "commit": "7f24fb208071eea9b73d54651d34ecc3016546ae"
      },
      "digest": "296b207d4b07e726bf5209b1572c76fdf8da6a914f1cbd804f142d4c3af3c217"
    },
    {
      "id": "ship/claimyour.gold/d95dce3bbef0",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T16:24:49Z",
      "kind": "feature",
      "title": "Session 5B — Knowledge Graph Browser",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Implements the /ops/knowledge page and its supporting API layer.\n\nService additions (knowledgeGraphService.ts):\n  - listNodes(options) — server-side paginated query with parallel\n    count for accurate totalPages; prevents the prohibited JS-slice pattern\n  - getGraphStats() — single round-trip for nodeCount, edgeCount,\n    distinctTypes used by the page header\n  - getBatchNeighbors(nodeIds) — two DB queries fetch all neighbor\n    edges + external nodes for a full page of results, eliminating N+1\n\nComponent (KnowledgeNodeCard.tsx):\n  - Named export; article element with aria-label\n  - ENTITY_TYPE_COLORS map for seven known entity types (free strings\n    from LLM — no DB enum)\n  - Importance bar, neighbor count pill, relative timestamp\n  - isExpanded prop changes border to highlight open details cards\n\nPage (/ops/knowledge/page.tsx):\n  - Server component; Next.js 15 async searchParams\n  - Filter bar (GET form, works without JS): text search + type chips\n    with aria-current state (aria-pressed is invalid on anchor elements)\n  - 3/2/1-column responsive grid; each card wrapped in details so\n    neighbor list expands inline with no client JS\n  - Three distinct empty states: system-empty, search-miss, type-miss\n  - Pagination: skip/take server-side, prev/next links with aria-disabled\n\nAPI routes:\n  - GET /api/os/knowledge — Zod validation, INVALID_ENTITY_TYPE guard,\n    returns { data, total, page, totalPages }\n  - GET /api/os/knowledge/[id]/neighbors — NOT_FOUND on missing node,\n    derives direction (outbound/inbound) from edge.fromNodeId comparison\n\nTests (15, target was 12):\n  - Full coverage of both routes: auth rejection, pagination math,\n    limit-exceeded, invalid type, empty results, correct skip/take call,\n    NOT_FOUND, direction field, inbound vs outbound, no-edge case, 500s\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "d95dce3bbef0455f4ccc8aa7fff57a21e22e99e1"
      },
      "digest": "072409822a9e2aa615c894c5d8838c8928fafb022aca4479b33fe27ccfc9c123"
    },
    {
      "id": "ship/claimyour.gold/961ed3bb68f7",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-23T15:11:41Z",
      "kind": "feature",
      "title": "Session 5A — Evaluator pipeline + Approvals page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Wires up the multi-stage evaluator pipeline and replaces the /ops/approvals\nplaceholder with a full server-rendered review UI.\n\n- src/lib/os/evaluatorPipeline.ts: runEvaluators() chains five named\n  evaluators (Grammar, Brand, Policy, SEO, Quality) in type-specific\n  sequences (SocialPost/Email/BlogPost/Report/Decision/default). Scores\n  are stored via addEvaluationScore(); a score below 60 aborts the chain\n  and returns passed=false / readyForHuman=false.\n\n- src/app/(ops)/ops/approvals/page.tsx: Server Component that queries\n  AwaitingHuman workflows and their Draft artifacts in parallel. Each\n  artifact card renders full content, evaluator score badges (green ≥75 /\n  amber 60–74 / red <60), debate/rationale for Decision types, and lineage\n  metadata. Three Server Actions (handleApprove, handleRequestChanges,\n  handleReject) mutate artifact state and revalidate the page in place —\n  no client JS required for the core approval flow.\n\n- src/app/api/os/artifacts/[id]/approve/route.ts: POST — approves an\n  artifact; returns updated document.\n\n- src/app/api/os/artifacts/[id]/reject/route.ts: POST {reason} — rejects\n  an artifact with a required reason string.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "961ed3bb68f7ffa038af205daca76c3c6dfaa3d7"
      },
      "digest": "d51a6da8e792a37d5c1e9c3a194596865eb27b9787e687e05fef0d3957a3550f"
    },
    {
      "id": "ship/claimyour.gold/aadee84c0c32",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T21:17:32Z",
      "kind": "feature",
      "title": "Session 4C — Planner (playbook-driven, not arbitrary)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Implements the FlashyOS Planner — the critical architectural gate that\nensures all workflows are driven by a matching playbook. The planner\nselects a playbook, fills parameter slots via LLM reasoning, prepends\na debate step for decision-oriented goals, validates the result through\nthe DAG engine, and escalates instead of freeforming when no match\nexists or the estimated cost exceeds the budget cap.\n\n- src/lib/os/planner.ts: plan(), shouldDebate(), resolveStep()\n- src/jobs/os/plannerJob.ts: BullMQ worker — transitions workflow through\n  Planning→Researching (or AwaitingHuman on escalation), stores dagJson\n  + playbookId, publishes PLAN_CREATED / WORKFLOW_NEEDS_PLAYBOOK events,\n  and enqueues the downstream execute-workflow job\n- tests/lib/os/planner.test.ts: 32 tests covering success path, both\n  escalation branches (no match, over budget), debate step injection,\n  and DAG error propagation\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "aadee84c0c328bc7b5a268bb4437a213fce4eafa"
      },
      "digest": "9c732861894e63e5c4a211bd305d4df47cfd86644b18d58326b1f22adfc479eb"
    },
    {
      "id": "ship/claimyour.gold/8e1cb297989a",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T20:59:47Z",
      "kind": "feature",
      "title": "Session 4B — DAG Engine (pure validation + topological sort)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- validateDag: Kahn's-style BFS detects cycles, missing deps, unknown\n  capabilities, depth > 10, and cost > $5 — all as typed AppErrors\n- buildExecutionPlan: computes parallel execution levels, critical-path\n  duration (not sum), aggregate cost, and requiresHumanApproval flag\n- Pure functions — zero DB calls, zero HTTP, zero side effects\n- 25 tests: linear/parallel/diamond topologies, all error paths, boundary\n  conditions, critical-path correctness, requiresHumanApproval propagation\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "8e1cb297989af23481b4215463257fa0b8fcdbb5"
      },
      "digest": "45e41a10e5f78dda5e75e868bb8be477de49c76e40e45bba634f4452daa0e088"
    },
    {
      "id": "ship/claimyour.gold/929baa8321db",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T20:49:29Z",
      "kind": "feature",
      "title": "Session 4A — Playbook Service + 12 seeded playbooks",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- playbookService: createPlaybook (validates DAG capability references against\n  registry), getPlaybook, listPlaybooks(domain?), updatePlaybook,\n  deactivatePlaybook, matchPlaybook (keyword scoring with forward-compat hook)\n- 12 default playbooks seeded across Marketing (4), BizDev (3), Tech (3),\n  Operations (2) — all fields populated, DAG steps use registered capability IDs only\n- 20 tests: DAG validation, capability registry checks, domain filtering,\n  matchPlaybook keyword scoring and null cases\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "929baa8321db0ec4f89e2349a841d260e147f0f1"
      },
      "digest": "612b5bf6f7836fe49d0bdc5775302500eaa6a9440975d04c144872ea5d5d1545"
    },
    {
      "id": "ship/claimyour.gold/1a7c46764913",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T18:19:10Z",
      "kind": "feature",
      "title": "Session 3D — Artifact Service (Full) + Decision Journal",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Extend createArtifact with lineage fields (parentArtifactId, originCapability,\n  derivedFromIds, promptVersionId), fire-and-forget entity extraction, and\n  ARTIFACT_CREATED event emission\n- Add createArtifactRevision: new artifact at version+1, updates parent childArtifactIds\n- Add getArtifactLineage: resolves parent, children, and supersededBy in one call\n- Add addEvaluationScore: merges JSON scores, maintains evaluatorsPassed/Failed arrays\n- Add publishArtifact: validates Approved state, audit log, ARTIFACT_PUBLISHED event\n- Add decisionJournalService with createDecision, getDecision, listDecisions, recordOutcome\n- 24 artifact service tests covering all new functions\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "1a7c467649139443c7e68bcf694b82f655524f09"
      },
      "digest": "04aadbffb41def967decbf4f69e2b45cf212625eeba108ea7c33bcc709bfd796"
    },
    {
      "id": "ship/claimyour.gold/b95686b64a7f",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T18:12:24Z",
      "kind": "feature",
      "title": "Session 3C — Knowledge Graph + Memory System",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Extend knowledgeGraphService with BFS traverseGraph (max depth 2, 15 nodes, cycle prevention)\n- Extend brainSnapshotService.restore to clear stale working memory (os:wm:*) after graph restore\n- Add unified 4-tier memory interface (working/semantic/graph/timeline) with intent retrieval policies\n- 26 tests covering all tiers, nullable Redis, intent policies, and per-tier failure resilience\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "b95686b64a7fc1df4260afcf2b9bba9ad275de03"
      },
      "digest": "40308f51d44e15caa4bfd4bcbbb694bd8bda25043e8a2185e1ef3dd8aa108956"
    },
    {
      "id": "ship/claimyour.gold/98525c17284b",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T17:47:42Z",
      "kind": "feature",
      "title": "Session 3B — Core Capabilities (Extract + Evaluate + Debate)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds 3 evaluator/analysis capabilities following the identical researchTopic pattern.\n\n- knowledge.extract-entities: haiku, idempotent, 30min cache; validates entity shape before upsert; fire-and-forget upsertFromEntities() after success\n- content.evaluate: haiku, idempotent, parallelizable, 30min cache; grade and approved computed deterministically in code from LLM score (90+=Excellent, 75-89=Good, 60-74=Acceptable, 40-59=NeedsRevision, <40=Reject); approved = score >= 75; score clamped 0-100\n- analysis.debate: sonnet; perspectives run in parallel via Promise.all, then one synthesis call; accumulates inputTokens/outputTokens/costUsd across all calls; uses buildContext for topic background\n- 24 tests: approved flag boundaries, full grade mapping (10 score/grade pairs via it.each), output shape invariants, error → success:false, prompt registry wiring, model defaults\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "98525c17284bac45e6c426e30d59bdc556209c18"
      },
      "digest": "04ea9a2d0daa85e4e67e4c8f96aeccc38e634242d3c0397e0c5a42e654fe2468"
    },
    {
      "id": "ship/claimyour.gold/33873cae0510",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T17:41:47Z",
      "kind": "feature",
      "title": "Session 3A — Core Capabilities (Research + Write + Summarize)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds 3 registered capabilities with full metadata, prompt seeding, and test coverage.\n\n- research.topic: quick/thorough depth selects haiku/sonnet; parallel retrieval via contextBuilder; cached 1h; returns { summary, keyPoints, sources, gaps }\n- content.write: brand-safe content drafting for 9 formats/4 tones; requiresHumanApproval: true; sonnet model; returns { content, wordCount, charCount, alternatives }\n- content.summarize: idempotent haiku summarizer; parallelizable; cached 1h; supports one_sentence/paragraph/bullets output\n- capabilities/index.ts: registerAllCapabilities() seeds 3 prompt versions via upsertPrompt then registers with has() guard against double-registration\n- All 3 default system prompts enforce brand safety: \"NEVER refer to rewards as 'real gold' — always use 'Flashy Gold' or 'Flashy Gold rewards'\"\n- 15 tests: success path, model selection (quick→haiku, thorough→sonnet, override), error handling, brand safety prompt checks\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "33873cae0510f9c7d446f0d6eef76186d0a52f80"
      },
      "digest": "604effeb25559c8a7e8c9a6df88d077806882849738fff5a27af4491d7d2f317"
    },
    {
      "id": "ship/claimyour.gold/d5f71b63f360",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T17:35:03Z",
      "kind": "feature",
      "title": "Session 2E — Context Builder",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Assembles token-budget-constrained LLM prompt context from memory tiers.\n\n- tokenCounter: conservative 4-chars/token heuristic; trimToTokenBudget preserves sentence boundaries before appending [truncated]\n- contextBuilder: parallel retrieval from knowledge graph (searchNodes), timeline (listEvents), and artifacts (listArtifacts); budget split 40/30/30; strips nodes matching secret pattern; all retrieval errors caught and logged, never thrown to caller; assembles ContextPackage with systemContext, individual section strings, totalEstimatedTokens, and sourcesSummary counts\n- 30 tests covering happy path, all 3 error-handling paths, token trimming, include flags, and secret filtering\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "d5f71b63f360c0ce8a3a2d99053da03512b9297b"
      },
      "digest": "c7d8427b44360fa70270573611a69e25c705067aa617009642e83adc25a1b69c"
    },
    {
      "id": "ship/claimyour.gold/9ba917586814",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T17:30:04Z",
      "kind": "feature",
      "title": "Session 2D — Prompt Registry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds prompt versioning service, in-memory prompt cache, and full test coverage.\n\n- promptVersionService: immutable versioned prompts; upsert deactivates prior active version via updateMany before creating new record; throws PROMPT_NOT_FOUND (404) when no active prompt exists\n- promptRegistry: in-memory cache keyed by name:capability; load() bulk-fetches all active prompts; get/set/invalidate/size API; singleton export\n- 10 tests covering upsertPrompt ordering, getActivePrompt error path, listPrompts capability filter, and getPromptHistory full history\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "9ba9175868143cef434d5a8225d3e15ca1a781a3"
      },
      "digest": "bf22367a4293ee2f046036360ee37f78db0fa647ddb73629f44c86787a026839"
    },
    {
      "id": "ship/claimyour.gold/1fa15a740653",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T16:47:18Z",
      "kind": "feature",
      "title": "Session 2C — Capability Metadata Registry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Establishes the type contract and registry for all AI capabilities.\nNo capability implementations yet — those are Sessions 3A/3B.\n\ncapabilityTypes.ts — shared types used by every capability:\n  CapabilityMetadata (14 fields): name, version, description,\n    inputSchema/outputSchema (JSON Schema for docs), estimatedLatencyMs,\n    estimatedCostUsd, dependencies, parallelizable, idempotent,\n    retryPolicy, cacheTtlSeconds (null = no cache), requiresHumanApproval,\n    failureStrategy ('fail'|'skip'|'fallback'), fallbackCapability?\n  CapabilityInput<T>: workflowId, input, model?, budgetUsd?, promptVersionId?\n  CapabilityOutput<T>: success:true + output, model, tokens, cost, durationMs, fromCache\n  CapabilityError: success:false + error, code, retryable\n  CapabilityResult<T>: discriminated union narrowed by .success flag\n  CapabilityFn<TInput, TOutput>: the required signature for all capabilities\n\ncapabilityRegistry.ts — DI-friendly singleton registry:\n  register(fn, meta): validates required fields at runtime, rejects\n    duplicate names (CAPABILITY_ALREADY_REGISTERED 409), validates\n    fallback strategy has fallbackCapability declared.\n  get(name): throws CAPABILITY_NOT_FOUND 404 for unknown names.\n  list(): returns CapabilityMetadata[] for Planner discovery.\n  has(name): boolean lookup.\n  unregister(name): test-only removal without error on missing name.\n\nTests: 30 new tests across 2 suites.\n  capabilityRegistry: register+get roundtrip, duplicate registration,\n    meta validation (name/version/description/fallback), get not-found,\n    list contents and shape, has true/false, unregister removes from\n    get/has/list, no-op on missing name.\n  capabilityTypes: CapabilityResult union narrows correctly via success\n    flag, CapabilityOutput shape (including fromCache), CapabilityError\n    shape, CapabilityInput required/optional fields, CapabilityFn\n    returning success and error, CapabilityMetadata valid shapes\n    (null cacheTtlSeconds, fallback strategy, all three stra",
      "refs": {
        "commit": "1fa15a7406538b36da465e46a16b823f6c4bc53c"
      },
      "digest": "3dfa4222e9a8326c64d8d046fa3da0644f2b229dedf8da9018b3e5db552eb9e1"
    },
    {
      "id": "ship/claimyour.gold/9b9012ba9430",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T16:42:24Z",
      "kind": "feature",
      "title": "Session 2B — Model Registry + LLM Gateway",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds the only two pieces of infrastructure that talk to Anthropic.\nEverything else goes through these abstractions.\n\nmodelRegistryService.ts:\n  seedDefaultModels() — upserts 4 Claude models (Haiku/Sonnet/Opus/Fable)\n    with cost-per-1k-token pricing; update:{} ensures existing latency/\n    quality stats are never overwritten by a re-seed.\n  getModel()      — throws AppError NOT_FOUND for missing or inactive models\n  listModels()    — active models ordered by inputCostPer1k asc\n  selectModel()   — cheapest model meeting vision/reasoning/cost requirements;\n                    preferSpeed picks lowest avgLatencyMs; falls back to\n                    cheapest when no latency data exists.\n  updateModelStats() — writes avgLatencyMs + qualityScore from eval results\n\nllmGateway.ts:\n  callLlm() — the ONLY place in FlashyOS that calls @anthropic-ai/sdk.\n    1. Validates model via registry (fails fast before SDK call)\n    2. Calls Anthropic messages.create with system+user prompts\n    3. Computes cost: (inputTokens/1k * inputCostPer1k) + (outputTokens/1k * outputCostPer1k)\n    4. Parses JSON when jsonMode:true; throws LLM_INVALID_JSON on bad JSON\n    5. Logs to OsCapabilityLog fire-and-forget when workflowId provided\n  Lazy singleton Anthropic client (constructed once per process).\n\nConfig:\n  production-env.ts — adds ANTHROPIC_API_KEY to ServerSchema\n  Dockerfile        — adds ANTHROPIC_API_KEY=\"build-dummy\" to build ENV block\n\nTests: 27 new tests across 2 suites covering all specified scenarios.\n  modelRegistryService: getModel not-found/inactive, listModels query shape,\n    selectModel cheapest/reasoning/vision/preferSpeed/no-match, seed upsert\n    count and update:{} invariant, updateModelStats write shape.\n  llmGateway: cost calculation, jsonMode parse, jsonMode invalid JSON throws,\n    capability log called/not-called, model validation before SDK, defaults.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKm",
      "refs": {
        "commit": "9b9012ba94305276da11d65454d76135fd0f83bc"
      },
      "digest": "b90555fe20525f41a1dee9bc938d2a7aff39f2c8eeb5bbfcda6b8e987722fd13"
    },
    {
      "id": "ship/claimyour.gold/efd18f8e9c8a",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T16:36:07Z",
      "kind": "feature",
      "title": "Session 2A — schema evolution",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Extends OsWorkflow and OsArtifact with intelligence substrate fields.\nAdds 4 new FlashyOS models. Regenerates Prisma client.\n\nOsWorkflow additions (6 fields):\n  successCriteria  Json?             — structured goal/budget/deadline/risk\n  playbookId       String? ObjectId  — which Playbook drove this workflow\n  playbookVersion  String?           — Playbook semver at time of planning\n  promptVersionId  String? ObjectId  — prompt version used during planning\n  approvalPolicy   String \"RequireAll\" — RequireAll | RequireAny | AutoApprove\n  budgetCapUsd     Float?            — user-set hard cost cap\n\nOsArtifact additions (10 fields):\n  originCapability    String?         — capability that produced this artifact\n  parentArtifactId    String? ObjectId — direct predecessor in revision chain\n  childArtifactIds    String[]        — descendants of this artifact\n  supersedes          String? ObjectId — older artifact this replaces org-wide\n  usedByArtifactIds   String[]        — workflows/artifacts consuming this\n  derivedFromIds      String[]        — all artifacts this was built from\n  promptVersionId     String? ObjectId — prompt version that produced content\n  evaluationScores    Json?           — { grammar, brand, policy, legal, quality }\n  evaluatorsPassed    String[]        — evaluator names that passed\n  evaluatorsFailed    String[]        — evaluator names that failed\n\nNew models:\n  OsPlaybook        — versioned Playbook definitions (dagPattern, budgetCap,\n                      riskLevel, approvalPolicy, humanCheckpoints, metrics,\n                      retrospectiveQuestions)\n  OsPromptVersion   — versioned LLM prompt templates per capability\n  OsDecisionJournal — evidence/alternatives/debate/choice/outcome audit trail\n  OsModelRegistry   — available LLM models with cost/capability metadata\n\nCompanion: updated workflowNodes.test.ts fixture to include new OsWorkflow\nfields (all null/default values — no test logic changed).\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthr",
      "refs": {
        "commit": "efd18f8e9c8a66a29768e99a49ec6f2c693aa9ed"
      },
      "digest": "c9d4b2c17ebb99fb6191882746ca62e80d07bb3f5144e6ebbbf3b0fcc28b55d2"
    },
    {
      "id": "ship/claimyour.gold/7cbf5749ecfb",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T16:31:10Z",
      "kind": "docs",
      "title": "rewrite Session D1 documents to match spec exactly",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Previous v1.0 documents diverged from the spec in several ways:\n- CapabilityMetadata had wrong field names (spec requires: dependencies,\n  parallelizable, idempotent, retryPolicy, cacheTtlSeconds, failureStrategy)\n- Approved capability list was 8; spec requires 10\n- ContextPackage output shape was wrong (spec: systemContext, relevantFacts,\n  recentHistory, relatedArtifacts, activePlaybook)\n- Context Builder sources missing Artifacts and Playbooks as explicit tiers\n- Artifact lifecycle missing UnderReview and Published states; missing\n  usedBy lineage field\n- Evaluator pipeline missing Legal evaluator (spec: Grammar/Brand/SEO/\n  Legal/Policy/Quality)\n- Playbook schema missing: triggerConditions, requiredCapabilities,\n  dagPattern, budgetCap, riskLevel, approvalPolicy, humanCheckpoints,\n  metrics, retrospectiveQuestions\n- Planner doc missing explicit escalation path and DAG validation rules\n\nAll 7 documents rewritten to v2.0 with exact spec compliance.\n1883 lines total. No code changes.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "7cbf5749ecfb9754afecd56f457ac3f6f7b69d8b"
      },
      "digest": "897474f96095950c9b1f751647e150be0cfcf36001a98f0aeaafb048ca42a7d4"
    },
    {
      "id": "ship/claimyour.gold/9506f57943c0",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T16:20:09Z",
      "kind": "fix",
      "title": "address Architecture Guardian findings",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Four issues identified during guardian review:\n\n1. Race condition in updateWorkflowCost: replaced read-modify-write\n   with Prisma increment operations to make concurrent cost updates\n   atomic at the database level.\n\n2. updateArtifact accepted Partial<OsArtifact> which included id,\n   state, approvedAt, approvedBy — allowing callers to bypass the\n   artifact state machine. Constrained to safe mutable fields only\n   (title, content, evaluationNotes, confidenceScore, publishTarget).\n\n3. getArtifact returned null on not-found, inconsistent with getWorkflow\n   which throws AppError('NOT_FOUND', 404). Now throws consistently.\n\n4. event.payload['to'] cast to string via 'as' in LiveOpsCanvas. SSE\n   payload is untrusted; replaced cast with typeof guard.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "9506f57943c08c80b7393f48365a9f6cac05c932"
      },
      "digest": "91d0a03a063933b4b8929459785a7d69a18c3afb4717e39aa57f52d2f732dc04"
    },
    {
      "id": "ship/claimyour.gold/f91b862011ff",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T16:15:26Z",
      "kind": "feature",
      "title": "add Session D1 architecture design documents",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Seven design documents establishing the architecture of FlashyOS before\nany implementation session begins. These docs are the authoritative spec\nfor Sessions 2A–4C and must be read before those sessions start.\n\ndocs/flashyos/capability-registry.md — 14-field CapabilityMetadata,\n  registry design, DI pattern via ServiceContainer, 8 approved capabilities,\n  invocation lifecycle and budget enforcement.\n\ndocs/flashyos/context-builder.md — ContextPackage interface, 4-tier memory\n  sources, priority fill algorithm with overflow handling, token counting,\n  brand guidelines always-included rule.\n\ndocs/flashyos/memory.md — Working (Redis, 24h TTL), Semantic (MongoDB\n  vector search), Graph (BFS traversal), Timeline (OsEvent recency) tiers.\n  Retrieval policies per intent, cross-tier checkpoint write path.\n\ndocs/flashyos/planner.md — Playbook-driven planning (NOT arbitrary DAGs),\n  Reasoning Engine vs Planner split, 7-step execution flow, parameter\n  resolution strategies, escalation at confidence < 0.70, budget guardrails,\n  OsDecisionJournal integration.\n\ndocs/flashyos/artifact-model.md — Full lifecycle states, 14 lineage fields\n  (promptVersionId, parentArtifactId, supersedes, derivedFrom, citations),\n  artifact cache deduplication, immutability invariants.\n\ndocs/flashyos/playbooks.md — Full Playbook schema (17 fields), 12 initial\n  playbooks across core/marketing/bizdev/tech/operations domains, governance\n  process, versioning rules, registry service.\n\ndocs/flashyos/evaluator-pipeline.md — 5 chained evaluators (Grammar,\n  Brand, Policy, Quality, SEO), zero-tolerance enforcement for Brand/Policy,\n  confidence score weighting, 2-revision loop, short-circuit on failure.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "f91b862011ff2ce77d0ac7a2bb6f77f831e1a34b"
      },
      "digest": "bab0091def72060b891079ea1f21bb063ec65bf8c536d9022bd3f46fe760a9d3"
    },
    {
      "id": "ship/claimyour.gold/da345c590610",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T15:43:06Z",
      "kind": "feature",
      "title": "Session 1B — Live Ops canvas (React Flow + SSE)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "workflowNodes.ts (pure, 26 tests):\n  workflowsToNodes, workflowsToEdges, applyStateChange,\n  appendNode, filterNodes — all immutable, no side effects.\n\nuseOsEvents.ts (6 tests):\n  parseOsEvent validates JSON is a non-null object with type+source\n  fields (bare strings, arrays, invalid JSON all return null).\n  useOsEvents() opens one EventSource per mount; stable cbRef updated\n  in a separate useEffect to satisfy React Compiler ref-during-render rule.\n\nWorkflowNode.tsx:\n  Custom React Flow node — division pill, state badge with pulse\n  animation on AwaitingHuman, spin on Executing, 2-line title clamp,\n  cost display. data cast via (data as unknown as WorkflowNodeData)\n  per @xyflow/react v12 NodeTypes constraint.\n\nNewWorkflowModal.tsx:\n  Controlled form without useCallback (React Compiler handles\n  memoization). Escape key closes, title auto-focuses on open.\n\nLiveOpsCanvas.tsx:\n  Loads workflows on mount, WORKFLOW_STATE_CHANGED patches nodes\n  in-place (no re-fetch), WORKFLOW_CREATED triggers full reload.\n  Division filter + hide-completed toggle + New Workflow button.\n  NODE_TYPES defined outside component to prevent re-registration.\n  Wrapped in ReactFlowProvider; dynamic ssr:false import in page.tsx.\n\nlayout.tsx: position:fixed + inset:0 + z-index:50 overlays root footer.\n\nAll 1663 tests pass. Zero TypeScript errors.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "da345c590610735cabb45a4067975dfb5d8e8de6"
      },
      "digest": "4f3673ed800e1e6618ef6717724d51c6167d1f0ccf58dba869510cf7ef04e569"
    },
    {
      "id": "ship/claimyour.gold/c28aca52522a",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T15:33:33Z",
      "kind": "feature",
      "title": "Session 1A — state machine, event bus, workflow API, /ops shell",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "State machine engine (src/lib/os/stateMachine.ts):\n  12 workflow states with typed valid-transition graph.\n  transition() throws AppError INVALID_TRANSITION on illegal moves.\n  isTerminal(), isValidState(), getAllowedTransitions() helpers.\n\nEvent bus (src/lib/os/eventBus.ts):\n  Singleton OsEventBus wrapping Node EventEmitter.\n  publish/on/off API — used by all services to broadcast state changes.\n\nSSE stream (src/app/api/os/events/stream/route.ts):\n  GET /api/os/events/stream — requireSuperAdminSession, ReadableStream,\n  25s heartbeat, persists events to MongoDB via eventService.\n\nFull workflow service (src/services/os/workflowService.ts):\n  createWorkflow, getWorkflow, listWorkflows, transitionWorkflow,\n  updateWorkflow, updateWorkflowCost, getDashboardStats.\n  Every mutating call emits eventBus + writeAuditLog.\n\nAPI routes:\n  GET/POST /api/os/workflows\n  GET      /api/os/workflows/[id]\n  PATCH    /api/os/workflows/[id]/state\n\n/ops shell (src/app/(ops)/):\n  OsSidebar (client nav), dark layout, executive dashboard RSC,\n  stat cards + workflow table with state badges.\n  Error boundary + skeleton loading state.\n  Placeholder pages for all remaining tabs.\n\nTests: 35 new — stateMachine (full transition matrix) + workflowService (mocked).\nAll 1632 tests pass. Zero TypeScript errors.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "c28aca52522aa5d5cf9773523f236f0318811d4e"
      },
      "digest": "5d27dcfccf49d24c4f110d0599ffab9bfa4ac8461b1ecc16101b670fb3336670"
    },
    {
      "id": "ship/claimyour.gold/72bdfdde8f25",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-22T15:22:29Z",
      "kind": "feature",
      "title": "Session 0 — pre-flight schema, packages, and service stubs",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds 8 new Prisma models for FlashyOS Company Operating System:\nOsEvent, OsWorkflow, OsArtifact, OsKnowledgeNode, OsKnowledgeEdge,\nOsProject, OsObjective, OsCapabilityLog, OsBrainSnapshot.\n\nCreates typed service layer stubs in src/services/os/ for all models\nfollowing existing codebase patterns (prisma service layer, pino logger,\nno console.*, AppError, writeAuditLog, nullable queues).\n\nAlso adds the missing campaigns/[id]/route.ts that was causing a pre-existing\ntsc error in .next/dev/types/validator.ts.\n\nInstalls: @xyflow/react, reactflow, eventsource-parser, uuid.\n\nAll 1597 existing tests pass. Zero TypeScript errors.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "72bdfdde8f253c8b51f86e042fb13ba6691e000e"
      },
      "digest": "6c3976368a5d12aed14e822702fa8db2b72ddcbe6857ca1184ac9baa1b8634ff"
    },
    {
      "id": "ship/claimyour.gold/7c7a3f11c7be",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-17T13:13:05Z",
      "kind": "feature",
      "title": "three native Mini App screens — Dashboard, Quests, Refer (Prompt 3B)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Dashboard (/telegram-app/dashboard):\n- Fetches /api/v1/portal/me + /api/v1/portal/streak in parallel\n- Gold balance hero in brand gold, streak card with flame and relative\n  time, +goldIfClaimed badge when claimable\n- Telegram MainButton lifecycle: setText/enable/disable/show/hide wired\n  to canClaimToday; showProgress/hideProgress bracket the POST request;\n  impactOccurred('medium') on success, notificationOccurred('error') on\n  failure, showAlert() surfaces the error message to the user\n- In-page fallback button when running outside Telegram (tg === null)\n- Exports formatRelativeTime() and isClaimableToday() pure functions\n\nQuests (/telegram-app/quests):\n- Fetches /api/v1/portal/quests; splits into Available / Completed sections\n- TELEGRAM_JOIN two-step UX: safeInviteUrl() validates https: protocol\n  before rendering \"Join Channel\" link; claim button text changes to\n  \"I've joined — Claim Reward\" when an inviteUrl is present\n- Auto-complete quest types (REFERRAL_COUNT, STREAK_MILESTONE,\n  PARTNER_POINTS) show \"Completes automatically\" instead of a button\n- Per-card claim error display (NOT_A_MEMBER, ALREADY_CLAIMED,\n  QUEST_MISCONFIGURED mapped to human-readable strings); +N flash\n  confirmation fades after 3 s; impactOccurred('light') on success\n- Exports safeInviteUrl(), isAutoComplete(), getClaimErrorMessage()\n\nRefer (/telegram-app/refer):\n- Fetches /api/v1/referrals/me; shows referral code in monospace box\n- Copy button: navigator.clipboard.writeText() + notificationOccurred\n  ('success') haptic + \"✅ Copied!\" state for 2 s\n- Share button: tg.openTelegramLink() with pre-composed message; falls\n  back to window.open() when outside Telegram\n- Stats row: Referrals / Earned / Pending in brand gold\n- Empty-state prompt when total referrals is 0\n- Exports buildShareMessage() and buildShareUrl() pure functions\n\nShared:\n- Add showAlert() and openTelegramLink() to TelegramWebApp interface\n- All screens use var(--tma-*) CSS vars set by TelegramProvider\n- Loading skeleton",
      "refs": {
        "commit": "7c7a3f11c7bef0dd9f109e720a7919f029129595"
      },
      "digest": "9b1e756b14bd819492775a8eddfc256b86f0e05215b2f30887e7c584e3d6fc8e"
    },
    {
      "id": "ship/claimyour.gold/b14bda757f08",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-17T03:25:21Z",
      "kind": "feature",
      "title": "Telegram Mini App native shell foundation (Prompt 3A)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Add src/lib/telegram-webapp.ts: full TypeScript types for Telegram WebApp\n  SDK (TelegramWebApp, TelegramThemeParams, MainButton, BackButton,\n  HapticFeedback), applyTelegramTheme() pure function with 5 CSS vars\n  (--tma-bg, --tma-secondary-bg, --tma-text, --tma-hint, --tma-button)\n  and brand-gold fallbacks, declare global Window augmentation\n\n- Add src/components/mini-app/TelegramProvider.tsx: React context that\n  initialises the SDK on mount (expand + ready), injects Telegram theme\n  colours into document.documentElement, and exposes useTelegram() hook\n  that throws a clear error when called outside the provider\n\n- Add src/app/(mini-app)/telegram-app/layout.tsx: new (mini-app) route\n  group layout with 3-tab fixed bottom navigation (Dashboard / Quests /\n  Refer), safe-area-inset-bottom padding, active-tab gold indicator,\n  wraps all children in TelegramProvider\n\n- Move src/app/(portal)/telegram-app/page.tsx → (mini-app): removes\n  inheritance of portal GlobalHeader / PortalRouteBackground / Prisma\n  query; updates verified-user redirect to /telegram-app/dashboard\n\n- Extend next.config.ts header override to /telegram-app/:path* so all\n  Mini App sub-routes allow Telegram iframe embedding (X-Frame-Options:\n  SAMEORIGIN, COOP: unsafe-none)\n\n- Add tests/lib/telegram-webapp.test.ts: 16 pure-function tests for\n  applyTelegramTheme (all 5 vars, fallbacks, partial params) and\n  TELEGRAM_CSS_VARS constant shape — no jsdom required\n\n- Add tests/components/mini-app/TelegramProvider.test.ts: 7 tests for\n  useTelegram hook via mocked React.useContext (throws on undefined,\n  returns null/WebApp, module export smoke tests)\n\nAll 1,542 tests pass. Zero TypeScript errors.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "b14bda757f08afead6d8fea11e5caf3124bfc339"
      },
      "digest": "0499fcc419f1b24435df9da7ecd978d8a2145243452c6db6577796060026c1ce"
    },
    {
      "id": "ship/claimyour.gold/fc64fff631f4",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-17T03:02:29Z",
      "kind": "feature",
      "title": "configurable TELEGRAM_JOIN quest verification via per-quest metadata",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Previously, all TELEGRAM_JOIN quests used a single hardcoded TELEGRAM_CHANNEL_ID\nenv var, making it impossible to run multiple channel campaigns simultaneously.\n\nChanges:\n- questVerification.ts: extend VerificationContext with questMetadata field;\n  verifyTelegramMembership resolves chatId from quest.metadata.chatId first,\n  falling back to TELEGRAM_CHANNEL_ID env var for backward-compat; throws\n  QUEST_MISCONFIGURED (400) when metadata is present but chatId is missing\n- claim/route.ts: call getQuest(slug) before verification so quest metadata\n  is available to the verifier; also surfaces QUEST_NOT_FOUND (404) earlier\n- quests-client.tsx: two-step UX for TELEGRAM_JOIN quests — \"📢 Join Channel\"\n  button (when metadata.inviteUrl is a valid HTTPS URL) followed by\n  \"✅ I've joined — Claim Reward\" button; inviteUrl is validated client-side\n  before rendering to prevent open-redirect\n- openapi.yaml: document chatId, inviteUrl, and targetCount metadata fields\n  with type-specific descriptions\n- +22 new tests: 7 new questVerification cases, 15 new claim route cases;\n  updated portal-quests*.test.ts mocks to include getQuest and relaxed\n  exact-shape assertions to objectContaining where questMetadata is now present\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "fc64fff631f425db9a0cfcd09f8cd3b558431c8d"
      },
      "digest": "9e7b5182335741066a38bb0b0adcb3ba6ee1852406fc5decf79e12a68041856a"
    },
    {
      "id": "ship/claimyour.gold/93aeb4018fae",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-17T02:45:55Z",
      "kind": "fix",
      "title": "allow Telegram Mini App iframe embedding on /telegram-app",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Override X-Frame-Options: DENY → SAMEORIGIN and COOP: same-origin →\nunsafe-none for the /telegram-app route so Telegram's WebView can embed\nthe Mini App page. CSP frame-ancestors (already set in middleware.ts to\nallow *.telegram.org) remains the authoritative framing gate for modern\nbrowsers and WebViews.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "93aeb4018fae05fdf29398edfef0174ba4412476"
      },
      "digest": "ca395e4b29913ab5b7cf0e5e215dfca9d57eb86626c262b425451e20b39e9e9f"
    },
    {
      "id": "ship/claimyour.gold/80832b813a98",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-17T02:39:45Z",
      "kind": "feature",
      "title": "add Telegram Mini App entry page and web_app button wiring",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- New page at /telegram-app: reads initData from window.Telegram.WebApp,\n  POSTs to /api/v1/portal/auth/mini-app, redirects to dashboard or\n  verify-email depending on account state; falls back to /portal/login\n  when opened outside Telegram (5 s safety timeout)\n- telegramBot.ts: add web_app button type to InlineKeyboardButton, export\n  MINI_APP_URL constant, add webAppButton() helper; update buildStartReply\n  (Claim CTA), buildClaimReply, buildRewardsReply, and buildHelpReply\n  (Open Portal) to use web_app buttons; drop unused ctx param from\n  buildClaimReply and buildRewardsReply; remove now-unused portalUrl()\n- telegramNotify.ts: update notifyStreakReminder and notifyQuestCompletion\n  CTAs to web_app buttons; fix remaining console.error → logger.error\n  violations across all six notification functions (CLAUDE.md rule)\n- 14 new tests in telegramBot.test.ts (first coverage of reply builders);\n  updated streak and quest tests to assert web_app button shape\n\nBotFather manual step: /setmenubutton → @claimyourgold_bot → https://claimyour.gold/telegram-app\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "80832b813a987b1e97b36e116f0e63a2922aa4ca"
      },
      "digest": "88617812a7fa53464cd30034a561108069fce3567f061257ec75d99a14568886"
    },
    {
      "id": "ship/claimyour.gold/634298fad130",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-17T02:25:09Z",
      "kind": "feature",
      "title": "add Telegram Mini App initData auth endpoint",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "POST /api/v1/portal/auth/mini-app authenticates users via the signed\ninitData payload from window.Telegram.WebApp.initData, enabling\n@claimyourgold_bot to operate as a first-class Telegram Mini App.\n\n- Verifies initData with the existing verifyTelegramInitData() from\n  production-telegram-auth.ts (no new crypto code)\n- Dual rate-limit: IP before verification, Telegram ID after (matching\n  the widget auth pattern in /portal/auth)\n- Correctly stringifies TelegramUser.id (number) before passing to\n  syncTelegramLogin (string param)\n- All three session paths: new user (onboarding cookie), returning\n  verified (session + clear onboarding), returning unverified (both)\n- Uses logger throughout — no console.error\n- No BYPASS_AUTH block, no direct Prisma imports\n- 28 new tests covering all paths, error codes, and the number→string\n  conversion; 1484 total passing\n- OpenAPI spec updated with full request/response documentation\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "634298fad130378e8e8e88dba1e945ed3af39ad1"
      },
      "digest": "3e65906c4ec7f345efbbbfd4c968e8c9c9dbe87e51db1d5e78e3f9c96a9f5cbf"
    },
    {
      "id": "ship/claimyour.gold/d27cfe759af2",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-17T00:04:11Z",
      "kind": "infra",
      "title": "add accretive E2E and API route tests (portfolio, streak, user-balance, partner journey)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Four new test files covering genuine gaps in the existing suite:\n\n- tests/api/portfolio.test.ts — GET /api/v1/customer/portfolio was completely\n  untested; covers auth (real HMAC session token), rate limit, success shape,\n  and AppError propagation (CUSTOMER_NOT_FOUND → 404).\n\n- tests/api/streak.test.ts — GET + POST /api/v1/portal/streak were untested;\n  covers both methods including STREAK_ALREADY_CLAIMED AppError → 400\n  propagation, which existing service tests throw but no route test verified.\n\n- tests/api/user-balance.test.ts — GET /api/v1/partner-api/user-balance was\n  untested; covers missing/invalid email validation, CORS headers, and\n  OPTIONS preflight.\n\n- tests/e2e/partner-api-journey.test.ts — structural gap: all existing API\n  tests mock the service layer; all service tests mock Prisma. This file is\n  the first to call real route → real partnerApiService → mocked Prisma,\n  catching wiring bugs, argument passing, response mapping, and idempotency\n  end-to-end (same-client idempotent 200 vs cross-client 400 distinction).\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "d27cfe759af2960130c5ea970a5a07ffb1bb22cd"
      },
      "digest": "c23c8ec5cc766bc1d65297fecdc751ff1f3864d47de96cfd77a3a766e59d344f"
    },
    {
      "id": "ship/claimyour.gold/e6dae31597a3",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T23:08:18Z",
      "kind": "docs",
      "title": "add OpenAPI 3.1 spec for all API routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Static docs/openapi.yaml covering ~120 endpoints across all API surfaces:\nhealth, public, waitlist, portal auth, portal features, referrals, partner API\n(award-points, batch, user-balance, tournament stats), client dashboard,\nsupport, Telegram bot, TOTP, and super-admin (tagged internal).\n\nIncludes reusable schemas for all core domain objects, four auth security\nschemes (PortalSession, PartnerApiKey, HmacAuth, ClientSession), and\nstandard error/rate-limit response components.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "e6dae31597a360b8296a438802ce69f4cca2dd40"
      },
      "digest": "4e3f2f9dacf495f0448cc3cd046b42a2c45e9a5797e77bd89dcc5d19ab840880"
    },
    {
      "id": "ship/claimyour.gold/95f64a8dae90",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T22:59:36Z",
      "kind": "infra",
      "title": "add husky pre-commit and pre-push hooks",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Pre-commit: lint-staged (ESLint on staged TS/TSX) + full tsc type check\nPre-push: full jest test suite (1408 tests)\n\nKeeps the commit gate fast (<10s) while ensuring no type errors or broken\ntests reach the remote. lint-staged config added to package.json.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "95f64a8dae9007a0d07b89c0a160f3d406bb5300"
      },
      "digest": "94e7565c2f7e3ae03b8b7185a2ddb96b341cff52d4ff78f8fca2d349650b4d0d"
    },
    {
      "id": "ship/claimyour.gold/45252cfba97d",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T22:14:10Z",
      "kind": "docs",
      "title": "add production troubleshooting guide and update CLAUDE.md index",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Comprehensive 13-section runbook covering all production incident scenarios:\nfirst-response checklist, service health checks, auth/session issues,\nclaim flow errors, email delivery, Telegram bot, rate limiting, BullMQ\njob failures, database/Redis issues, Cloud Run deployment, complete\nAppError code reference, and P0–P3 escalation paths.\n\nCo-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "45252cfba97daede0d99b46da90cda87c2a2503b"
      },
      "digest": "42cbd152e3e8413a255a7371139c3ffcb87ac56ec52c27735a2563d005efbc07"
    },
    {
      "id": "ship/claimyour.gold/84643f0a0813",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T21:56:42Z",
      "kind": "fix",
      "title": "update seed-matrix-article upsert to set order=2, publishedAt=2026-06-15",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "84643f0a08134592712695f96da95e9bdbdbf828"
      },
      "digest": "51193fd124ef95a636e1658d6c90049e0a9c213bb09d43a2e79aab3ee5379fbb"
    },
    {
      "id": "ship/claimyour.gold/d6a55de0343b",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T21:56:20Z",
      "kind": "fix",
      "title": "set chronological order and dates on all articles",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Press page sorts by order ASC then publishedAt DESC. Updates:\n\n  order=1  publishedAt=2026-06-16  Redemption Waitlist (newest, top)\n  order=2  publishedAt=2026-06-15  Matrix Season 1 Gold Rush\n  order=3  publishedAt=2026-06-10  Flashy Gold × Predictfully\n  order=4  publishedAt=2026-05-27  claimyour.gold Launch (oldest, bottom)\n\nAll seed/update scripts now force-set order and publishedAt on upsert.\nAdded production branch trigger to claimyourgold and matrix workflows.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "d6a55de0343bef1e0270a8c852239d070d9657b3"
      },
      "digest": "897de218e26e40f1e1655d8253c9f56b2bed085855931384244a8853752bcf74"
    },
    {
      "id": "ship/claimyour.gold/9c7ab5d91d48",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T21:52:06Z",
      "kind": "fix",
      "title": "update redemption waitlist article banner to flashygroup.com upload",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "9c7ab5d91d48b92d96bb2ca1950bac02fa0735f2"
      },
      "digest": "03a71c863581911ad3a4d63e88fe577ba17dc5d23cb4c3ffbc655c638b0e00a7"
    },
    {
      "id": "ship/claimyour.gold/a81c9f2ef278",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T21:39:41Z",
      "kind": "fix",
      "title": "reduce Predictfully wordmark height to h-6 to match Flashy logo",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The wordmark (160×42px intrinsic) filled its full h-8 height with text,\nwhile the Flashy SVG (130×60px) has internal padding so appears smaller\nat the same CSS height. Dropping the wordmark to h-6 (24px) balances\nthe two logos visually.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "a81c9f2ef278209e340d37a31edc50513ff4cdc7"
      },
      "digest": "cf388e9f331555965b8eec81c0557be3a3912da5d4c1463f574fd8ba7e7c3f07"
    },
    {
      "id": "ship/claimyour.gold/8b1cb6ded665",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T21:35:01Z",
      "kind": "fix",
      "title": "set OG image on redemption waitlist article to claimyourgold-logo.png",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Sets coverImage to https://claimyour.gold/claimyourgold-logo.png so\nWhatsApp, Telegram, Twitter, and other platforms show the Claim Your Gold\nlogo when the article URL is shared, instead of the platform default.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "8b1cb6ded665e4594f6a9aea991f33d4a2b1c6b6"
      },
      "digest": "1e4cc9ec199592328a33df9a7e0b8489aa1406194650113da590289748587e35"
    },
    {
      "id": "ship/claimyour.gold/02851e2a471a",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T21:30:48Z",
      "kind": "feature",
      "title": "add Flashy Gold Redemption Waitlist is Now Open article",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Institutional press article announcing the redemption waitlist opening.\nCovers: what the waitlist is, eligibility criteria, how to register,\nwhat happens after registration, and about Flashy Gold / Flashy Group.\n\nSEO: primary keyword 'Flashy Gold redemption', structured H2s for LLM\nextraction, internal cross-links to launch/Matrix/Predictfully articles,\nexternal links to claimyour.gold, flashy.gold, flashygroup.com.\n\nSlug: flashy-gold-redemption-waitlist-open\nPublished: 2026-06-16\nCover image: placeholder (to be updated separately)\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "02851e2a471a402e5d6aaa2f808fa303c91c8f9d"
      },
      "digest": "cd8760fbc2ea03ea35b21ca1a53d060f11deac5ab1f777384879c60832eb0b03"
    },
    {
      "id": "ship/claimyour.gold/5c3cdd6dcd42",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T21:16:16Z",
      "kind": "fix",
      "title": "update Predictfully article cover image to Predict-For-Gold banner",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "5c3cdd6dcd42f61d213e5f8fedf4a26eead7a6bc"
      },
      "digest": "cee77e7839e7d9459ac15b45e9472959670b4ce9f84800e86dbc80fb80a57c7e"
    },
    {
      "id": "ship/claimyour.gold/c0f2b35da8fa",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T21:11:15Z",
      "kind": "feature",
      "title": "add Flashy Gold × Predictfully launch article",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Seed script + GitHub Actions workflow to publish the Predictfully\ncampaign article to the production DB. Article covers:\n- What the campaign is and how to participate\n- Predict-for-Gold earn model explanation\n- Cross-link to Matrix Season 1 article, flashy.gold, flashygroup.com\n- Support links: t.me/FlashyOfficialHQ, support@claimyour.gold\n- Published date: 2026-06-16\n- Slug: flashy-gold-predictfully-predict-for-gold\n\nWorkflow triggers on push to production when the workflow file changes.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "c0f2b35da8fad895df1fb37c1e1b04bfac3a0b81"
      },
      "digest": "335f37ea2aa04085639e016eea9d6b7365b74e891d700d74367c0df24f4399c9"
    },
    {
      "id": "ship/claimyour.gold/53eb977eb7e2",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T20:50:41Z",
      "kind": "fix",
      "title": "update 'Learn more' URL and support Telegram link",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- 'Learn more' button → https://FlashyWorldCup.com (was support Telegram)\n- Telegram support link → https://t.me/FlashyOfficialHQ (was flashygold_support)\n- Added separate learnMoreUrl field to CAMPAIGN config to decouple the\n  two CTAs going forward\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "53eb977eb7e2dbe5a3ce6e80ccfc23cbc41c6ef5"
      },
      "digest": "fadced0e944912f4b27eec86ceebdad2fb8963126c109d9c17a1efa6a3c589ea"
    },
    {
      "id": "ship/claimyour.gold/a9d4c797c2d3",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T20:49:00Z",
      "kind": "feature",
      "title": "set status to LIVE — green badge in nav and page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Updates both the CAMPAIGNS registry (navbar dropdown source of truth)\nand the page's own CAMPAIGN config so the status badge reads \"Live Now\"\nwith a green pulsing dot, matching the Matrix campaign styling.\nAlso updates kickoffLabel from 'Coming Soon' to 'June 2026'.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "a9d4c797c2d3451702703e24cb2be7c6a71d7595"
      },
      "digest": "08f00538b9183be4e533ba7eba368fc6c2e992df3d9855ccaf82f7f76b0da786"
    },
    {
      "id": "ship/claimyour.gold/10299307277c",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T20:47:47Z",
      "kind": "fix",
      "title": "fix wordmark logo, remove double 'Flashy', consistent branding",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Logo:\n- Switch Predictfully wordmark from next/image to plain <img> to bypass\n  Next.js remotePatterns build-time requirement; logo now loads reliably\n  from media.base44.com regardless of config state\n\nCopy (6 occurrences fixed):\n- metadata description: 'Flashy Flashy Gold' → 'Flashy Gold'\n- FAQ answer: 'Flashy Flashy Gold' → 'Flashy Gold'\n- Hero paragraph: 'Flashy Flashy Gold' → 'Flashy Gold'\n- Hero headline: 'Earn Gold.' → 'Earn Flashy Gold.'\n- Section heading: 'Three steps to earn Gold' → 'Three steps to earn Flashy Gold'\n- Step 01 body: 'Flashy Flashy Gold' → 'Flashy Gold'\n\nTests: 7 new assertions covering logo tag, eslint disable comment,\nalt text, and branding consistency (no double-Flashy, earn-Flashy-Gold)\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "10299307277cf7177307c8c7db91903fc60ce933"
      },
      "digest": "3380a3d8f395b0c6d27ab773000ca8c280ec4c66f75f087cb07e86cb5a0abcde"
    },
    {
      "id": "ship/claimyour.gold/0a02f3e0ce70",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T20:41:43Z",
      "kind": "fix",
      "title": "poll for cross-device email verification",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "When a user requests a verification link on mobile but clicks it in a\ndesktop browser, the mobile \"Check your inbox\" screen was stuck — it had\nno mechanism to detect that verification had completed elsewhere.\n\nFix: add a useEffect that fires when sent === true and:\n- Polls /api/v1/portal/onboarding every 5 s; if the response is\n  ALREADY_VERIFIED, the DB has been updated by the link click on the\n  other device — redirect to /portal/login?verified=1 immediately.\n- Also fires on visibilitychange (visible), covering the same-device\n  case where the user opens the email app in another tab and switches\n  back.\n\nCleanup (active flag + clearInterval + removeEventListener) prevents\nstate updates on unmounted components and stops polling as soon as the\nuser navigates away or verification is detected.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "0a02f3e0ce70b79e622f5983ecc2db099fe5056c"
      },
      "digest": "dd3f7d2df0333be5bc236e5795c2ae156bf99be1f2f26ef83fbf621ad1f72a8b"
    },
    {
      "id": "ship/claimyour.gold/aeff620f8abd",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T20:32:00Z",
      "kind": "feature",
      "title": "launch Predictfully — nav, logo, indexable, remove platform stats",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Add Predictfully entry to CAMPAIGNS registry (status: UPCOMING, indexable: true)\n  so it appears in the navbar dropdown and /campaigns page automatically\n- Allow media.base44.com in next.config.ts image remote patterns for wordmark\n- Swap plain \"Predictfully\" text in hero badge for <Image> wordmark from base44 CDN\n- Set INDEXABLE = true so /predictfully is now crawlable and in the sitemap\n- Remove \"Platform / Powered by Flashy Gold\" stats section and unused StatCard\n- Update tests to reflect new public state (was hidden/noindex, now live/indexable)\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "aeff620f8abd1924a36fd295145a22fba132517b"
      },
      "digest": "4b2a2c9d592636b0b799cce12717256b7868bc1872d6a59f4a5e46099ca40c8d"
    },
    {
      "id": "ship/claimyour.gold/44dd1f34687d",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T20:16:44Z",
      "kind": "feature",
      "title": "Pass 3 — super admin UI, nav link, unsubscribe tests",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds /super/waitlist operations page: stat cards (total/today/pending/\nnotified), Export CSV button, Send Launch Broadcast with confirmation\ndialog showing exact pending count, entries table with email/source/\njoined/status columns, offset-based pagination (50/page).\n\nAdds Waitlist link to super admin sidebar nav.\n\nCloses test gap: 6 new tests for GET /api/v1/waitlist/unsubscribe\n(valid token, invalid, expired, missing, already-removed, unexpected\nerror). Full suite: 1394 tests passing, tsc clean, zero regressions.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "44dd1f34687d5985ee123656218e8567c927deda"
      },
      "digest": "3dd768b61cf4c9d6c577be9d3c5ca8d7fce73f763b6879e655375e142f76f0fe"
    },
    {
      "id": "ship/claimyour.gold/21dd19d561e7",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T20:10:29Z",
      "kind": "feature",
      "title": "Pass 2 — modal UI and dashboard CTA",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replaces the Telegram link on the dashboard with an in-product waitlist\ncapture modal. WaitlistModal uses Radix Dialog with idle/loading/success/\nerror states, pre-fill for authenticated email, ARIA attributes, Escape-\nto-close, Enter-to-submit, mobile responsive. GoldBannerCTA is a lazy-\nloaded client wrapper preserving surrounding layout. Dashboard exposes\ncustomer.email and removes href to telegram.org. 19 new API route tests,\n1388 total passing, tsc clean.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "21dd19d561e7d0d65d7e15d35a64f55c88718892"
      },
      "digest": "09910dfec50bb4c792539ebf2b7061840a4bf480d7729b594f8ac63cb8187f7b"
    },
    {
      "id": "ship/claimyour.gold/98db12ae3ff3",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T20:01:33Z",
      "kind": "infra",
      "title": "move prisma CLI to devDependencies",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "98db12ae3ff301214856c0e461e28b6f5aee3fe9"
      },
      "digest": "9c84c49549857c0e03df9bf4cfab86a93cd07d415f45cf27afa1154be2cc7610"
    },
    {
      "id": "ship/claimyour.gold/9ec86ddcf29a",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T20:00:47Z",
      "kind": "feature",
      "title": "Pass 1 — data, API, and email infrastructure",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds full waitlist capture and notification system:\n- WaitlistEntry Prisma model (email unique, source, userId, notifiedAt)\n- waitlistService: join (idempotent upsert), unsubscribe (HMAC token),\n  stats, paginated entries, broadcastLaunch (batch, stamp-before-send,\n  rollback on failure)\n- POST /api/v1/waitlist — rate limited (5/15min), validates source\n- GET  /api/v1/waitlist/unsubscribe — HMAC-signed token, 30-day expiry\n- GET  /api/v1/super/waitlist — stats + paginated entries + CSV export\n- POST /api/v1/super/waitlist/broadcast — idempotent batch broadcast\n- Resend confirmation + broadcast emails with unsubscribe link\n- waitlistRateLimit added to rateLimit.ts\n- 13 tests, tsc --noEmit clean\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "9ec86ddcf29abd1120256360feb83b724a7c5707"
      },
      "digest": "aefbd669a7cdbedff3fa8674e408ca7b77f0bace3f32eaf6414d174502ffe3d2"
    },
    {
      "id": "ship/claimyour.gold/4cff6a46f9c8",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T19:31:39Z",
      "kind": "feature",
      "title": "add banner image to claimyour.gold launch article",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "4cff6a46f9c8687795559808cd98a26421a93ff2"
      },
      "digest": "71c05514442e026dd16f64a2ab0d92f3ff7f37bd5a97b1b3c83bf7e95cda90d3"
    },
    {
      "id": "ship/claimyour.gold/e9be3e26ab98",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T19:30:07Z",
      "kind": "feature",
      "title": "update claimyour.gold launch article - May 27 2026, remove TVL/nGRND",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Corrects launch date to May 27 2026, removes $35M TVL reference and\nnGRND Inc. mention from article body and excerpt. Script now also\nupdates existing article if already seeded.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "e9be3e26ab98f74cb10ebc3275a8ada59ee48f0b"
      },
      "digest": "0df15fb601ad714d9bc73811070a58d3ea415ba4c430b620c340ed77e59f8196"
    },
    {
      "id": "ship/claimyour.gold/fe6c2e32150e",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T19:27:09Z",
      "kind": "feature",
      "title": "add claimyour.gold launch article (Feb 5 2026, $35M RWA TVL)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Creates seed script and GitHub Actions workflow to publish the\nclaimyour.gold launch press article to production DB. Article dated\nFebruary 5 2026, includes full earn model links, internal cross-links\nto Matrix article, external links to flashygroup.com and flashy.gold,\nSEO title/description/keywords, and institutional-grade copy.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "fe6c2e32150e12af403b934f185e5e4cd8e0a165"
      },
      "digest": "e7488ddb8d4102d1ecfcdd2818b5497a0d7b43f1143ef3a8b184e97d2753a729"
    },
    {
      "id": "ship/claimyour.gold/c416bdbc0a72",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T18:58:39Z",
      "kind": "feature",
      "title": "update Matrix article links + replace em-dashes with commas",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Each earn model now links to its dedicated Flashy Group learn page:\n  Play-for-Gold, Move-for-Gold, Engage-for-Gold, Attend-for-Gold,\n  Watch-for-Gold, Predict-for-Gold -> flashygroup.com/learn/what-is-*\n- \"Flashy Gold\" linked to flashy.gold throughout the article\n- All em-dashes (—) replaced with commas for cleaner prose flow\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "c416bdbc0a721881eb15436b559c2ae419515f5e"
      },
      "digest": "8353c67b7512209d7915465c83d48a8ece6d12aa3ceba3604053c145ebca2c8b"
    },
    {
      "id": "ship/claimyour.gold/c7358359f5b5",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T18:43:26Z",
      "kind": "feature",
      "title": "set Matrix article cover image (Gold Rush banner)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "c7358359f5b5b50fbe7957e51ec3d910966eabba"
      },
      "digest": "f65d1e2b01943b1f4a12041c60e1f7d0e42b7dad131c3212f678fbaa932db29a"
    },
    {
      "id": "ship/claimyour.gold/78a0fcaaf598",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-16T18:37:35Z",
      "kind": "feature",
      "title": "enhance article SEO metadata for search + LLM crawlers",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Add missing meta tags and structured data:\n- keywords meta from article.tags array\n- og:site_name, og:url, og:modifiedTime, og:tags (article:tag)\n- twitter:card (summary_large_image when coverImage present, else summary)\n- twitter:title, twitter:description, twitter:images\n- JSON-LD: keywords, mainEntityOfPage, publisher @type Organization,\n  ImageObject dimensions for coverImage\n\nThese fields are parsed by Google, Bing, ChatGPT, Perplexity, and other\nLLM crawlers when indexing article content.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "78a0fcaaf598f57dce0e17377cbc47a4e6eb4947"
      },
      "digest": "394872b9702bb91bd022755996b1490348341a690b27461aaad11bff78af22e0"
    },
    {
      "id": "ship/claimyour.gold/1eb2bd6cf163",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-15T16:20:47Z",
      "kind": "fix",
      "title": "exclude .claude worktrees from jest test discovery",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Added testPathIgnorePatterns to prevent Jest from picking up test files\nin git worktrees under .claude/worktrees/, which caused spurious failures\nwhen worktree tests referenced services unavailable in that worktree.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "1eb2bd6cf163611aa6cb172998cb563d90789aae"
      },
      "digest": "564b56c0c3ed606aa941a60e54115c2321a000d7e58e799c5b554b3feb82fb95"
    },
    {
      "id": "ship/claimyour.gold/efd0827e1808",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-15T16:16:33Z",
      "kind": "feature",
      "title": "referral intelligence, callback SLA panel + bulk CSV export",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "efd0827e1808aa7c9747a51cd951e3c76679ff1d"
      },
      "digest": "e675754ae1e9193edd44dd8ba4cdcaf3eb8ccb0b1e08d5722ccea9a28603f859"
    },
    {
      "id": "ship/claimyour.gold/a77bf17b00cc",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-15T15:51:07Z",
      "kind": "infra",
      "title": "ignore .claude session directory",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "a77bf17b00cc6ef7053d461721a0fe3e0ef85831"
      },
      "digest": "33720ff2c42a86f3f394cdffe5b9d39d337b97b70f7ae99fbc05bef27996d42d"
    },
    {
      "id": "ship/claimyour.gold/570ca206fee5",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-15T15:49:51Z",
      "kind": "feature",
      "title": "customer drill-down + quest analytics dashboard",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Add getCustomerDetail() + CustomerDetailData interface to superAdminService.ts\n- New GET /api/v1/super/customers/[id] route with auth guard and AppError handling\n- New super/users/[id] page with tabbed UI (Overview, Transactions, Quests, Badges, Referrals)\n- Make users table rows clickable (router.push to detail page)\n- Add listQuestsWithStats() to questService.ts with per-quest completion/user/gold stats\n- Update GET /api/v1/super/quests to support ?includeStats=true param\n- Update quests page to use includeStats=true, show summary banner and Completions/Users columns\n- Add super-customer-detail.test.ts (4 tests) and extend super-quests.test.ts (4 new tests)\n- All 1338 tests pass, tsc --noEmit clean\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "570ca206fee56fff20e58512a643db3df9a76293"
      },
      "digest": "8d1110ec5b095d1aebfa9f7b060f9eb7ad2158dbd79d283da3ba762255cdce4f"
    },
    {
      "id": "ship/claimyour.gold/c50ae07e0961",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-15T15:33:53Z",
      "kind": "feature",
      "title": "persistent audit log — DB-backed trail for all super admin actions",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Add AuditLog model to schema (actor, action, entityType, entityId, before/after JSON, ip, userAgent)\n- New auditLogService: writeAuditLog (fire-and-forget, never throws) + listAuditLogs (paginated, filterable)\n- Wire audit logging into all mutating service functions: client/partner lifecycle, quests, articles, campaigns, streak config\n- Add optional actor param to activateQuest, deactivateQuest, publishArticle, unpublishArticle, deleteArticle, createCampaign, activateCampaign, deactivateCampaign\n- All calling routes now pass actor (email or \"operator\") through to services\n- GET /api/v1/super/audit-logs route with filters: actor, entityType, entityId, action, from, to, page, limit\n- /super/audit-logs UI page: filterable table with expandable before/after JSON diff\n- Sidebar nav updated with Audit Log link\n- 22 new tests across auditLogService + API route; 1331 total passing, 0 TS errors\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "c50ae07e09617e95ff5eb9c1c3f21ad574c82940"
      },
      "digest": "31a325165b1e80db63e39d18e34f4ecd931ce0b64d02ade9dd5d2baebc6c109f"
    },
    {
      "id": "ship/claimyour.gold/34c467d018bf",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-15T14:51:52Z",
      "kind": "feature",
      "title": "server-side quest verification for telegram/profile/redemption quests",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds runQuestVerification() registry called before claimQuestReward. Verifies\nTelegram channel membership (getChatMember API), email verification for\nprofile completion, and redemption history for first-redemption quest.\nFails open on Telegram API errors to avoid blocking legitimate claims.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "34c467d018bf1341858a742c4e38210e20ca477e"
      },
      "digest": "e092b6f43cbe8b6d4ab40e4217bf49f45a2350a98d69590c63ff648943dbae52"
    },
    {
      "id": "ship/claimyour.gold/5fc1ac18dcb2",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-15T14:49:33Z",
      "kind": "feature",
      "title": "server-side quest verification for telegram/profile/redemption",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds runQuestVerification() registry called before claimQuestReward.\nVerifies Telegram channel membership (getChatMember API), email\nverification for profile completion, and redemption history for\nfirst-redemption quest. Fails open on Telegram API errors to avoid\nblocking legitimate claims. Unregistered slugs are honour-system.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "5fc1ac18dcb2176b71df9b1f76e312774e9541f3"
      },
      "digest": "3fcf0a8b6363f6ccb659a18990fa0ab20830cd0a8a56d45655acacb7302f9e6a"
    },
    {
      "id": "ship/claimyour.gold/f1ce8457fc6f",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-12T18:53:03Z",
      "kind": "feature",
      "title": "operator API token for programmatic content management",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds OPERATOR_API_TOKEN bearer auth as an alternative to super admin\nsessions on quest and article write endpoints. Enables Claude Code to\ncreate/publish content from the terminal without browser cookies.\nUses constant-time comparison (timingSafeEqual) to prevent timing attacks.\nGET/LIST endpoints remain super-admin-only.\n\nAlso consolidates async params fixes and sitemap force-dynamic onto the\nfeature branch so production and feature branches are fully in sync.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "f1ce8457fc6f6782ea0033f60b8f3afebe2432aa"
      },
      "digest": "ebe8d86531c4b43d355e1f1eb585c983e170cd87d34119dc8820759261868882"
    },
    {
      "id": "ship/claimyour.gold/64a7d36fd880",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-12T17:29:41Z",
      "kind": "feature",
      "title": "Learn & Press content engine",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds a Mongo-backed CMS for publishing articles to /learn and /press\nwithout requiring a redeploy. Includes super admin editor, public pages\nwith full SEO/JSON-LD schema, Redis caching for public listings, and\ndynamic sitemap entries.\n\n- prisma: Article model + ArticleSection enum (LEARN/PRESS)\n- articleService: CRUD, publish/unpublish, Redis-cached public listing, read-time estimator\n- API: /super/articles (list+create+get+update+delete+publish+unpublish), /public/articles (rate-limited)\n- Super admin UI: filter tabs, create/edit modal, publish toggle, delete confirm\n- Public pages: /learn, /learn/[slug], /press, /press/[slug] with generateMetadata + JSON-LD\n- global-header: Learn + Press links in public nav\n- sitemap: async, includes published article URLs\n- Tests: 40 new tests covering articleService, super-articles API, public-articles API\n- All 1245 tests pass\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "64a7d36fd880eed1fbc5dd6b1a4c145caefdf498"
      },
      "digest": "f8dee6fa40a053f98b83416511200b50f5cf1376cb479d1087057a1c265b0cc7"
    },
    {
      "id": "ship/claimyour.gold/c1db230405c3",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-12T17:08:23+02:00",
      "kind": "feature",
      "title": "Phase 9 + 10a — campaign management UI, daily streaks, configurable rewards",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "feat: Phase 9 + 10a — campaign management UI, daily streaks, configurable rewards",
      "refs": {
        "commit": "c1db230405c3af4ec907b839ff5c202277f15695"
      },
      "digest": "da454b5de65b837957d49e1c6db7ca31d0b17f6369177a277fa6998670c32bc0"
    },
    {
      "id": "ship/claimyour.gold/250641f02738",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-12T16:49:20Z",
      "kind": "feature",
      "title": "merge Phase 11a + 11b — Quest Engine backend + frontend",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Quest Engine backend: Quest model, 6 QuestTypes, atomic claim with\n  multiplier + idempotency + capacity cap, Redis cache, auto-complete\n  (REFERRAL_COUNT/STREAK_MILESTONE/PARTNER_POINTS), partner API with\n  CORS, Telegram quest completion notifications\n- Quest Engine frontend: Super admin /super/quests CRUD page, portal\n  quest list using live DB-backed API with all quest type CTAs\n- 1205 tests, tsc clean\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "250641f027389aa8aae6607acc0eb57d2dd69811"
      },
      "digest": "7fd7e4b35886126879d7f3129048bb37cd201e6275360763ca128b0445af0477"
    },
    {
      "id": "ship/claimyour.gold/6495d724ffed",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-12T15:49:58Z",
      "kind": "feature",
      "title": "streak Telegram reminders — merge to production",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds BullMQ streak reminder queue, idempotent scheduler (21:00 UTC),\nconcurrency-10 worker, notifyStreakReminder notification, and Super Admin\nmanual trigger route. 1119 tests passing, CI green.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "6495d724ffedd1e3b741797afef48de870c80660"
      },
      "digest": "19f1db51c45802b908f3cc4e3d549708be5210e1b0e59ec1636e3679ad595fed"
    },
    {
      "id": "ship/claimyour.gold/a17ca14dffbf",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-12T15:22:14Z",
      "kind": "fix",
      "title": "mock logger and prisma in SEO foundation test to prevent CI exit(78)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "dashboard/page.tsx → streakService.ts → logger triggers process.exit(78)\nin CI where env vars are absent. Added jest.mock hoists for logger, prisma,\nand streakService so the page's metadata export can be read without running\nservice initialisation.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "a17ca14dffbfef129196e52f9507838349f97456"
      },
      "digest": "842e8d65dcf94951fa227051c31b0049ba5fe8923e5ea19c4a060a79cb98f1bf"
    },
    {
      "id": "ship/claimyour.gold/99f17823407d",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-12T15:13:49Z",
      "kind": "fix",
      "title": "add logger mock to referral integration test to prevent CI exit(78)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Without this mock, importing referral.ts triggered production-env.ts\nto validate env vars and call process.exit(78) when they were absent\nin CI, killing the Jest worker and failing every CI run since Phase 8.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "99f17823407d71f3385aea268dcd5c959c5d4051"
      },
      "digest": "23238ee3e8f0f357d34128d463de4d43f72256e52d3e8e4aa7faf7a5b5f38d1e"
    },
    {
      "id": "ship/claimyour.gold/3a80cb5ff7fd",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T19:19:19Z",
      "kind": "docs",
      "title": "split CLAUDE.md into focused reference docs",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "CLAUDE.md trimmed to 48 lines (commands, where things live, rules, do-nots).\nDetailed content moved to:\n- docs/architecture.md  — directory layout, data flows, auth model, infra\n- docs/runbook.md       — env vars, pre-launch checklist, deploy, rate limits, scale\n- docs/domain-glossary.md — entity definitions, reward concepts, language rules\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "3a80cb5ff7fdb65910bed281cc607231dc7e4e0f"
      },
      "digest": "b4224a432a59de1306fc1985f2495b8a2de3dbd08830ba02f4378fe8ae55c4b7"
    },
    {
      "id": "ship/claimyour.gold/90b4926468b3",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T19:13:00Z",
      "kind": "infra",
      "title": "fix all TypeScript errors, enforce tsc in CI",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Root causes:\n- tsconfig included both .next/types/**/*.ts (stale placeholder) and\n  .next/dev/types/**/*.ts (current, dev-server-generated). The stale\n  .next/types/link.d.ts had a circular StaticRoutes definition that\n  clobbered the valid route union when the namespaces merged, making\n  Next.js typed-routes reject /portal/refer, /portal/profile,\n  /portal/badges, /partner/dashboard, /goldfest, and more (11 errors).\n  Fix: remove .next/types/**/*.ts from tsconfig include; the dev-types\n  are already pulled in by next-env.d.ts and the tsconfig dev glob.\n\n- .next/dev/types/validator.ts, routes.d.ts, and link.d.ts had stale\n  entries for /campaigns/matrix (page moved to src/app/matrix/page.tsx).\n  Fix: update all three generated files to reference /matrix.\n\nCI: add .github/workflows/ci.yml — runs prisma generate, tsc --noEmit,\nand jest on every push and PR (skips production branch which has its\nown deploy workflow).\n\nnpx tsc --noEmit → zero errors\nnpx jest --no-coverage → 854 tests passing\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "90b4926468b37481001f976f6ed7ec214edc4436"
      },
      "digest": "8402f38fd8114fb368f8796f9ab8bf579ef05925476b666cc2bc4e41bbb742aa"
    },
    {
      "id": "ship/claimyour.gold/7e4f3765f5a8",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T18:57:48Z",
      "kind": "other",
      "title": "Phase 4: logger migration + 4 new service extractions",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Part A — Migrate console.* to structured logger in Phase 1/2 services and\nauth routes: customerService, identityService, emailAuthService,\nconfirm-email, verify-email, telegram/auth, matrix/callback.\n\nPart B — Create questService, leaderboardService, redeemSnapshotService,\nloginTokenService; each owns all Prisma calls for its domain.\n\nPart C — Refactor customer/quests, customer/leaderboard,\ncustomer/redeem-snapshot, portal/login-token routes to zero Prisma imports.\n\nPart D — Service tests for all 4 new services (37 new tests); rewrite\nlogin-token.test.ts to service-layer mock; add logger mock to 6 existing\ntest files that import the updated services.\n\n854 tests passing, tsc clean, no console.* in touched services.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "7e4f3765f5a881ce4a4f20b2a3bea5195f03ff65"
      },
      "digest": "4e03150829d1da91440c3dbf33b6738fa8fccc1cd2ff8f3f560519964d70c8f7"
    },
    {
      "id": "ship/claimyour.gold/168ae99f0d3e",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T18:22:26Z",
      "kind": "other",
      "title": "Service layer extraction Phase 3: customer, referral, and portal routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Creates 7 new services (claimService, portfolioService, transactionService,\npointsSyncService, referralStatsService, portalMeService, portalOnboardingService),\nrefactors 9 routes to zero Prisma imports, rewrites 3 referrals route tests to\nservice-layer mocks, adds 8 new test files (7 service + 1 route). Migrates all\nconsole.error calls to the structured Pino logger. 820 tests passing.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "168ae99f0d3eddaf3fe6d2a58cb861e7d01a7baa"
      },
      "digest": "e6ed959935cfdefa095cc235f5b700c3d46366d27ed5a9fd62423f5a9e8ce068"
    },
    {
      "id": "ship/claimyour.gold/97e238c6d29b",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T17:56:47Z",
      "kind": "feature",
      "title": "service layer Phase 2 — confirmEmailService, telegramAuthService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Routes confirm-email, portal/auth, and auth/telegram now delegate all\nbusiness logic to typed service functions. Zero Prisma imports in the\nrefactored routes (portal/auth bypass block excepted, marked).\n\n- src/services/confirmEmailService.ts — token confirmation, pending award\n  crediting, welcome series data fetch\n- src/services/telegramAuthService.ts — returning-user login sync, active\n  client lookup\n- src/services/customerService.ts — adds findByTelegramId\n- All three routes refactored; services/tests/docs updated\n- 735 tests passing (up from 701)\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "97e238c6d29bd760ddbcdec082586db64f1d9f89"
      },
      "digest": "306dbea96fe1d55d6d2016cc4fbb7b1235a9bfb99bfb5838a82326e3353e496d"
    },
    {
      "id": "ship/claimyour.gold/dd9decf8635f",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T17:35:52Z",
      "kind": "feature",
      "title": "extract service layer — customerService, identityService, emailAuthService",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Routes now delegate all business logic to typed service functions. AppError\npropagates domain failures as structured errors (code + httpStatus) so routes\nmap them to the correct HTTP responses without knowing the underlying cause.\n\n- src/lib/AppError.ts — typed error class used across all services\n- src/lib/redact.ts — shared PII-safe email redaction helper\n- src/services/customerService.ts — customer lifecycle (find/create, email, wallet, client linking)\n- src/services/identityService.ts — provider identity lifecycle (Matrix OAuth)\n- src/services/emailAuthService.ts — verification token issuance + email dispatch\n- Routes refactored: verify-email/route.ts, matrix/callback/route.ts\n- tests/services/ — full unit coverage for all three services (service-level Prisma mocks)\n- tests/api/ — route tests now mock at service layer, assert HTTP behaviour only\n- docs/service-layer.md — two-page reference: ownership map, AppError contract, extension guide\n\n701 tests passing.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "dd9decf8635fbc45fbf3358ec483f56a28328c29"
      },
      "digest": "4a2b7e6e8768e158ae821ab74c6323771f25c6fe7e6966dabd1d49c55ebd069e"
    },
    {
      "id": "ship/claimyour.gold/3651907592ab",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T17:15:34Z",
      "kind": "feature",
      "title": "remove MatrixSignIn card, use Matrix SSO as sole sign-in",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Removes the separate MatrixSignIn card section and its server-side\n  session/identity fetch (no longer needed)\n- Changes loginUrl to /api/v1/auth/matrix?mode=login — all PrimaryButtons\n  on the page now drive Matrix OAuth\n- Renames every CTA from \"Join the Campaign\" / \"Sign In with Telegram\"\n  to \"Continue to your Matrix rewards\"\n- Updates supporting copy to reference Matrix sign-in instead of Telegram\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "3651907592ab0a7eedbc8da0f527121188b61a73"
      },
      "digest": "8b639d81a5af3dacc9aa12cb474dd0f39f082ca9b82c3b7721dda1a9b5fb2019"
    },
    {
      "id": "ship/claimyour.gold/e4d7eed14969",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T17:03:57Z",
      "kind": "feature",
      "title": "elite verify-email UX, matrix auto-creation, 670 tests passing",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Rewrites verify-email page with fortune-10 quality UX:\n  60s resend cooldown, ERROR_COPY map, friendlyError helper, spam tip,\n  \"Wrong address?\" correction flow, role=alert banners, a11y attributes\n- Upgrades sendVerificationEmail: gold gradient CTA button, MSO VML Outlook\n  fallback, x-apple-disable-message-reformatting, fallback plain-text link,\n  improved subjects/headings/preheader, Claim Your Gold logo\n- Fixes matrix callback: adds email field to providerIdentity.create (link\n  mode) and userInfo.email to displayName chain (login mode)\n- Fixes matrix-auth tests: adds oauthInitRateLimit mock, customer/wallet\n  mocks for auto-creation path, updates stale redirect expectations, adds\n  3 new auto-creation tests (race condition fallback, upsert call, wallet)\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "e4d7eed14969ace3b0ae20e6275f6f6c8f96112f"
      },
      "digest": "f5226b50217f8a5944dd9c3190d483d6c422aba079a21cd89565aaa2aaaa5c85"
    },
    {
      "id": "ship/claimyour.gold/648e2cd68111",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T16:37:06Z",
      "kind": "fix",
      "title": "prevent Internal server error when Matrix user verifies email",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The placeholder email replacement (matrix_xxx@pending.flashy.local →\nreal email) could throw a P2002 unique constraint when the desired email\nwas already owned by another account, crashing with a generic 500.\n\n- Add explicit conflict check before update; return 409 EMAIL_CONFLICT\n  so the user gets a clear message instead of a 500\n- Improve catch-block logging with structured code + message fields\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "648e2cd68111ffac07e6df3b6615084b50d73cb1"
      },
      "digest": "44c54109393ea6fc855a7d480e1cbd1d167789e7fa6734aa88ab741e5bbc7ddf"
    },
    {
      "id": "ship/claimyour.gold/28f744f5372d",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T14:38:57Z",
      "kind": "feature",
      "title": "debug: add step-by-step logging to Matrix callback for diagnosis",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Logs each stage (token-exchange, userinfo, create-customer, upsert-identity)\nso Cloud Run logs reveal exactly which step is failing when verify-failed is\nreturned. Also logs error code and first 4 stack frames on failure.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "28f744f5372dcbe8c01e276027d0799a340896a8"
      },
      "digest": "f45588a4f2827dc9a3e038e4ec1682c632afeea7f54e24e3a1d9c27f89090d66"
    },
    {
      "id": "ship/claimyour.gold/76866b2c8d0f",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T14:27:22Z",
      "kind": "fix",
      "title": "raise Matrix OAuth rate limit to 20/min, redirect on limit instead of JSON",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The Matrix sign-in initiation uses the generic auth limiter (5/min) which is\ntoo tight for an OAuth button that users click interactively. Switch to a\ndedicated oauthInitRateLimit (20/min, fail-open on Redis error) that allows\nnormal use while still preventing abuse.\n\nWhen the limit is hit, redirect to /matrix?matrix_error=rate-limited instead\nof returning a raw JSON 429 — the browser navigates to this URL directly so\nJSON is confusing UX. Add the matching error message to MatrixSignIn.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "76866b2c8d0f7c8c021df79507fd4cab49210687"
      },
      "digest": "923f6af4cfe14f19a85e72dae9f9dc9190bbd1281e2d37e1e0706ed06209c6d8"
    },
    {
      "id": "ship/claimyour.gold/1e3796acfbcb",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-10T13:37:53Z",
      "kind": "fix",
      "title": "add try/catch to Matrix initiation route, harden callback URL resolution",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The initiation route (/api/v1/auth/matrix) had no error handling around\ncreateMatrixProvider() — a missing or malformed Matrix env var would throw\nuncaught and return HTTP 500 to the user.\n\nThe callback route assumed getPublicAppUrl() could never fail; wrap it in a\ntry/catch so a missing NEXT_PUBLIC_SITE_URL/NEXTAUTH_URL degrades to a redirect\nto the canonical domain rather than a 500.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "1e3796acfbcbaaa27cc6b342e07e1c1678e84d8e"
      },
      "digest": "a484ae7179e33b9daa501d2f3b91484412e36428fe9a86e31a49c5331d2b21ee"
    },
    {
      "id": "ship/claimyour.gold/0d8ffb7e436e",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T21:29:28Z",
      "kind": "feature",
      "title": "add Powered by Flashy Gold attribution to hero",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds a subtle stacked \"POWERED BY / Flashy logo\" treatment below the\nTelegram login line, matching the login card reference design. Uses\n/flashy.svg at 40% opacity so it reads as secondary attribution without\ncompeting with the primary CTA.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "0d8ffb7e436e25c0b65ab6fc26a05b6fa4e9ee52"
      },
      "digest": "05af06bb0f3561a630f693080e72721dbc3c447de65aafb6795b8af3e17afc95"
    },
    {
      "id": "ship/claimyour.gold/279c189009db",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T21:26:48Z",
      "kind": "fix",
      "title": "remove duplicate GlobalFooter from homepage",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "layout.tsx already renders GlobalFooter for all pages. page.tsx was\nrendering a second one, causing two footers to appear on the homepage.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "279c189009db7774a4fa75437b0e2d5b7a8f349a"
      },
      "digest": "c1d085b18ab2bdf779c5314f0fd2fd8f95ed0ce822515e232fd30c4325a598ff"
    },
    {
      "id": "ship/claimyour.gold/e166a0f14c30",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T21:26:10Z",
      "kind": "fix",
      "title": "redirect verified users away from verify-email page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Onboarding API already returns ALREADY_VERIFIED (400) when the session-\ncookie fallback path detects emailVerified=true. The page was ignoring\nthe error code and redirecting to /portal/login instead of /portal/dashboard.\n\nFix: parse the error body before branching — ALREADY_VERIFIED goes to\ndashboard, all other errors go to login. A `redirecting` state gates\n`return null` to prevent any flash of the email form during navigation.\n\nTests: tests/components/portal-verify-email.test.ts (8 assertions)\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "e166a0f14c30c948fde3ec42d0fe38dfa12e19ae"
      },
      "digest": "6a50b6d40e8ec5e6a407654f2415d76314990fcd6f68b7f645473305118dd2f1"
    },
    {
      "id": "ship/claimyour.gold/b3dd7688bf73",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T21:19:43Z",
      "kind": "perf",
      "title": "enable Next.js image optimization",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Remove unoptimized: true — images now served as WebP with responsive\n  srcsets via Next.js built-in optimizer\n- Add remotePatterns for Telegram CDN (**.telegram.org, t.me) to cover\n  profile photo URLs used in wallet page\n- Add sharp as a production dependency (required for image processing\n  on Cloud Run / non-Vercel Node.js runtimes)\n- Regenerate Prisma client to fix pre-existing stale type for\n  ProviderIdentity.email field (was blocking npm run build)\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "b3dd7688bf7358cebaac939daf8bf4873d8d19dd"
      },
      "digest": "8f0391c1d9cbb4fc20c539fb5c440cfa3d7c56f5f7c1865e6a705b8d5dca794e"
    },
    {
      "id": "ship/claimyour.gold/937de630454f",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T21:10:05Z",
      "kind": "infra",
      "title": "sync production fixes to feature branch",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "937de630454f4f5e2fb5ece38f045c9cf4a453ba"
      },
      "digest": "96764277939023bcd7c9f5f952f96413af45ed23b7a3f06d979aec62dccf6f21"
    },
    {
      "id": "ship/claimyour.gold/f9e3f95e5721",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T20:02:06Z",
      "kind": "fix",
      "title": "exclude sitemap.xml and robots.txt from middleware matcher",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "These files were being processed by the middleware, which calls getToken()\nand injects CSP headers. Any middleware-level error on Googlebot requests\nwould cause a 500 and Google Search Console's \"Couldn't fetch\" error.\n\nSEO-critical files should always be served bare with no auth/CSP logic.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "f9e3f95e5721c11593e5a402a9555cfcf8f4e8b4"
      },
      "digest": "b270f1a6ea0e4b8c38c903d8106d105bb2099a79d53b7a56c6b3d6cf623f2a95"
    },
    {
      "id": "ship/claimyour.gold/65bab41f4cfc",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T17:31:27Z",
      "kind": "feature",
      "title": "add portal error boundaries for dashboard, login, and portal group",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Prevents white-screen crashes from showing to users. All three boundaries\nshow branded recovery UI with \"rewards are safe\" reassurance copy and a\nreset() + support email fallback. Tests verify file existence, client\ndirective, reset wiring, and key copy phrases.\n\nAlso fixes 4 TS errors in global-footer.tsx introduced by nav link additions.\n578 tests passing.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "65bab41f4cfc952c0565e92f8b3afc5cc01019ce"
      },
      "digest": "e92df9904e13c66c669a5f79201f2bc011b4f89ce2127c67785a4037a470dfbd"
    },
    {
      "id": "ship/claimyour.gold/1d9f778334b6",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T16:53:28Z",
      "kind": "infra",
      "title": "copy: rename \"Gold Points\" → \"Flashy Gold\" across all user-facing text",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Replaces all 83 instances of \"Gold Points\" with \"Flashy Gold\" in user-facing\ncopy (pages, components, FAQ catalog, layout schema, marketing email).\n\nPreserves \"Gold Points Balance\" in client CSV import page — that is a\ndata-format column name, not user-facing branding.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "1d9f778334b6572acd598ab4a5f8a3b00455e207"
      },
      "digest": "c4cc0ff5eb26c164097a21fde443927ae2a45e51f2e65e2b112b656d7177bc8b"
    },
    {
      "id": "ship/claimyour.gold/0e86e97d73dc",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T16:52:28Z",
      "kind": "infra",
      "title": "nav: wire /campaigns, /how-it-works, /about into header and footer",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Header public nav: add \"How It Works\" link\n- Header Campaigns dropdown: add \"View all campaigns →\" at bottom\n- Header mobile drawer: add \"View all campaigns →\" below campaign list\n- GlobalFooter: replace \"GoldFest\" with Campaigns/How It Works/Support/About links\n- sections/footer (homepage): add nav links, fix \"Real gold.\" → compliant language\n- Update chrome-nav test to match new footer structure\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "0e86e97d73dc7cb7216397f55777cf873c2bc604"
      },
      "digest": "324dbadbdc6a439400b4a6af22e754b37912bda33780f7a3430cbeb312ba9ebe"
    },
    {
      "id": "ship/claimyour.gold/8a9823fc4723",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T16:32:09Z",
      "kind": "docs",
      "title": "add Phase 2 SEO section to CLAUDE.md",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Documents all schema additions, new cornerstone pages, sitemap updates,\nlanguage rules, and schema injection patterns.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "8a9823fc472348f1723da54cd2a59a23d7213d1a"
      },
      "digest": "6d53c72a107ba89d73af41414bc41f0e93a5c59b0287fa6307c49967221c5921"
    },
    {
      "id": "ship/claimyour.gold/707784be30df",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T16:31:22Z",
      "kind": "other",
      "title": "SEO high-priority: Event/Dataset/FAQ/Breadcrumb schema, campaigns hub, how-it-works, about page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- goldfest/page.tsx: Add Event, Dataset, FAQPage, BreadcrumbList JSON-LD schema\n- matrix/page.tsx: Add Event, FAQPage, BreadcrumbList JSON-LD schema\n- support/page.tsx: Add FAQPage (all 21 FAQs) + BreadcrumbList JSON-LD schema\n- campaigns/page.tsx: New hub page — CollectionPage + BreadcrumbList schema, maps CAMPAIGNS registry\n- how-it-works/page.tsx: New cornerstone page — HowTo (5 steps) + FAQPage + BreadcrumbList schema\n- about/page.tsx: New entity page — AboutPage + FAQPage + BreadcrumbList schema, GoldFest stats\n- sitemap.ts: Add /campaigns (0.9), /how-it-works (0.8), /about (0.7) — 8 total entries\n- tests/seo/schema.test.ts: 29 source-file schema presence tests (all pass)\n\nAll copy uses \"Flashy Gold\", \"gold rewards\", \"Gold Points\", \"redeemable for real assets and\nexperiences\" — no \"real gold\" language. 563 tests pass.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "707784be30df378a1f49b47df47a3d7c81780c0c"
      },
      "digest": "398f0d8662ebb5ef53088f43d853e64a7e17d2ea77984de703e0ca1a24acd7a6"
    },
    {
      "id": "ship/claimyour.gold/071f023cd678",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T16:08:31Z",
      "kind": "docs",
      "title": "add SEO & GEO Foundation section to CLAUDE.md (section 18)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Documents: what was implemented, how to add campaigns to sitemap,\nhow to toggle indexability, where Organization JSON-LD lives,\nand production verification URLs for sitemap.xml + robots.txt.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "071f023cd678bffb58a8ac72cf67ed3f6e5c1538"
      },
      "digest": "2e953bf1c0a848a1181946c538565114f1037e9e80ffab334ed3cfe4757535a7"
    },
    {
      "id": "ship/claimyour.gold/e0912e49e0b7",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T16:07:52Z",
      "kind": "other",
      "title": "SEO foundation: robots.txt, sitemap, Organization schema, canonical URLs, noindex fixes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Implements the complete SEO/GEO foundation layer:\n\n- public/robots.txt: explicit crawl rules — allows public pages, blocks\n  all authenticated portal routes, admin/client/partner routes, API\n  routes, and the status utility page; references sitemap URL\n\n- src/app/sitemap.ts: dynamic Next.js sitemap driven by CAMPAIGNS\n  registry; homepage priority 1.0, campaigns 0.95 (LIVE) / 0.85,\n  support 0.7, portal login 0.5; filters indexable:false campaigns\n\n- src/lib/campaigns.ts: adds indexable?: boolean to CampaignConfig;\n  goldfest and matrix set indexable:true explicitly\n\n- src/app/layout.tsx: adds Organization + WebSite JSON-LD structured\n  data via dangerouslySetInnerHTML <script type=\"application/ld+json\">\n  — establishes Claim Your Gold as a named entity for AI knowledge\n  graph systems (ChatGPT, Perplexity, Claude Search, Gemini)\n\n- src/app/page.tsx: adds metadata export with upgraded title/description\n  targeting gold rewards keywords, canonical URL, Twitter card\n\n- src/app/goldfest/page.tsx: adds canonical + Twitter card override\n\n- src/app/support/page.tsx: upgrades title/description for keyword\n  relevance, adds canonical + Twitter card\n\n- src/app/(portal)/portal/login/page.tsx: adds metadata export with\n  unique title/description (removes duplicate of homepage metadata)\n\n- src/app/status/layout.tsx: flips robots to noindex (utility page)\n\n- Portal authenticated pages (dashboard, quests, leaderboard, refer,\n  redeem): add robots: { index: false, follow: false } to prevent\n  crawlers from burning budget on auth-gated soft-404s\n\n- src/app/(portal)/portal/badges/layout.tsx: new layout.tsx to carry\n  noindex metadata for 'use client' page component\n\n- src/app/(portal)/portal/profile/layout.tsx: same pattern as badges\n\n- tests/seo/foundation.test.ts: 33 tests covering all of the above\n\nTypeScript: 13 errors before, 13 after (all pre-existing, zero new)\nTests: 513 passing, 0 failing\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "e0912e49e0b743e731f5428926972b7b8a911add"
      },
      "digest": "fee6fe58c444113261668e9800ef577bf2f958bb6781d3c30ffaf4b4334660de"
    },
    {
      "id": "ship/claimyour.gold/080670e42005",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-09T14:59:34Z",
      "kind": "feature",
      "title": "Add hidden Predictfully landing page at /predictfully",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Creates a hidden-but-live campaign landing page for the Predictfully\n× Flashy Gold partnership. The page is accessible by direct URL but\nintentionally excluded from all navigation, sitemaps, and search\nindexing (noindex robots meta, not in campaigns.ts registry).\n\n- src/app/predictfully/page.tsx — server component with auth-aware\n  CTA routing, how-it-works steps, eligibility callout, FAQ, and\n  compliant reward language throughout (\"may earn\", \"subject to\n  eligibility\", rewards not guaranteed)\n- src/app/predictfully/PredictfullyAnalytics.tsx — client component\n  firing PostHog events: predictfully_page_view,\n  predictfully_primary_cta_click, predictfully_secondary_cta_click,\n  predictfully_auth_start, predictfully_faq_expand\n- tests/pages/predictfully.test.ts — 14 tests covering noindex\n  metadata, absence from CAMPAIGNS registry, CTA routing, all five\n  PostHog event names, compliance language, and footer isolation\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "080670e4200520a522c40357ac42cf3fcf283c60"
      },
      "digest": "e6a71a8178ad916650a2480e500cba0a00ba00fc86f08ea1d12b414b7de0a0e3"
    },
    {
      "id": "ship/claimyour.gold/c0fce1f769f9",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-08T16:33:48Z",
      "kind": "infra",
      "title": "Align Matrix SSO with provider's OAuth spec (JSON body, email-only userinfo, access_denied)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Per Matrix OAuth2.0 integration doc:\n- Token exchange: change Content-Type from form-encoded to application/json;\n  Matrix endpoint requires JSON body, not URLSearchParams\n- Remove scope param from auth URL (not in Matrix spec)\n- Userinfo: Matrix returns only { sub, email } — remove expected\n  preferred_username/name fields; add email field to ProviderUserInfo\n  interface and ProviderIdentity schema\n- Callback: handle ?error=access_denied (user clicked Deny on consent screen)\n  redirecting to matrix_error=cancelled instead of verify-failed\n- Callback: store Matrix email in ProviderIdentity.email; use email as\n  session display name with telegramUsername fallback\n- MatrixSignIn component: show linked email instead of @username; add\n  cancelled error copy\n- 33 tests (was 26) — new cases: access_denied, email stored on link,\n  displayName uses email, telegramUsername fallback, state uniqueness,\n  del not called on cache miss\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "c0fce1f769f9a178a6721ada03a583fa146cda39"
      },
      "digest": "61f75dc7fc8cea0b7cfb26327bfe39aaf925967606d3b62b27cbb2b64c51fb82"
    },
    {
      "id": "ship/claimyour.gold/0b3379178cee",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-03T19:08:00Z",
      "kind": "feature",
      "title": "Add Matrix SSO OAuth flow — link identity, sign in, and access campaign rewards",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- ProviderIdentity schema model: compound unique on (provider, providerUserId),\n  indexed by customerId, relation on Customer\n- matrixProvider.ts: OAuthProvider abstraction (buildAuthUrl, exchangeCode,\n  fetchUserInfo); sanitizes all profile fields; never logs tokens\n- GET /api/v1/auth/matrix: rate-limited initiation route; generates\n  cryptographically random CSRF state stored in Redis (5 min TTL);\n  supports mode=login (no auth) and mode=link (requires portal session);\n  allowlisted returnTo prevents open redirect\n- GET /api/v1/auth/matrix/callback: validates and atomically deletes Redis\n  state (replay prevention); login mode looks up ProviderIdentity and issues\n  portal session cookie; link mode upserts ProviderIdentity, rejects\n  cross-account conflicts with already-linked error\n- MatrixSignIn client component: three states (loggedOut, loggedInNotLinked,\n  loggedInLinked); all five UX copy strings; success/error banners from URL\n  params; no client-side secrets\n- /matrix page: reads session + DB to determine link state, passes to\n  MatrixSignIn via server-rendered props; searchParams wired for\n  ?matrix=connected and ?matrix_error=* redirects\n- 26 new tests covering rate limiting, mode validation, auth gates, CSRF\n  state storage, link allowlisting, token exchange errors, already-linked\n  conflict, replay prevention, login session cookie issuance, redirect URLs\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "0b3379178cee5e18ffa537f1f99e6c5b1d1406d2"
      },
      "digest": "b19d06ca2159dd1e6aa04f2bba6855d51a0d54eb374b5110c4d43afa93bc629c"
    },
    {
      "id": "ship/claimyour.gold/b308fe4af661",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-02T19:03:58Z",
      "kind": "infra",
      "title": "move Matrix page from /campaigns/matrix to /matrix",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- src/app/campaigns/matrix/ → src/app/matrix/\n- Update canonical URL to https://claimyour.gold/matrix\n- Update OG url to /matrix\n- Update campaigns.ts href: '/matrix'\n- Update mobile nav shortcut href to /matrix\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "b308fe4af66165a0d6b3d80bc7033d0986bda32c"
      },
      "digest": "ebef197385cd6bf9acbd0a8c659e65c4f2485f041c8d9d1cb19731c29dad2edc"
    },
    {
      "id": "ship/claimyour.gold/be67ba450763",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-02T16:56:38Z",
      "kind": "feature",
      "title": "add Campaigns dropdown nav + Matrix Season 1 campaign page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Architecture:\n- src/lib/campaigns.ts — typed CampaignConfig registry; single source of truth\n  for navbar, future campaign index, and any listing page. Adding new campaigns\n  requires one entry here only.\n\nNavbar (global-header.tsx):\n- Removed standalone GoldFest link from publicLinks/portalLinks\n- Added CampaignsDropdown (Radix DropdownMenu) with status dot, partner label,\n  and season status badge for each campaign — fully accessible + keyboard nav\n- Added MobileCampaignLinks component that renders flat links in the mobile drawer\n- Mobile unauthenticated header shows Matrix shortcut link\n- Typed route cast for /campaigns/matrix\n\nMatrix campaign page (src/app/campaigns/matrix/page.tsx):\n- Full SEO: title, description, keywords, canonical, OG, Twitter card\n- Hero: H1 \"Flashy Gold x Matrix Season 1\", tagline, compliance-safe subheadline,\n  gold CTA cluster, ambient glow (gold + violet)\n- Campaign stats grid: $100K, June 4 kickoff, 3 months, Flashy Gold, Matrix, portal\n- How It Works: 4-step timeline with spine connector\n- Campaign Mechanics: 4 cards (Gold Run, Gold Survivor, Project Tournaments, Final)\n- Rewards section: gold+violet gradient panel with 4 reward-type cards\n- ClaimYour.Gold portal section with benefits checklist\n- Planning estimates section with compliance disclaimer box\n- FAQ: 10 questions, all compliance-safe copy\n- Bottom CTA + support footer with legal disclaimer\n- Server Component with session cookie read for header auth state\n- Reusable StatCard, MechanicCard, StepRow, PrimaryButton, SecondaryButton\n\nTests: updated chrome-nav.test.ts to reflect new Campaigns dropdown structure\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "be67ba450763aad1a35398f217d298798f0cf450"
      },
      "digest": "c3b4c823d3c6b53341b21a49ffbb5f1e7ee7766592c8b1dc5001ebea1edb5b27"
    },
    {
      "id": "ship/claimyour.gold/2afcdaefd7ea",
      "repo": "repo/claimyour.gold",
      "at": "2026-06-02T16:14:01Z",
      "kind": "infra",
      "title": "add comprehensive test suite covering auth, referrals, and core libs",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds 12 new test files (430+ new tests) with Fortune-10-grade coverage:\n\nAPI routes:\n- confirm-email: token validation, scanner pre-click handling, redirect URLs\n- login-token: POST token creation, GET polling, new/returning user paths, ref threading\n- referrals-leaderboard: Redis cache hit/miss, DB aggregation, username masking\n- referrals-me: auth gate, stats aggregation, milestone mapping, activity ledger\n- verify-email: onboarding+session auth, rate limiting, new/existing customers, referral association\n\nLib units:\n- apiError: status codes, response shape, optional code field\n- clientIp: CF/x-real-ip/x-forwarded-for priority, whitespace, IPv6, fallback\n- format: formatPoints, pointsToFG, formatFG, fgProgress, truncate\n- hunterRank: getRankTitle, getRankTier, RANK_TIERS integrity\n- portalOnboarding: 30-min TTL, ref round-trip, tampered token rejection\n- portalSession: 12-hour TTL, forged payload, expired token, cookie builders\n- wallet: createWallet, creditWallet, getBalance with exact query shapes\n\nAlso enhances tests/helpers/mockRequest.ts to support body, cookies, searchParams.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "2afcdaefd7ead88f451ebbee1252b1e34c4ada51"
      },
      "digest": "0f79f61b68b100b4c7a8fde035540ffc6e1b35acd3db9d53ebcb5c9b4706997a"
    },
    {
      "id": "ship/claimyour.gold/52c0e45904ae",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-30T16:15:25Z",
      "kind": "other",
      "title": "Thread referral code through bot deep-link login flow",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The login-token flow always set ref=null in the onboarding cookie,\nsilently dropping the referral attribution for any user who signed up\nvia the Telegram bot deep-link (the primary login path).\n\nFix: login page now passes ref in the POST body, login-token stores it\nin the pending Redis payload, bot webhook preserves it when writing the\nready payload, and login-token GET forwards it into the onboarding\ntoken so verify-email receives it server-side (localStorage fallback\nis kept as a belt-and-suspenders backup).\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "52c0e45904ae615820c1789520e314d9b7ef4428"
      },
      "digest": "4ceda8f328cfef667efb5f448f1737895619e19ab92f9a0da2e4ea27e1fce006"
    },
    {
      "id": "ship/claimyour.gold/fb87aeb2e660",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-30T15:48:44Z",
      "kind": "infra",
      "title": "Remove redundant My Profile nav link from portal navbar",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "My Profile is already accessible via the profile dropdown, so the standalone\nnav item is unnecessary and adds visual clutter.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "fb87aeb2e660cd20bccd6201963903151f807e4a"
      },
      "digest": "8841ceea3117af9d3619ffe0508863400b573efae4d0690bf33a66f13a9666f0"
    },
    {
      "id": "ship/claimyour.gold/e804034ead8e",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-29T19:40:08Z",
      "kind": "fix",
      "title": "add metadataBase and root OG image so social sharing previews work",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- layout.tsx: metadataBase set from NEXT_PUBLIC_SITE_URL (falls back to\n  https://claimyour.gold) — without this Next.js cannot output absolute\n  og:image URLs, so all social card previews were blank\n- layout.tsx: add explicit openGraph.images and twitter.images pointing at\n  /opengraph-image so the tag is present even as a fallback\n- opengraph-image.tsx: new edge-rendered 1200x630 OG image for the home\n  page — dark gold aesthetic matching the site, shows headline, tagline,\n  and three feature pills (Play to Earn, Referral Rewards, Instant Payouts)\n\nPreviously, sharing claimyour.gold on Telegram, iMessage, X, or any\nplatform that reads og:image produced a blank/missing preview card.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "e804034ead8e8fcdefb1d4d2504bee07a90f32f1"
      },
      "digest": "004ac49200dd98f69b78c3c5741fe7a2012e61bae86839124bcdd9e8ebb21cf4"
    },
    {
      "id": "ship/claimyour.gold/7ea04a27fb0a",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-29T18:24:11Z",
      "kind": "feature",
      "title": "production-safe referral backfill",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Adds a one-time backfill script to promote stuck PENDING referrals to\nREWARDED status.  These referrals were created correctly but never\nactivated because email verification links were temporarily broken\n(resolved to 0.0.0.0), so activateReferral() was never called.\n\nscripts/backfill-pending-referrals.ts\n- Queries PENDING referrals where referred customer has emailVerified=true\n- Calls existing activateReferral() — no logic reimplemented\n- Default: --dry-run (no writes unless --no-dry-run is passed explicitly)\n- --limit N (default 50) caps each run to a safe batch size\n- --delay-ms N (default 500) throttles DB writes to avoid spikes\n- Structured summary: found / processed / failed / error details\n- Exits with code 1 if any record fails (CI/monitoring detectable)\n- Idempotent: safe to run repeatedly (activateReferral skips REWARDED)\n- Disconnects Prisma in finally block — no leaked connections\n\ntests/scripts/backfill-pending-referrals.test.ts\n- 23 tests covering: dry-run, live mode, partial failures, full failure,\n  limit passthrough, delay behaviour (0 ms / N ms / single record),\n  result shape invariants, null-safety runtime guards\n- All external dependencies mocked (Prisma + activateReferral)\n\npackage.json\n- Adds \"backfill:referrals\" npm script\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "7ea04a27fb0a652ca21f04cf137ccc997e1cac3d"
      },
      "digest": "01c092358a803e3acd755af8266398f1344940449043dbdffd74fac168404de4"
    },
    {
      "id": "ship/claimyour.gold/77ca414638c5",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-29T16:44:37Z",
      "kind": "fix",
      "title": "9-item referral system hardening",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "R1: fix broken referral links (was resolving to 0.0.0.0)\n    - referrals/me now uses getPublicAppUrl() instead of config.auth.url\n\nR2: add @@index([referrerId, status]) compound index on Referral model\n    - speeds up checkAndGrantMilestones count query and leaderboard groupBy\n\nR3: fix N+1 leaderboard query\n    - single findMany with {id: {in: referrerIds}} replaces 10 serial findUnique calls\n\nR4: harden email verification tokens\n    - tokens now use crypto.randomBytes(32) instead of cuid()\n    - old unused tokens invalidated (usedAt=now) before issuing a new one\n\nR5: enforce MAX_ASSOCIATE_PER_IP_PER_HOUR (5/hr)\n    - new referralAssociateRateLimit limiter in rateLimit.ts\n    - verify-email route checks it before calling associateReferral\n\nR6: structured logging for attribution failures\n    - referral associate errors now log customerId, code, and message\n\nR7: Redis cache (60s TTL) on leaderboard endpoint\n    - cache:leaderboard key, fail-open on Redis error\n\nR8: Telegram bot handles /start ref_CODE deep links\n    - sends portal link with ?ref=CODE so RefCapture picks it up in localStorage\n\nR9: RefCapture already applied on portal/login via merge resolution\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "77ca414638c5cc6fe390f56924c1dea70a16d8df"
      },
      "digest": "ece9e42b4fa1df37985071317b3199c824638796c41fd4573d00458dc5b7b9f9"
    },
    {
      "id": "ship/claimyour.gold/d68eacf172ee",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-29T16:41:48Z",
      "kind": "infra",
      "title": "merge production into feature branch to bring up to date",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "https://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "d68eacf172ee33641965bb001d77bba85e555839"
      },
      "digest": "6f5209eacbc3fadef6c9fc3695cd83b116bfde95a4e13118c08b6ade14547515"
    },
    {
      "id": "ship/claimyour.gold/01a4e9b08305",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-28T16:34:13Z",
      "kind": "fix",
      "title": "use getPublicAppUrl() so verification links never resolve to 0.0.0.0",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "NEXTAUTH_URL is a Docker server bind address (0.0.0.0:3000) in production,\nnot a public URL. All verification email links were constructing\nhttps://0.0.0.0:3000/... which caused ERR_SSL_PROTOCOL_ERROR on click.\n\nChanges:\n- src/lib/publicUrl.ts: new getPublicAppUrl() utility that reads\n  NEXT_PUBLIC_SITE_URL first, falls back to NEXTAUTH_URL only when it is\n  not a bind address (0.0.0.0 / 127.0.0.1), and hard-fails in production\n  when no valid public URL is configured\n- src/lib/email.ts: sendVerificationEmail uses getPublicAppUrl() instead\n  of config.auth.url\n- src/app/api/v1/auth/confirm-email/route.ts: redirectTo() uses\n  getPublicAppUrl() as the base instead of req.url (which carried the\n  bind address as the host if the user clicked a broken link)\n- tests/lib/publicUrl.test.ts: 11 regression tests covering 0.0.0.0\n  rejection, https enforcement in production, fallback chain\n\nSet NEXT_PUBLIC_SITE_URL=https://claimyour.gold in GCP Secret Manager.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "01a4e9b08305ff80febb1717ccb44a40cf9a0e0c"
      },
      "digest": "e9718ff3bc6f93812cfb34e5cc38a6a7e832525759f208a2b906cb231e836ae7"
    },
    {
      "id": "ship/claimyour.gold/28bc7a77b2bc",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T21:42:44Z",
      "kind": "fix",
      "title": "restore Telegram OAuth on production (claimyour.gold)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Two bugs prevented sign-in:\n\n1. Cross-Origin-Opener-Policy: same-origin was set globally. The Telegram\n   Login Widget opens an oauth.telegram.org popup from inside a telegram.org\n   iframe; COOP same-origin isolates that popup into its own browsing context\n   group, making window.opener null so Telegram can never postMessage the auth\n   data back. Fix: override COOP to unsafe-none only on /portal/login.\n\n2. The fallback OAuth redirect URL included embed=1, which tells\n   oauth.telegram.org to use postMessage-to-opener mode. Since the fallback\n   uses a full-page redirect (no opener exists), the auth result was silently\n   discarded. Fix: remove embed=1 so Telegram uses the return_to redirect.\n\nNote: BotFather must also have claimyour.gold registered as the bot domain\n(/setdomain claimyour.gold) for both the widget and OAuth redirect to work.\n\nhttps://claude.ai/code/session_01EnURDwKmd4b1SQTScfGRDR",
      "refs": {
        "commit": "28bc7a77b2bcbb08d499102fb6912d1996a2d472"
      },
      "digest": "f2ee12cbe1fa788f856fef419afd7b18f76c3e8c650b3e77357b4a1dc6944b5a"
    },
    {
      "id": "ship/claimyour.gold/e9e906013f1e",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T20:52:48+02:00",
      "kind": "other",
      "title": "changed chest image",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "e9e906013f1efd1c58d1b2a005db3355ce809ab6"
      },
      "digest": "20b1b6d158bd85cd2efc7213ee7ee05367845e9eed0174a08f744ef76f6d2a85"
    },
    {
      "id": "ship/claimyour.gold/552a19c37c9e",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T20:37:03+02:00",
      "kind": "infra",
      "title": "update lowercase ui component modules",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "552a19c37c9e20a26949095ed56ecc6b0c44939e"
      },
      "digest": "cbb5663fcda9af1fa4eb1923e04df08d6fbdf9a4ed8374674856bcde3671dc78"
    },
    {
      "id": "ship/claimyour.gold/5d65af4aa285",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T20:20:24+02:00",
      "kind": "other",
      "title": "stabilize UI branch after main merge and auth-safe cleanup",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "5d65af4aa285e58fe7f2da93e57cd2b67008591a"
      },
      "digest": "99df994359bb93e9c3de1588a486aecb8b49531e5b4bdf0f9a70a18142c7672b"
    },
    {
      "id": "ship/claimyour.gold/af4826bdbc57",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T19:50:37Z",
      "kind": "fix",
      "title": "CSV import handles UserID column and scientific notation numbers",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "af4826bdbc575f57e08551d7702f0ab5b095554b"
      },
      "digest": "fd5b737df858f5693e8202cfb0309f166aeb897ab6abae24e017392dc05e256d"
    },
    {
      "id": "ship/claimyour.gold/856789e56c91",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T19:00:30Z",
      "kind": "infra",
      "title": "Remove duplicate uppercase UI component files",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Co-authored-by: Flashy Labs <FlashyLabs@users.noreply.github.com>",
      "refs": {
        "commit": "856789e56c913808c7d4c8541c0163fd1f1eaf3f"
      },
      "digest": "d53203fdb29544dcf766be5c3746f6ea60da4a9458cfad99a0df4a188030a5e5"
    },
    {
      "id": "ship/claimyour.gold/c1c8f57ee345",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T17:56:21+02:00",
      "kind": "feature",
      "title": "merge main into UI, keep main runtime functionality",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "c1c8f57ee345f211ff9c5be2fd700c3373ece551"
      },
      "digest": "d1fbccbc1f43f5608f7c93d436f75b9d648e46e5f48c9c571d43bbfbed5def76"
    },
    {
      "id": "ship/claimyour.gold/c47875f61451",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T11:22:21+02:00",
      "kind": "feature",
      "title": "Merge origin/main into UI using main conflict resolutions",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "c47875f61451d2898367c1f4bb4246b0a3812c00"
      },
      "digest": "966ff687a8761d9c59f0e3be31d9be9403c1e0d6d49ebdbdd92652cdfa1ab22b"
    },
    {
      "id": "ship/claimyour.gold/d91f1b81213d",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T00:38:45+02:00",
      "kind": "fix",
      "title": "Fix UI component filenames to match import casing (badge.tsx, button.tsx, card.tsx)",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "d91f1b81213d8879935ec89da172ff1094ceeac8"
      },
      "digest": "ea67c60363fc3f94184691eae19f54243231269d8411e3b6c0fb31e2558e6397"
    },
    {
      "id": "ship/claimyour.gold/757259ff13a8",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T00:30:49+02:00",
      "kind": "feature",
      "title": "Add UI components index file for proper imports",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "757259ff13a82504deedacd4baa8240bcd269f9d"
      },
      "digest": "4a8891c7883dc8082088632ca89010f40b2f0a168a501d3587c92b26e6381363"
    },
    {
      "id": "ship/claimyour.gold/60b452268591",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-16T00:15:07+02:00",
      "kind": "fix",
      "title": "Fix all TypeScript compilation errors and missing production infrastructure",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "60b452268591e99dc3b05b84d9db5b33faf16bca"
      },
      "digest": "0ce344e7b855096452585040629102337a012dceaddd3cd38735b9ce09a86bd7"
    },
    {
      "id": "ship/claimyour.gold/02c11a8d48fd",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T23:19:16+02:00",
      "kind": "other",
      "title": "Change database environment variable from DATABASE_URL to MONGODB_URI",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "02c11a8d48fd15f53dc70331b55ef833b0e0da95"
      },
      "digest": "3e054481d200bf55cb78afc61216c3b9d74cf3a7931ccd297976c8ef3420a37c"
    },
    {
      "id": "ship/claimyour.gold/698c58280c5e",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T23:04:57+02:00",
      "kind": "other",
      "title": "Clean up project structure for Vercel deployment",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Remove references folder to avoid multi-service detection\n- Add proper vercel.json configuration\n- Clean up duplicate .env files\n- Ensure single Next.js application structure\n- Ready for Vercel deployment",
      "refs": {
        "commit": "698c58280c5ebf482e174c28f131c55232c7325e"
      },
      "digest": "52f2abbfe3ae899312b4d3382bbb24865b4c6deb4c7aa86d2e2b820a0091d8a2"
    },
    {
      "id": "ship/claimyour.gold/9fdb45d010e8",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T23:02:45+02:00",
      "kind": "feature",
      "title": "Add comprehensive Vercel deployment guide and setup scripts",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Add complete step-by-step deployment guide\n- Create production environment variables template\n- Add setup script for secret generation\n- Fix leaderboard component imports and props\n- Include MongoDB Atlas, Vercel, and service setup instructions\n- Add troubleshooting and post-deployment steps\n- All components now working and production-ready",
      "refs": {
        "commit": "9fdb45d010e83f18b22421e4e73ae37e533a9752"
      },
      "digest": "ebec9c540b050cd6435c4cb0a3b6903261c6711c1f75a183bc0481d1c8a1cdf2"
    },
    {
      "id": "ship/claimyour.gold/fa4227fbd90b",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T23:01:47+02:00",
      "kind": "fix",
      "title": "Fix leaderboard page and prepare for production deployment",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Fix leaderboard page imports and component usage\n- Update TopBar props to use initial instead of handle\n- Add production environment variables example file\n- Create production setup script for easy deployment\n- Fix all module resolution issues for UI components",
      "refs": {
        "commit": "fa4227fbd90bbff86f85e93b162abecf3ddbb852"
      },
      "digest": "56503dccdd7e42e773b407a2cb2e499917db70999a5692e7cb205f61054c24bc"
    },
    {
      "id": "ship/claimyour.gold/a2b0dc9c9c6f",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T22:54:28+02:00",
      "kind": "infra",
      "title": "Update Next.js config to use stable typedRoutes",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "a2b0dc9c9c6f715900f1582d457b8492f2ff910b"
      },
      "digest": "0a6c9fbc6135196f89ab14159f8d3238998283e4f1d6cd17ed340055f03af96a"
    },
    {
      "id": "ship/claimyour.gold/5fd337317d64",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T22:54:02+02:00",
      "kind": "fix",
      "title": "Fix production UI component imports and change port",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Move icons.tsx, primitives.tsx, particle-field.tsx to correct location\n- Remove production-ui directory after migration\n- Change port from 80 to 3001 (port 80 was already in use)\n- Fix module resolution errors for chrome components\n- Update experimental.typedRoutes to typedRoutes in next.config",
      "refs": {
        "commit": "5fd337317d64451c712d8c6d26743c5a3a511e04"
      },
      "digest": "1c0a9df467ac8384b4fc1f232e1e021f90100af9cd5a058154409fc18293ef2f"
    },
    {
      "id": "ship/claimyour.gold/9342beb25e23",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T22:50:26+02:00",
      "kind": "fix",
      "title": "Fix port configuration and rate limiting for development",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Change development server port from 3000 to 80\n- Add memory-based rate limiter fallback for development\n- Allow app to work without Redis/Upstash in dev mode\n- Gracefully handle missing UPSTASH_REDIS_REST_URL env var\n- Maintain production rate limiting with Redis when available",
      "refs": {
        "commit": "9342beb25e238909f7ffcbe6bc8de5a8435ce28a"
      },
      "digest": "da7b7b7e6cb15c3c579b399628516a9fdb00e3f86c4c223e30d03daab318eeac"
    },
    {
      "id": "ship/claimyour.gold/76ef18462dc6",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T22:45:00+02:00",
      "kind": "feature",
      "title": "Add dev login button and fix auth endpoint for development",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Add dev login button to bypass Telegram authentication for development\n- Move dev button outside Telegram widget logic so it's always visible\n- Make hash field optional in portal auth schema\n- Skip Telegram HMAC verification when hash not provided (dev mode)\n- Allow developers to test dashboard/redeem/leaderboard without real auth\n- Log dev mode access for debugging purposes",
      "refs": {
        "commit": "76ef18462dc6e34c7d914de94c1cb9659f766351"
      },
      "digest": "525762801b269dd1a8bf96e4b13e02a26d95a1ea6b8e28f22f982b7d47ced0b4"
    },
    {
      "id": "ship/claimyour.gold/7c34eecdebdb",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T22:39:06+02:00",
      "kind": "other",
      "title": "Integrate production-ready portal views and infrastructure",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Migrate Dashboard (/portal) with balance card, claim flow, progress, achievements\n- Migrate Redeem page (/portal/redeem) with hero, category cards, scale signal, notify module\n- Add Leaderboard functionality with badges, levels, podium, rankings\n- Integrate production infrastructure (env validation, Telegram WebApp auth, rate limiting)\n- Add support/ticket system functionality with FAQ, claim status, categories\n- Update security headers and CSP for Telegram WebApp compatibility\n- Add production Dockerfile and docker-compose configuration\n- Copy production UI components (chrome, dashboard, redeem, leaderboard)\n- Add server logic for balance, categories, notifications, leaderboard data\n- Integrate framer-motion and pino dependencies\n- Set standalone output mode for production Docker builds\n- Add Telegram WebApp frame-ancestors to CSP\n- Maintain luxury gold landing page with production-ready portal UI",
      "refs": {
        "commit": "7c34eecdebdb2ed08968d96684ea9d86e57587b7"
      },
      "digest": "192fd99b81299a4a6830616b908cb7accea47a433b555305bbc59630ab18ec53"
    },
    {
      "id": "ship/claimyour.gold/fb02994b6927",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T17:05:20-04:00",
      "kind": "infra",
      "title": "push dev flag",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "fb02994b69276f329305d16405b9a83a9b28954a"
      },
      "digest": "26fd6847d7fc412f7184edd03058e04cd67323b30ffc60f6333f6a1bc4758c1d"
    },
    {
      "id": "ship/claimyour.gold/8377ab8b2bf9",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T15:35:26+02:00",
      "kind": "infra",
      "title": "Remove redundant ui/ folder after integration",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "All UI components, assets, and functionality have been successfully integrated into the main project. The original ui/ folder is no longer needed.",
      "refs": {
        "commit": "8377ab8b2bf909cf7db3fac21ac7b6bbb2226d04"
      },
      "digest": "884dfead3e0487269e6fd1df8d66899d5fb73f41ff131336f8713bcd8cef90ec"
    },
    {
      "id": "ship/claimyour.gold/d9f3519db80e",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-15T15:33:36+02:00",
      "kind": "infra",
      "title": "Replace UI with new 'Claim Your Gold' landing page",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- Integrate modern gold-themed landing page from ui/ directory\n- Add premium design with animations, particles, and glass morphism effects\n- Implement direct Telegram authentication on homepage (no redirect needed)\n- Add shadcn/ui components and luxury color scheme\n- Include three premium fonts (Figtree, Unbounded, JetBrains Mono)\n- Add responsive sections: Hero, How It Works, Claim Steps, Why Section, Final CTA, Footer\n- Maintain all existing Telegram auth functionality and API routes\n- Update dependencies: class-variance-authority, lucide-react, next-themes, sonner, etc.\n- Smooth scroll from bottom CTA to hero section for authentication",
      "refs": {
        "commit": "d9f3519db80eeb9e0a2d42f271331d4477bf434e"
      },
      "digest": "2887d4a508d35ded856a8a0840437524a62d48ac68a3fdb9c2952525bb6c6cca"
    },
    {
      "id": "ship/claimyour.gold/fba31eb809c7",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-14T21:38:25-04:00",
      "kind": "other",
      "title": "Feat/CSV-Upload (#1)",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "* Feat/CSV-Upload\n\n* chore: remove BYPASS flag for testing without db",
      "refs": {
        "commit": "fba31eb809c76aac90528634d7f735fa79495fd5",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/1"
      },
      "digest": "8a1e122af678d6b3538b977ff3bcb57700981f9daa9f1158b19b0a88f46e88ac"
    },
    {
      "id": "ship/claimyour.gold/fab6c0a6ab2f",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-14T21:33:58-04:00",
      "kind": "fix",
      "title": "telegram HMAC passthrough for extra fields + points pre-check in claim (#2)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "- TelegramAuthData gains last_name and an index signature so all Telegram\n  profile fields are included in the HMAC check string unchanged.\n- verifyTelegramAuth drops the keyof casts so the index signature is used\n  directly, eliminating the field-stripping that broke HMAC for users with\n  last_name or other extra profile fields.\n- portalAuthSchema switches to z.looseObject so extra Telegram fields survive\n  Zod parsing (Zod v4 idiomatic replacement for .passthrough()).\n- handleTelegramAuth spreads the full user object before overriding id and\n  auth_date as strings, forwarding any extra fields to the API.\n- claim route gains an early findUnique balance pre-check returning\n  INSUFFICIENT_POINTS before reaching getActiveRate; the atomic updateMany\n  conditional decrement is left untouched as the authoritative TOCTOU guard.\n\nCo-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>",
      "refs": {
        "commit": "fab6c0a6ab2f6f10083af4f740b95449347404f5",
        "pr": "https://github.com/FlashyLabs/ClaimYour.Gold/pull/2"
      },
      "digest": "c370e15a07a2ca823586d37c26be4a9218c77d56245e1e61eabc30ec8c7b6001"
    },
    {
      "id": "ship/claimyour.gold/f772e75d058c",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T12:40:20+05:00",
      "kind": "fix",
      "title": "correctly type rejected session in authOptions callback",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The previous { ...session, user: undefined } shape clashed with NextAuth's\nSession type. Return { expires } cast through unknown so the JWT-rejection\npath compiles cleanly without weakening the runtime behaviour.",
      "refs": {
        "commit": "f772e75d058cb172a7d24fcd862f41b9b28d847b"
      },
      "digest": "e20b133442009d932258b85895f5d9f70a99aa5e8a39348431f8b21655c04624"
    },
    {
      "id": "ship/claimyour.gold/979a0b5f4e29",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T12:25:01+05:00",
      "kind": "infra",
      "title": "drop unused HMAC_CALLBACK_SECRET env var",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "config.hmac.callbackSecret was loaded from HMAC_CALLBACK_SECRET but never\nreferenced — the callback worker signs payloads with each client's own\nper-client secretKeyEncrypted. Remove the dead config entry and the\nsample line in .env.example so operators stop being asked to set a\nsecret that has no effect (INFO-002).",
      "refs": {
        "commit": "979a0b5f4e29b341cc6f090d62eab88d9a3d7560"
      },
      "digest": "73e899090e8ddf36a1cbf31b36c571824e7eac987bec5b1394176044f669ec01"
    },
    {
      "id": "ship/claimyour.gold/f493c16cf356",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T03:17:40+05:00",
      "kind": "security",
      "title": "scope wallet/balance to the calling client's customers",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "GET /api/v1/wallet/balance accepted any customerId and returned that\ncustomer's gold balance regardless of whether they were linked to the\ncalling business (LOW-004 / GRAY-004). Authenticated clients could\ntherefore enumerate every customer's balance.\n\nVerify a ClientCustomer link exists for { clientId, customerId } before\nreturning the balance, and fall through to a 404 otherwise.",
      "refs": {
        "commit": "f493c16cf356057f69618df93a45e88326a3597e"
      },
      "digest": "05d319e2f6a2f43cdac1b03424d3fff03bdcc5b9f3bafd2a09f7b60266c06256"
    },
    {
      "id": "ship/claimyour.gold/0e4162f41a34",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T03:14:38+05:00",
      "kind": "security",
      "title": "HTML-escape user input in transactional email templates",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The rejection-reason and welcome-credentials templates interpolated raw\nSUPER_ADMIN- and registration-supplied strings (rejection reason, business\nname, email, generated credentials) into HTML email bodies, allowing\nstored XSS in webmail clients that render HTML (MEDIUM-006).\n\nAdd esc() (entity-encode) and escUrl() (entity-encode plus scheme\nallowlist of http/https/mailto) helpers and wrap every dynamic\ninterpolation. Also URL-encode tokens that flow into verify and reset\nlinks so a token containing reserved characters can't trick the parser.",
      "refs": {
        "commit": "0e4162f41a3447731dc800633c0287ae4000152c"
      },
      "digest": "183786762f2b1ce04a8231c1f86cbf5ea7c6e1fd977bcb776f9cb71c27d9b267"
    },
    {
      "id": "ship/claimyour.gold/c87b4fb10239",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T03:02:08+05:00",
      "kind": "security",
      "title": "neutralise CSV formula injection in transaction exports",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Customer email and business name flowed unescaped into the transaction\nCSV exports for both CLIENT_ADMIN and SUPER_ADMIN. A customer who\nregistered with =HYPERLINK(...) or @SUM(...) as their email could trigger\narbitrary spreadsheet formulas in any operator who opened the export\n(MEDIUM-005).\n\nAdd lib/csv.ts which quotes every cell, escapes embedded quotes, and\nprefixes a single quote on values starting with formula triggers\n(=, +, -, @, tab, CR). Use it to build both export endpoints.",
      "refs": {
        "commit": "c87b4fb10239abe16902e9c3d2a4a383c87eef95"
      },
      "digest": "cd14ab69dbc1b4797279a6e498f40b6b589f95cd84c680f579fbfcd960f80e91"
    },
    {
      "id": "ship/claimyour.gold/aaea454874d0",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T02:55:13+05:00",
      "kind": "security",
      "title": "require step-up auth before regenerating API secret key",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A stolen CLIENT_ADMIN session could rotate the API secret key with no\nre-authentication, locking the legitimate business out of their own API\n(MEDIUM-004).\n\nRequire either the current password (bcrypt-checked) or a fresh TOTP code\non POST /api/v1/client/regenerate-secret. Add the corresponding inputs to\nthe regenerate-secret confirmation modal in the client settings page.",
      "refs": {
        "commit": "aaea454874d0f69b28fbfc3f8872d8d5c4c94757"
      },
      "digest": "9c266c6e95d46add17ce1bd55aa4fab226be7ec82114e4b17a18c10421ccaa8f"
    },
    {
      "id": "ship/claimyour.gold/82d17f97425d",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T02:53:43+05:00",
      "kind": "security",
      "title": "revoke client JWTs on password reset and tighten password policy",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "A password reset previously left every existing JWT valid until its natural\nexpiry — an attacker who stole a session cookie kept access even after the\nvictim reset their password (MEDIUM-003).\n\nAdd Client.sessionVersion (default 0). authOptions.session compares the\nJWT's sessionVersion against the persisted value on every request and\nreturns an empty session when they diverge or the client is no longer\nACTIVE. The reset-password route increments sessionVersion in the same\ntransaction that updates passwordHash.\n\nWhile here, raise the password policy from min-8 to a 12-character schema\nthat requires lower, upper, digit, and symbol classes (LOW-002). Apply it\nto client registration, super-admin client creation, and reset-password.",
      "refs": {
        "commit": "82d17f97425da87287de70483c51f58e89a13afa"
      },
      "digest": "6855ade101f56da4389b60c651d9ffa14faf1fff45424204986c012ba7ef15f9"
    },
    {
      "id": "ship/claimyour.gold/73d29dce820e",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T02:51:27+05:00",
      "kind": "security",
      "title": "add HTTP security headers and remove wildcard CORS",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "next.config.ts emitted no CSP / HSTS / X-Frame-Options / X-Content-Type-\nOptions / Referrer-Policy on any route, and applied\nAccess-Control-Allow-Origin: * to every /api/v1/* path including\nauthenticated endpoints (HIGH-004, HIGH-005). The wildcard CORS combined\nwith the now-fixed customer-route IDOR meant any third-party page could\ntrigger gold claims if it knew a customer ID.\n\nApply a baseline set of security headers to every response and confine\nthe wildcard CORS to a small allowlist of intentionally public endpoints\n(currently /api/v1/health). The customer portal and client dashboard are\nsame-origin, and server-to-server API consumers use HMAC-signed requests\nthat are not subject to CORS.",
      "refs": {
        "commit": "73d29dce820ebc146b874d8e73fc60dd37c9e3db"
      },
      "digest": "aeacbca2c2df8c10619bba612e254456c12c1aed39ac4cbf5822a28b46e4b20c"
    },
    {
      "id": "ship/claimyour.gold/70ac3474ba60",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T02:49:51+05:00",
      "kind": "security",
      "title": "bump next to 16.2.4 for DoS CVE GHSA-q4gf-8mx6-v5v3",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "next@16.2.2 has an unauthenticated DoS via uncontrolled resource\nallocation on Server Component endpoints (HIGH-001 / LOW-001 — the\nupgrade also pulls in the postcss XSS fix). Bump next and\neslint-config-next to 16.2.4.",
      "refs": {
        "commit": "70ac3474ba60e2888f3fac19f34922afcdec0578"
      },
      "digest": "c6522d3126d7d02a75b7bb56d86a541e8829939a5f30986492f7d5f142f5d966"
    },
    {
      "id": "ship/claimyour.gold/b2374e93982d",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T02:48:09+05:00",
      "kind": "security",
      "title": "use timingSafeEqual for Telegram auth hash check",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The expected === hash short-circuits on the first differing byte, leaking\ntiming information that lets a remote attacker recover the HMAC byte-by-byte\nand forge a Telegram auth payload (HIGH-002 / HOTSPOT-001).\n\nCompare the hex digests with crypto.timingSafeEqual after a length check.\nReject non-string and length-mismatched inputs early since timingSafeEqual\nthrows on length mismatch.",
      "refs": {
        "commit": "b2374e93982d6af3ad76513f23077b3d2f952d43"
      },
      "digest": "536a1ea09b9d1fe954c912868940fefddf3f9de6f7df7d117e0573fd38ece8c4"
    },
    {
      "id": "ship/claimyour.gold/2dbc7c4f21a4",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T02:47:43+05:00",
      "kind": "security",
      "title": "validate outbound URLs to block SSRF on webhooks",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "The webhook test endpoint and the callback worker both fetched\nclient-controlled URLs with no validation, letting a CLIENT_ADMIN reach\ncloud metadata (169.254.169.254), loopback services, and RFC1918 ranges\nto map internal infrastructure (CRITICAL-002, MEDIUM-001, HOTSPOT-005).\n\nAdd ssrfGuard.checkOutboundUrl that rejects:\n  - non-HTTPS schemes\n  - URL credentials\n  - localhost / *.local / *.internal hostnames\n  - private/loopback/link-local/multicast/CGNAT IPv4 and IPv6 literals\n  - hostnames whose DNS resolution returns any of the above\n\nApply the guard at three points: callback URL save, webhook test, and\ncallback delivery (defence-in-depth in case the saved value pre-dates\nthis check). Also pass redirect: 'error' on outbound fetches so an\nattacker cannot redirect to an internal address after the check.\n\nTighten the URL Zod schemas to require https:// at the validation layer.",
      "refs": {
        "commit": "2dbc7c4f21a4eea1afa706223f8b782636cda968"
      },
      "digest": "bd5ed7a8b19f74ca312c2a13800f311eafd05d1e4643d3d916e68092f832ea7b"
    },
    {
      "id": "ship/claimyour.gold/6af4343256c5",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-02T02:36:36+05:00",
      "kind": "security",
      "title": "replace x-customer-id trust with HttpOnly portal session cookie",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "detail": "Customer portal routes (/api/v1/customer/*) previously trusted any value in\nthe x-customer-id request header, allowing unauthenticated access to any\ncustomer's portfolio, transactions, and claim flow given a guessed or\nobserved MongoDB ObjectId (CRITICAL-001 / GRAY-001).\n\nIntroduce a signed, HMAC-SHA256 session cookie issued after Telegram auth\nvia portalSession.ts. Customer routes now read the customerId from the\nverified cookie payload. Update the portal pages to drop sessionStorage\ntrust and rely on the HttpOnly cookie automatically attached to fetches.\n\nAlso closes the TOCTOU race in the claim flow (MEDIUM-002): the points\ndecrement is now an atomic conditional updateMany that fails when balance\nwould go negative, with a refund path on wallet credit failure.\n\nWhile here, switch auth-route rate limiting to a non-spoofable client IP\nhelper (cf-connecting-ip / x-real-ip / rightmost x-forwarded-for) and\nsupplement IP throttling with per-Telegram-ID and per-email keys\n(HIGH-003).",
      "refs": {
        "commit": "6af4343256c5489e68542f40ce2bd700dee03a22"
      },
      "digest": "eb868fc61f20bac36100bc86cea6fcc6ffebfec99f26de2d40233b1787151fa3"
    },
    {
      "id": "ship/claimyour.gold/b8248c78b0f4",
      "repo": "repo/claimyour.gold",
      "at": "2026-05-01T15:31:27+01:00",
      "kind": "infra",
      "title": "Initial Commit",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/claimyour.gold-ci",
      "visibility": "public",
      "refs": {
        "commit": "b8248c78b0f435e98ef6a9f867209d4619bb8229"
      },
      "digest": "6c32bbef5c89d3f8e3ee092c8d6754a6a0b9f6fdbe5b6fba4a00ff82d244f11e"
    }
  ]
}
