{
  "shipped": "1",
  "source": "repo/flashy-academy",
  "org": "org/flashy-academy",
  "generated": "2026-09-03T02:56:37.620Z",
  "entries": [
    {
      "id": "ship/flashy-academy/0b70adb64700",
      "repo": "repo/flashy-academy",
      "at": "2026-09-03T02:55:04Z",
      "kind": "other",
      "title": "The machine-age doors: /engage names the three ways in",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-03",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "One page under the academy prefix — where the host rewrite lands bare\npaths — with three doors, each cited rather than restated: an AAO\ncharter our agents can read (conformance init, flashyos.com/join through\nMESH_JOIN, and the handshake this property serves from public/, excluded\nfrom the rewrite), the human graph (magician.network/join and this\nproperty's concierge), and the machine surfaces an agent reads here.\nIntentMesh is named without a link because no URL for it exists yet; the\nestate ladder is one line, cited to gord.holdings/engage. Registered in\nthe footer resources, llms.txt and the sitemap; engage.test.ts pins the\npage, the three doors and both join links.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01EXAA7bi94PPtBupN1jGt9N",
      "refs": {
        "commit": "0b70adb64700b464d34c7723755b3eabc09de174"
      },
      "digest": "a4ce20463ff1f3bed0b88ad3bd280e2e82ac0752b0829cb8f44bec07052b4293"
    },
    {
      "id": "ship/flashy-academy/4256e9f0b0d9",
      "repo": "repo/flashy-academy",
      "at": "2026-09-02T16:22:19Z",
      "kind": "other",
      "title": "Re-vendor: the ship log learns ritual/1 before its first commit",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-02",
      "assertedBy": "agent/flashy-academy-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": "4256e9f0b0d96cf1a3772b112d35e3f6d929e566"
      },
      "digest": "c8ea813f49cbd272044ecbec93ef59a16e6c8370a67244f5f39f51e1e6d0a5f2"
    },
    {
      "id": "ship/flashy-academy/46690b094766",
      "repo": "repo/flashy-academy",
      "at": "2026-09-02T16:13:38Z",
      "kind": "feature",
      "title": "deploy/1: declare where this repository is hosted",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-02",
      "assertedBy": "agent/flashy-academy-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": "46690b0947664ee7e1ed91764602222c97abea90"
      },
      "digest": "0649c09865107b65973058a690d3d4ec6e4bb83d5545a79cc2c19c89f782d871"
    },
    {
      "id": "ship/flashy-academy/5512fecb03ee",
      "repo": "repo/flashy-academy",
      "at": "2026-09-01T21:08:56Z",
      "kind": "feature",
      "title": "Tell the estate the moment this repository pushes a record",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/flashy-academy-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": "5512fecb03ee3203d66082295652ecd676b3e827"
      },
      "digest": "b639131cd0aabdedbd38e790e6a5d8676f57ef95f3c3385b09c5276a888eb89d"
    },
    {
      "id": "ship/flashy-academy/fd117bf6df52",
      "repo": "repo/flashy-academy",
      "at": "2026-09-01T19:22:13Z",
      "kind": "feature",
      "title": "Serve the backlog projection at /.well-known/intent.json too",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/flashy-academy-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": "fd117bf6df527e9f122aaff3edce5330d2f5ab93"
      },
      "digest": "76dbc49da9b6f5852cd9e1278f90172ddd7c330921338fb61a628910c4f793a7"
    },
    {
      "id": "ship/flashy-academy/97decd90f881",
      "repo": "repo/flashy-academy",
      "at": "2026-09-01T18:54:17Z",
      "kind": "fix",
      "title": "Activate the concierge, and fix a layout that has not compiled since the Bolt rollout",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "**`src/app/layout.tsx` on main does not parse.** `import Bolt from\n'@/components/Bolt';` sits inside another import's brace list, landed by\n`6c07bc6 Bolt Rollout: Flashy Academy takes Ember`, and `npm run\ntypecheck` has been failing on it since. Whatever ran after that commit\ndid not run typecheck, and a syntax error in the root layout is not a\nsubtle one — it fails the build, so what is deployed is older than main.\nFixed by moving the import above the brace it was inserted into.\n\nThen the Activation standard's three door artifacts. `/concierge.js` is\nthe built 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. The page says what the door is\nnot: nothing filed there grants a shield, a cohort place, or anything\nthis property charges for — the free-shield path was a real economy bug\nhere once and an intake panel is where somebody reads an offer that was\nnever made.\n\n**The middleware would have 404'd the script, and its own test caught\nit.** `FILE_EXTENSIONS` deliberately excludes `.js` — bundles come from\n`_next/static` and `node.js-in-anger` is a plausible slug — so\n`/concierge.js` would have been rewritten to `/academy/concierge.js` on\nflashy.academy and served nothing. A script tag that 404s reports\nnothing; the door would simply have been absent on the live domain while\npresent in the repository. `ABSOLUTE_FILES` names the one exact path\nrather than opening the extension, which would start rewriting every\narticle whose slug ends in a framework name. The sweep that caught it\nreads `public/` rather than listing it, which is why it could catch a\nfile nobody had thought to add to a list.\n\nOne thing that looked like a defect and was not: five TypeScript errors\nin the Gold payout services turned out to be a stale generated Prisma\nclient on this machine. `npx prisma generate` clears all five, and the\ntree is clean.\n\nKind: fix\n\nCo-Authored-By:",
      "refs": {
        "commit": "97decd90f881802a744adacd956c9ce3a51d8421"
      },
      "digest": "324d72e4690543229c6847800583e94f42023779c8ade78be798411ab0f07310"
    },
    {
      "id": "ship/flashy-academy/e2c3a0cf9993",
      "repo": "repo/flashy-academy",
      "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/flashy-academy-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": "e2c3a0cf99935f4f1736adef5590a85ecdff6916"
      },
      "digest": "df699e5535bd3eca5a436549915a36be3bb9bccf37a750c5153183356970a75d"
    },
    {
      "id": "ship/flashy-academy/72363a96a730",
      "repo": "repo/flashy-academy",
      "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/flashy-academy-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": "72363a96a730fbf34c510a086cfd3740756969e6"
      },
      "digest": "b2b112fdee31df86742faccbc9a189c45e6427fd2eee9e78d2716330cd03768e"
    },
    {
      "id": "ship/flashy-academy/b71ece798802",
      "repo": "repo/flashy-academy",
      "at": "2026-09-01T17:26:15Z",
      "kind": "fix",
      "title": "Fix a layout that has not compiled since 31 August, and one env name",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "src/app/layout.tsx has been syntactically invalid on main for a day. The\neaster-egg rollout inserted `import Bolt from '@/components/Bolt'` in the\nmiddle of a multi-line import — an import block cannot contain an import\nstatement — and the commit carried [vercel skip], so nothing ever tried\nto build it. The site has been serving the last good build since.\n\nTwo of my own rules, both written down, both broken by the same commit:\na marker that exists for the emitters must never ride a commit that\nchanges what the site renders, and a naive \"insert after the last line\nstarting with import\" lands inside an unclosed one. The second is why\nthis repository and not another: only here did the last import happen to\nbe multi-line.\n\n`npm run build` passes now, which is the check that would have caught\nit — typecheck and the suite both pass over a file the bundler cannot\nparse, because neither of them parses the app router's entry.\n\nAlso in this commit, the smaller thing that led me here.\nFLASHYGOLDAMS_API_URL is read by five services and points at\nClaimYour.Gold's API — `flashygoldams` is what that product was called\nbefore the rename, and the name now reads as `flashy.gold`, which is a\ndifferent property with a different mesh org and a different domain.\n\nclaimYourGoldApiUrl() is the one accessor, reading\nCLAIMYOUR_GOLD_API_URL and 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. On a path that pays learners gold, a variable\nthat quietly resolves to '' fails the payout, so the warning is the\ncheap half of that trade — and it is the only thing that will say the\nVercel half is still outstanding.\n\nKind: fix",
      "refs": {
        "commit": "b71ece79880295c59211c6b364263eb40d1eed68"
      },
      "digest": "7ca17da768e84df3cfa88d8016fd6c002b2dd13412389b19995238f125f795eb"
    },
    {
      "id": "ship/flashy-academy/b32932ab169d",
      "repo": "repo/flashy-academy",
      "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/flashy-academy-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": "b32932ab169db7ab77548822491f0fc31708353b"
      },
      "digest": "ea2c8a26578cc09329afbc742cf52e0794f16faa29fa69fec3fa565200ff9732"
    },
    {
      "id": "ship/flashy-academy/acada70329fd",
      "repo": "repo/flashy-academy",
      "at": "2026-09-01T14:33:32Z",
      "kind": "fix",
      "title": "Re-vendor check-directory.mjs: enforce what every edge type must carry",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/flashy-academy-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": "acada70329fd4afaf98ba27beb74ba417c788f0e"
      },
      "digest": "b59930ad8bbf55881607c248544c9bffceb1f2a5aec66dac6c6e5a5ca71e018e"
    },
    {
      "id": "ship/flashy-academy/1a75a9322477",
      "repo": "repo/flashy-academy",
      "at": "2026-09-01T14:23:56Z",
      "kind": "feature",
      "title": "Open the LICENSE with the licence, so a scanner can see it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "GitHub reports NOASSERTION on this repository despite a complete, genuine\nlicence file. So does SPDX, and so does every SBOM generator and licence\ncompliance tool that reads the same signal — which is what stalls an\nenterprise procurement review before a human opens the file.\n\nThe cause is that a copyright line and a sentence of description sat above the\ncanonical text, and a scanner reads the first bytes. Measured on 2026-09-01:\nall thirteen repositories in this estate that carry a LICENSE read NOASSERTION,\nnot the one that an outside review happened to notice — that one is simply the\nonly public repository, so nobody had ever looked at the rest.\n\nThe copyright is not dropped. A licence text naming nobody is a grant on\nbehalf of nobody, which this estate has already written up once. Both licences\ndesignate a place for it — Apache's APPENDIX, the AGPL's \"How to Apply\" — and\nit now sits there, which satisfies the scanner and the lawyer at the same time.\n\nNothing about the licence changed: same licence, same holder, same terms. The\nrule and the rewrite live once, in flashyos's tools/estate-licences.mjs, with\ntests.",
      "refs": {
        "commit": "1a75a93224775a3c158a188f03278409f38c7ea6"
      },
      "digest": "2736acaeb5ce97ebb4b30ccb5235bfc7101a3a8228bf76a14a85e37db5146286"
    },
    {
      "id": "ship/flashy-academy/83b359f0f57f",
      "repo": "repo/flashy-academy",
      "at": "2026-09-01T03:41:08Z",
      "kind": "docs",
      "title": "Document the shard, and deploy it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-09-01",
      "assertedBy": "agent/flashy-academy-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": "83b359f0f57fe9e061f2c508a8510ed73be0e066"
      },
      "digest": "98b385f33edf4ee1ffecc46ea4b1834abbaf18c9d205b091364e9be547f7c0f0"
    },
    {
      "id": "ship/flashy-academy/d31f611db127",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T21:06:01Z",
      "kind": "feature",
      "title": "This property hides CANON [vercel skip]",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "bolt/1 — every live property in the estate hides one word, and the set proves\nitself at gord.holdings/hunt/ in the finder's own browser against a published\ncommitment. Type \"flashy\" on any page and the bolt strikes in this property's\nown accent.\n\nA server component reading .bolt/bolt.html at build time, generated by\nvendor-bolt.mjs from .bolt/config.json. Deliberately not a client component\nwith the shard in a prop: that puts it in the RSC payload of every page and in\nthe client bundle, findable by anyone who opens devtools rather than anyone who\nfinds it. Absent is fine and silent — a checkout without the snippet renders\nthe site with no egg rather than failing to build.\n\nKind: feature",
      "refs": {
        "commit": "d31f611db12799723c0b30b3b452bc0650ddd23b"
      },
      "digest": "04533f025c79180f280b579fe4e0e9b70ccaa076fe71a6b6cb70dc8741861233"
    },
    {
      "id": "ship/flashy-academy/51d8163901d7",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T20:54:02Z",
      "kind": "infra",
      "title": "Hold the attribution line: freeze what sealed, refuse what would seal next",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-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": "51d8163901d73629e8599924c3b759442abc181c"
      },
      "digest": "686306cb61260d596a8a37adf89008405e35a4abbfc795509cafd7c68b5b35c4"
    },
    {
      "id": "ship/flashy-academy/073b82af94df",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T19:38:25Z",
      "kind": "fix",
      "title": "Re-vendor the shiplog emitter: the bookkeeping filter learned its suffixes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-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": "073b82af94dfc84817ffe12b760cf0d15a44c0ea"
      },
      "digest": "c5e112201e1c12d72af009a8465bb392b344fffe61e6af710df1f8a2961398cf"
    },
    {
      "id": "ship/flashy-academy/aa34e66f6550",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T17:38:11Z",
      "kind": "infra",
      "title": "backlog/1: refresh the fragment [skip ci]",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "aa34e66f65504ac527fcc9285302db4cf789ef86"
      },
      "digest": "68ae33307b5cf169362e376f5d8a4c7b74c1cb17b3fb9ec67ccb10d0cf29bc40"
    },
    {
      "id": "ship/flashy-academy/f892a2129c2c",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T17:19:40Z",
      "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/flashy-academy-ci",
      "visibility": "public",
      "detail": "The backlog and shiplog workflows carried a bare 'git push', which loses\nthe race whenever main moves under the run — the failure flashyos hit\nthree runs straight before growing the regenerate-on-the-new-tip retry\nthis ports. Rebase is deliberately not the retry: these artifacts derive\nfrom the very history that moved.\n\nWhere this repository's served public/directory.fragment.json trailed\nthe committed record (the diff the Directory workflow refuses), the two\nare re-synced from the emitter's output, with every directory check run\nlocally before committing.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo",
      "refs": {
        "commit": "f892a2129c2c89ccf347308ecb1a0563519463e5"
      },
      "digest": "9e86b51b0984af92b6b1bf5a3ba67a9a86552b31380e33881d63b2439cf337db"
    },
    {
      "id": "ship/flashy-academy/a5d617623d40",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T17:15:23Z",
      "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/flashy-academy-ci",
      "visibility": "public",
      "detail": "flashyos.com publishes syndicate/1 at /estate-feed.json; its properties block\ncomputes a ring per property — for flashy.academy, 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. Both are right. What must not happen is the\ntwo drifting about the five they share, or a computed neighbour sitting below\nLIVE — which quietly keeps it out of the footer and the subOrganization graph\nwhile the estate says the link should exist.\n\nThat exact drift shipped. flashynetwork.com has served its homepage, explorer,\ncheckpoint and well-known surfaces for weeks, and this list said BUILD, so\nnothing here linked it and nothing could say so. It reads LIVE now, verified\nagainst the live domain on 2026-08-31, and the new check makes the class\nimpossible to ship again: computed-link-not-live is a finding.\n\nscripts/estate-feed-check.mjs follows the estate's checker split — dependency-\nfree ESM whose live half runs with bare node against academy.json and the live\nfeed, and whose pure comparison half is fixture-tested offline. The four\nfamily-only siblings carry written exemptions, and an exemption that stops\nbeing true becomes a stale-exemption finding, so the list self-cleans.\n\nKind: fix\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01NfXZ2PAsNCENGJupuCQrnH",
      "refs": {
        "commit": "a5d617623d40598b0926c5d7a9fd4b072660a867"
      },
      "digest": "8535390fc8262c0a58a2e974baf2da7a4fc776bc64e6b9ff56b2911b5a45f7dd"
    },
    {
      "id": "ship/flashy-academy/c0432f97f9ec",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T16:59:21Z",
      "kind": "fix",
      "title": "Serve the icon at the two paths that never go through the head link",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "/icon.svg was correct and current — the bytes the domain serves are identical\nto the repository's. The favicon still looked stale because two paths never\nconsult the <link> at all:\n\n  /favicon.ico     404'd. Chrome requests it directly for bookmarks and some\n                   tab contexts, and a long tail of feed readers and chat\n                   unfurlers is hard-coded to it. A client that gets nothing\n                   keeps the icon it already had, which is exactly what \"the\n                   favicon isn't updating\" looks like from outside.\n  /apple-icon.png  absent. An iOS home-screen tile, and no SVG support at all.\n\nBoth are now generated by scripts/make-icons.mjs, which reads the same path\ndata and the same two colours out of icon.svg and rasterises them. A\nhand-drawn second copy would be a second source of truth for the logo, and\nthis estate has been bitten by every one of those it has made. Dependency-free\n— node:zlib is all a PNG needs — so it runs before an install like the other\nemitters here.\n\nicons.test.ts does not check that the files exist; it checks that regenerating\nthem right now would produce the same bytes. Confirmed against a negative\ncontrol: changing the accent in icon.svg turns it red.\n\nKind: fix\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01VgrPGGUFKMq9zXBHnfcTgs",
      "refs": {
        "commit": "c0432f97f9ec61e4c85234e979b5f4da05f926f9"
      },
      "digest": "2fa86c61276e0462d3d10819f047087665a390f8c58ca0bfe9b44b366f308b72"
    },
    {
      "id": "ship/flashy-academy/e48e1d97125d",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T16:44:59Z",
      "kind": "feature",
      "title": "Give a person the door the agents have had all along",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The handshake here has advertised `join` to agents since it shipped and no\npage linked it. A live survey of the estate on 2026-08-31 — fetched over the\nnetwork rather than read from git — found the machine door at six of seven\nproperties and the human door at nought of eight.\n\n`MESH_JOIN` is absolute and deliberately not in `ACADEMY_RESOURCES`, where\neverything resolves against a base that differs between flashy.academy and\nclaimyour.gold/academy. This app serves two hosts and the door serves neither;\na relative link would 404 on one of them or, worse, resolve to the wrong site.\nA test pins that, and pins the constant to the `join` the handshake serves.\n\nKind: feat",
      "refs": {
        "commit": "e48e1d97125d06ffe0f66adb32a0b6e842bb0924"
      },
      "digest": "d0dbee2114f4d7a8711d01a1f07431c31f0d42ad8f95b28158b550ad5c0673d0"
    },
    {
      "id": "ship/flashy-academy/1809b37bd5c2",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T16:42:43Z",
      "kind": "fix",
      "title": "An emitted record must not spend a deploy [vercel skip]",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-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": "1809b37bd5c2bd5111cda20b3618fcfd103f6245"
      },
      "digest": "ac5a056d42a6e0a9041086f7af9652cc66e1304494f97f9f093022ab415d470c"
    },
    {
      "id": "ship/flashy-academy/e5bb3f0d2cd0",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T14:19:49Z",
      "kind": "fix",
      "title": "A file in public/ is addressed absolutely, and that is a rule now",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "`/lockup.svg` and `/bolt.svg` — this site's own logo — return 404 on\nflashy.academy. So does `/directory.fragment.json`, which is why the estate\ngraph merge could not read this property. All three sit in `public/`, all\nthree are served correctly on the Cloud Run URL, and the domain routes every\nrequest for them away.\n\nMiddleware runs before Next serves `public/`, so the host rewrite turns\n`/lockup.svg` into `/academy/lockup.svg` and lands on nothing. The exclusion\nlist has now been wrong three times in the same way: it was `['/api']`, then\nthe machine surfaces were missed and every `.well-known/…` 404'd, then\n`/llms.txt` and `/flashyos.roles.json` were added by name — and the three\nabove were still broken, because a list only ever contains what somebody\nalready thought of.\n\nIt is a rule instead. A root path with a file extension is a file, and a file\nis addressed by its absolute path; `/tracks` and `/llms-txt-explained` are\npages and still move.\n\nTHE TEST HAD THE SAME DEFECT AS THE CODE\n\nIt listed eight paths by hand and passed green the whole time the logo was\nmissing. It walks `public/` now, so a file added there is checked by existing\nof. That took the assertions from 8 to 19 and immediately covered the three\nnobody had named — verified by disabling the rule and watching all five\npreviously-unreachable paths fail.\n\nKind: fix",
      "refs": {
        "commit": "e5bb3f0d2cd0657e403599b8a5ea5c439a0199ab"
      },
      "digest": "c0bf8930f99017b7a2751aa568976804e0168fb400c455e61459f5c749a4dd79"
    },
    {
      "id": "ship/flashy-academy/ea01b0225e9d",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T13:45:10Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "ea01b0225e9d4719f3d8d547463bc322b437280e"
      },
      "digest": "c8e401a2b01758b20efa68221be8edfdbaacc749ffa86a56d276c9feb3e9c70c"
    },
    {
      "id": "ship/flashy-academy/5b7569d929e1",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T13:09:40Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "5b7569d929e1cc2ad8e03eda0860effd1896fef3"
      },
      "digest": "9972d05a9b663d7a6d3b28ea4d14627399566d3931d2e0e61a78bf1841868275"
    },
    {
      "id": "ship/flashy-academy/be84c1afe211",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T12:27:41Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "be84c1afe211ba011418e08c70674dcf223b446a"
      },
      "digest": "77e929bfa5f43d00c44684c9acc6c313144841a753b5cdeb3d442a275da7c7df"
    },
    {
      "id": "ship/flashy-academy/89ab1219109f",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T12:26:51Z",
      "kind": "other",
      "title": "Re-vendor the directory checker, which had drifted in twelve repositories",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-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": "89ab1219109f0e2e511c4b8ec59344aa5a6b03fd"
      },
      "digest": "cc60ae19bb285088802c7f4416afb2b723ed77bfe39f9e3834d9814fd00a73b9"
    },
    {
      "id": "ship/flashy-academy/e66207f0d828",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T10:57:42Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "e66207f0d8283fba0ac4ee8a67e77c3fd3a95de5"
      },
      "digest": "dfbce0a7a0cceb659162e39c3f3a3c5a0d85dce6a2e0175b7481e3921cb69458"
    },
    {
      "id": "ship/flashy-academy/4c4f9239625b",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T10:18:36-04:00",
      "kind": "feature",
      "title": "Merge pull request #23 from FlashyLabs/claude/gord-directory-spec-3jx7zk",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The logo and the favicon 404 on the domain, and nothing was looking",
      "refs": {
        "commit": "4c4f9239625b0dae3de2c15ac4daffae522219d3",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/23"
      },
      "digest": "925e677619d3986f933644976517e1986d2e25a7256ff0521f738c0980fce574"
    },
    {
      "id": "ship/flashy-academy/afe90e36dbb4",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T09:44:51-04:00",
      "kind": "feature",
      "title": "Merge pull request #22 from FlashyLabs/claude/gord-directory-spec-3jx7zk",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Stop the host rewrite from routing machine surfaces into a 404",
      "refs": {
        "commit": "afe90e36dbb494deb472c1292237f2d4849300c7",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/22"
      },
      "digest": "0c9275d96ebf602c63ba6dceb56d091f0b73319744d134d2f69b84c35fd5a3e1"
    },
    {
      "id": "ship/flashy-academy/c1637cecbfc8",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T09:09:28-04:00",
      "kind": "feature",
      "title": "Merge pull request #21 from FlashyLabs/claude/gord-directory-spec-3jx7zk",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Name the missing repository instead of reporting a denied permission",
      "refs": {
        "commit": "c1637cecbfc8d6a0f8845766bc30658d76f92364",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/21"
      },
      "digest": "92800a3f29a52ed0989ac8ff29057265369daa86161b2975d8c57adcd7c4b748"
    },
    {
      "id": "ship/flashy-academy/4e808ee1bd01",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T02:57:20Z",
      "kind": "feature",
      "title": "Merge standard/organizations-resolve — where flashy.academy's identifier goes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Three commits: the property serves /organizations/flashy-academy under\ndirectory/1 Rule 14, so a permanent identifier dereferences to a record rather\nthan being a primary key only its holder can read; the credential issuer becomes\nsomething a reader can check; and the vendored directory validator learns two\nclaim types.\n\nThe one conflict was that validator, and the resolution is not a coin toss.\nMain's copy listed neither `engaged` nor `controls`; the branch adds both and\nrecords why. `engaged` — a commercial relationship between two organisations —\nhad been missing from this copy for as long as it has existed while the\ncanonical list in @flashyos/directory carried it, so this validator rejected the\none claim type the estate's product is about and would have failed CI the first\ntime this repository published a partner. Taking main's side would have\nre-broken it.\n\n271 tests pass, typecheck clean, directory validator clean at 21 nodes and 28\nedges. One suite does not load — scripts/flashyos-role-mesh.test.ts imports\n@flashyos/conformance, which is declared in package.json and not installed in\nthis checkout. It fails identically on main and is an uninstalled dependency\nrather than anything in this merge.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_0198vyysGCrfdioK9uQr3kbs",
      "refs": {
        "commit": "4e808ee1bd01ee15e9b0f3dce861fed6bb7501f1"
      },
      "digest": "2df6e3789b5e0879e2f114f51e8129bcaebfabe5fdfefe692b3b3a1af74e1777"
    },
    {
      "id": "ship/flashy-academy/f43620cad903",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T02:18:40Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "f43620cad9037c6146360293493f38593d324568"
      },
      "digest": "bc6d282403724e69b76454199fbd5b86dcba8386272a8a224487fa5e34b55319"
    },
    {
      "id": "ship/flashy-academy/5d3d8d1dc424",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T02:18:29Z",
      "kind": "other",
      "title": "Re-vendor the backlog emitter: it can revise an item now",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-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": "5d3d8d1dc424ea2c2db4574f051511aa0bb1f100"
      },
      "digest": "4ccce473e06979b8bec140469ba34bc62678272f18ce2ba67c14dd212bbc17ed"
    },
    {
      "id": "ship/flashy-academy/c91c6c62e657",
      "repo": "repo/flashy-academy",
      "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/flashy-academy-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": "c91c6c62e657747dcaf7c449e4950d00c542fd15"
      },
      "digest": "687b0227ac74edc45f78b53e8905ee63e7ebfd229a85a40ae95718e4284dd156"
    },
    {
      "id": "ship/flashy-academy/b4ee79dbe737",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T00:51:37Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "b4ee79dbe7372e9b0d3ba7b4cc38911bc3440e28"
      },
      "digest": "9c98bc1b7bd2c16c5a0ed50893b753363de7010ea07cc878e48c1556f676fa83"
    },
    {
      "id": "ship/flashy-academy/6a41bc8b0268",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T00:50:55Z",
      "kind": "feature",
      "title": "Declare the machine surfaces this property serves",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-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": "6a41bc8b0268bd5b8733d1dc6d8b5a974fd97507"
      },
      "digest": "47bf987c9d7597e8ea9e475ad6481acf7f25b20990f4cc311310a583b760f296"
    },
    {
      "id": "ship/flashy-academy/a73a6df298d0",
      "repo": "repo/flashy-academy",
      "at": "2026-08-31T00:48:02Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "a73a6df298d0972319127018ae197d3b9aafc7c5"
      },
      "digest": "59681e05c1322060498ef6d6835ffa48ad859bef27bffe4f33d6ec35c55248e6"
    },
    {
      "id": "ship/flashy-academy/f311ebfc4531",
      "repo": "repo/flashy-academy",
      "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/flashy-academy-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": "f311ebfc4531e29c5038f96ad1e6749011ad48cf"
      },
      "digest": "bf16cd6091a50fc7a30120e257ae5eaefa74ccdb26e0d1aefbdb6e37ff38483c"
    },
    {
      "id": "ship/flashy-academy/9f86bef59089",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T22:06:02Z",
      "kind": "other",
      "title": "Re-vendor the checkpoint and frontdoor emitters",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-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": "9f86bef59089183a19eb1e2373b295c8011c943d"
      },
      "digest": "ce041f0f9421a706c94cb68604aab706bdce1b743e8d3c698a428e18fcceff2f"
    },
    {
      "id": "ship/flashy-academy/1134396a1efa",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T21:44:13Z",
      "kind": "fix",
      "title": "Read the emitter id, do not derive it",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-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": "1134396a1efa7ba4257c9ce17fd7d7b90c84aba3"
      },
      "digest": "eb60044ba646ab870f2c02412ac3d199cf30d25423c06b70af3aa879462e12cc"
    },
    {
      "id": "ship/flashy-academy/2dd5341f92ad",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T21:38:21Z",
      "kind": "feature",
      "title": "Declare the machine that signs this repository's record",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-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": "2dd5341f92ad49a3611007537bed686bbf2fa25c"
      },
      "digest": "46623ce91066fcd5b9e1901b88d732e7ef3f0d0943cbd13f15069f8d1c891ff8"
    },
    {
      "id": "ship/flashy-academy/c41f7cadb3f9",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T19:46:23Z",
      "kind": "infra",
      "title": "shipped/1: refresh the log, and the checkpoint over it",
      "by": [
        "agent/unattributed"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "c41f7cadb3f95fa631579c6997fbeb8a9f369088"
      },
      "digest": "0fcd654d7c15676426386103cd45635f5a4ba3fcbbd4e7976223f883c59d153e"
    },
    {
      "id": "ship/flashy-academy/14b4ac93e8ba",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T19:45:07Z",
      "kind": "fix",
      "title": "Re-vendor the charter checker: it had drifted from the spec",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-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": "14b4ac93e8baf93074e136f0b01406c616c8cd77"
      },
      "digest": "b072d9a596518a827783da4a8b9e2223d6d4fea5218247b1848d8bebf0208808"
    },
    {
      "id": "ship/flashy-academy/4742432d3728",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T19:36:54Z",
      "kind": "other",
      "title": "Conformance from the package, not from a copy of its rules",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "scripts/flashyos-role-mesh.test.ts carried its own SPEC_KEYS array and its\nown copy of the ten families, both typed out from the spec. That is a\nvendored snapshot of a live source with nothing to notice when the two\ndiverge — and this repository has already been bitten by exactly the failure\nthose constants are meant to catch: a  key that failed all five\nstatic conformance questions, because the suite stops at the first invalid\nmanifest and a fully-populated roster then reads as an org that declared\nnothing.\n\nassertProperty imports those constants from @flashyos/aao, so a spec change\narrives on the next install rather than never, and it is applied to the two\ndocuments under public/ — what a stranger actually fetches.\n\nWhat stays is what is true of this organisation and of no other: a purpose\nlonger than the spec asks for, a measure on every role, operations and\nfinance deliberately empty, and the five role names shared with\nClaimYour.Gold on purpose.\n\nKind: refactor",
      "refs": {
        "commit": "4742432d37288a979f80348ae30111f6987ca808"
      },
      "digest": "0c710cb0a88191c4e4fdcffef6cbdbe7cd844503525a0841d3dbadc5702d49e2"
    },
    {
      "id": "ship/flashy-academy/c819d6eb1e0a",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T19:32:28Z",
      "kind": "docs",
      "title": "Carry the house rules, so an agent stops having to guess them",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Twenty of thirty-five repositories had no CLAUDE.md or AGENTS.md, and an\nagent with no repository doc guesses. Every avoidable mistake made across\nthis estate on 2026-08-30 happened in a repository without one — and each\nwas a fact that is true everywhere rather than a fact about that\nrepository:\n\n  work pushed to `main` in eleven repositories whose default branch is not\n  `main`, deploying nothing and read by nobody, with the push succeeding;\n\n  a vendored emitter trusted after its source changed, so a privacy hold\n  added that morning did nothing in sixteen repositories and published the\n  entry it was meant to withhold;\n\n  a copyright holder guessed as the studio on a client's site;\n\n  measurements reported from a working copy while claiming to describe the\n  branch that ships — twice, in two tools, by two agents, four hours apart.\n\nNone of that is repo-specific knowledge, and writing it thirty-five times\nwould drift the first time it changed. It is declared in\n`tools/estate-house-rules.mjs` in flashyos and synced between two markers.\nEverything outside the markers is this repository's own and is never\ntouched.\n\nWhere this file is new it says the repository is not yet described, which\nis true. A generated description would be wrong and would read as\nauthoritative; admitting the gap is a task somebody can close in a minute.\n\nKind: docs",
      "refs": {
        "commit": "c819d6eb1e0a859156c11207795b70f566414b40"
      },
      "digest": "a2414844b4daca933dddaca76c55f0be370dcaf639a8850143ea1f1962604c58"
    },
    {
      "id": "ship/flashy-academy/84050337c545",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T18:01:10Z",
      "kind": "other",
      "title": "Re-emit against the rebased tree",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Kind: chore",
      "refs": {
        "commit": "84050337c545e1f42dd0edd1d6134f73f94504a5"
      },
      "digest": "22349ffe8e64d569146ba67c755c7368d4cfb0b772891226b3192e62fb15dbdb"
    },
    {
      "id": "ship/flashy-academy/2462c7be8788",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T17:58:50+00:00",
      "kind": "fix",
      "title": "Carry the current vendored emitters",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-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": "2462c7be8788f66ea4f36decb4100857f7b99751"
      },
      "digest": "598cd3a54136a51440090f225cacb25f5f4a1da9351bb9dd8e31b5661a92fd4c"
    },
    {
      "id": "ship/flashy-academy/3924d0b5dedd",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T17:37:58+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/flashy-academy-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": "3924d0b5dedd2d50cca713107acd761b37042203"
      },
      "digest": "b4344e6fd99bad4636e8fa3ef492a8d40cd660a1790b0e49b834969a7df0a16a"
    },
    {
      "id": "ship/flashy-academy/ded0049d383b",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T17:22:35+00:00",
      "kind": "other",
      "title": "Re-emit the log and its checkpoint after rebase",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Kind: chore",
      "refs": {
        "commit": "ded0049d383beca174118d8765c8a036296b1a0d"
      },
      "digest": "691edfe1ce259f96f7a7c084ce2a258eb90c49ef1aff8fed746f7e3964b50c14"
    },
    {
      "id": "ship/flashy-academy/c22202f00b38",
      "repo": "repo/flashy-academy",
      "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/flashy-academy-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": "c22202f00b3898ed4594591ad0ab5c0e8925db1d"
      },
      "digest": "96b4e94754aeccf920a610790265fd8691a23cab870d07a54a4480008ad0bb13"
    },
    {
      "id": "ship/flashy-academy/0149ed06a1d7",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T16:18:22+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/flashy-academy-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": "0149ed06a1d707104cfd24e9fedb5d6a07db6c8c"
      },
      "digest": "4b47dedd1cc6ae845af814c6d54d7acbda26d8216c78ea05b31d10062f0fb008"
    },
    {
      "id": "ship/flashy-academy/17e48875616e",
      "repo": "repo/flashy-academy",
      "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/flashy-academy-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": "17e48875616e7f50e5f24dac08a2c16b211ddc81"
      },
      "digest": "769dd6f5270b786e983d58a927594bc344362178d5a93a44beca9122e203ecd0"
    },
    {
      "id": "ship/flashy-academy/813df4a3f262",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T13:21:10+00:00",
      "kind": "infra",
      "title": "Reclassify the log against the convention this estate writes in",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The derived log was classified only by conventional-commit prefixes, and\nthis repository writes declarative English. Unclassified went from 100%\nto 24% 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": "813df4a3f26213c228d7d63f7920b9dc6b125b83"
      },
      "digest": "b3de25535fb49eb8a7d6574bd1a178f895029b7cddae21fc354424ccb6fe4f9c"
    },
    {
      "id": "ship/flashy-academy/73ca3a6e7be8",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T05:45:09+00:00",
      "kind": "feature",
      "title": "Adopt backlog/1 and shipped/1",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-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 63 entries from this repository's own history, every seal\nrecomputed. Org org/flashy-academy, 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": "73ca3a6e7be8ef9154dd3d4df494a857f0cfc5ad"
      },
      "digest": "f7b55a2a75591f1cd89c1639a9280bfda2a5a9d1a54fecf5698c1f37b19b2ccb"
    },
    {
      "id": "ship/flashy-academy/e64787c5d7ff",
      "repo": "repo/flashy-academy",
      "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/flashy-academy-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": "e64787c5d7fff71b20e97082bccae49c32cdecf5"
      },
      "digest": "aad5e95212db2e5f83b3cbf9e31fa51a719349bcc36e824cbcca146a8db7eefb"
    },
    {
      "id": "ship/flashy-academy/40531e4de0b9",
      "repo": "repo/flashy-academy",
      "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/flashy-academy-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": "40531e4de0b9a1615fe4c62c109523e56a9c135d"
      },
      "digest": "bd54224c27285c64bd2f3e00520782ee41e19439fd747508531cc4c01961bd48"
    },
    {
      "id": "ship/flashy-academy/cdc7386e5ca6",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T01:59:07Z",
      "kind": "other",
      "title": "Module gold reaches the ledger",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-31",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Passing a quiz for the first time computed goldEarned, wrote it onto the\nattempt, logged it, and added it to the totalGoldEarned shown on the learner's\nprogress screen. Nothing credited it. Only the track certificate was ever\npaid. Across the six seeded tracks that is 120 of 191 gold advertised and\nnever issued — 63 per cent of what a learner is told they earned.\n\nThis makes the advertised number true.\n\nTHE OUTBOX, GENERALISED. The certificate payout already had the right shape:\nthe intent to pay commits in the certificate's own transaction, a drainer\nretries with a stable key until AMS accepts, and FAILED is reserved for a\ndecision a human makes. Module gold needed the same machinery, not a second\ncopy of it.\n\nAcademyGoldPayout gains `kind` (defaulting to \"certificate\", so every row\nwritten before this reads correctly with no backfill) and `attemptId`.\n`trackTitle` becomes `label` through @map, so the column is untouched and the\nfield stops lying about what it holds for a module.\n\ncertId loses @unique. The invariant it expressed — one certificate, one payout\n— is enforced by idempotencyKey, which is @unique and is a deterministic\nfunction of the same id. Keeping it would have forced certId to stay required,\nand a unique index over a column that is null for every module payout collides\non the second one.\n\nTHE KEY FORMAT IS FROZEN. academy-cert-<certId> is on live rows and is what\nAMS dedupes against; changing it would make every historical payout look\nunpaid and pay it again. Module payouts key on academy-module-<attemptId>, and\na test asserts the two cannot collide when a certificate and an attempt happen\nto share an ObjectId.\n\nWHAT THE ATTEMPT NOW DOES. The attempt row and its payout row commit in one\ntransaction, for the reason the certificate's does: an attempt that records\ngold with no durable intent to pay it is the original defect restated. Zero\ngold enqueues nothing, so a failed or repeat attempt does not create a job the\ndrainer retries forever against a cr",
      "refs": {
        "commit": "cdc7386e5ca6814cffea6b9cec4d60a9a09b2296"
      },
      "digest": "262aa796bf7cca265240535df45ee3d7ead77d73f4d7cb6653323f68ae0d3622"
    },
    {
      "id": "ship/flashy-academy/19c708bb4904",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T01:34:56+00:00",
      "kind": "feature",
      "title": "Serve the directory fragment, which this property was not doing",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-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": "19c708bb4904c7eb533e4d32d6544f30ad3ed2cd"
      },
      "digest": "ad593a866be4b7c211e5cb9b984f34785b51dc0da9d58283d6a2db0d87927578"
    },
    {
      "id": "ship/flashy-academy/15d4183ed968",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T00:19:05+00:00",
      "kind": "feature",
      "title": "Serve the charter, which this property was not doing",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The AAO charter lived only at the repository root. A Next.js app does not\nserve the repository root, so https://<this property>/flashyos.roles.json\nreturned 404 while the standard this estate publishes tells every\norganisation to serve exactly that path.\n\nFound by running the estate's own properties through the verifier written\nto mark a stranger's homework. Nine of the ten live properties failed at\nrung 1 — not because a charter was missing, but because nobody could read\nit. gord.holdings was the only one that passed, and only because it is a\nstatic site that happens to serve from the repository root.\n\nThe charter is now copied into the served directory, and the front door\nworkflow diffs the served copy against the source so the two cannot drift.\nA charter that exists and cannot be fetched is worth exactly as much as no\ncharter at all — less, because it produces the belief that the work is\ndone.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "15d4183ed968d612faf79c2cdd8fa2ffed9b9312"
      },
      "digest": "2c2b01fd802bc73baeecc7f33851ae2c45dc17bc3e636724050bb2201baf7bca"
    },
    {
      "id": "ship/flashy-academy/2f748ec9a8fe",
      "repo": "repo/flashy-academy",
      "at": "2026-08-30T00:14:37+00:00",
      "kind": "feature",
      "title": "Publish a front door (frontdoor/1)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "This property now serves /.well-known/frontdoor.json: which lanes it\nopens, what it asks at each, and what it owes in return. It completes the\ntrio the estate already half had — the handshake says who this is, the\ncharter says how it is governed, the door says how to reach it.\n\nLanes are declared per property class rather than per property, so the\nrestraint is checkable: a consumer app opens one lane and it is not\ncapital, and no property outside the parent and the bank opens the capital\nlane at all. frontdoor.config.json is the only file here that carries\nanything specific to this repository.\n\nThe rungs are identical across the estate on purpose. Standing is\nportable — the credential is a charter published at the applicant's own\ndomain, not a row in our store — so an applicant who climbs at one door\nand arrives at another must be owed the same thing. The estate-wide merge\nfails if two properties promise different terms for the same rung.\n\nCarried verbatim in every door: a rung buys a reply and a place in a\nqueue. It never buys authority, money, or access. Publishing a file at a\ndomain proves someone can write to that host and nothing more. Where real\nauthority is needed it is delegated and verified through flashyID. Both\nthe checker and the library reject a door that drops that paragraph,\nbecause a door quietly treated as an authorisation is the one way this\nbecomes a vulnerability rather than a front door.\n\nscripts/check-frontdoor.mjs and scripts/emit-frontdoor.mjs are vendored\nbyte-identical across every repository publishing a door; the canonical\ncopies and the drift test live in @flashyos/frontdoor. Both are\ndependency-free, so CI needs no install and the same two scripts work on a\nNext.js app and a static generator alike.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01BEaXzktRU5ZPe3R2NY7CKD",
      "refs": {
        "commit": "2f748ec9a8fecf40866a1e823d17968f57f7bf26"
      },
      "digest": "6b903875a7349d37efdb20de9810db516eb8457f4e3fb23e088ab3d95d1c2120"
    },
    {
      "id": "ship/flashy-academy/440a67e923c0",
      "repo": "repo/flashy-academy",
      "at": "2026-08-28T19:51:42+00:00",
      "kind": "infra",
      "title": "Make every charter in the estate conform, and gate it",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Ran the estate's own published validator - validateCharterDocument from\n@flashyos/aao - against every charter for the first time. None passed,\nincluding FlashyOS's own production charter and flashy-academy's. Two real\nclasses of failure:\n\n  _comment is not part of aao 0.1. The spec's own extension convention is an\n  x- prefix, and the validator says so in the error. Ten charters carried a\n  bare key the standard does not recognise.\n\n  Four family names were invented: trust, release, inbound, network-effects.\n  The ten declared families are growth, revenue, product, engineering,\n  operations, data, finance, risk, governance, support. Remapped trust to risk\n  (compliance, security, audit), release to engineering, and inbound and\n  network-effects to growth.\n\n10/10 charters now clean against the published validator.\n\nAdds scripts/check-charter.mjs, mirroring the static half of the conformance\nsuite, dependency-free so it runs before an install, vendored byte-identical\nacross the estate. Wired into the Directory workflow ahead of the fragment\ncheck. The published validator stays authoritative; when @flashyos/agent is\navailable, `npx @flashyos/agent conform` supersedes this.\n\nVerified against six failure modes, all caught: a bare non-spec key, an\ninvented family, a codename role, the template placeholder as accountable\nhuman, a capability naming a department rather than an action, and an\nescalation pointing at no declared role.\n\nOne correction along the way: the checker first flagged CRITICAL as an invalid\napproval threshold in flashyos and flashy-ledger. IMPACT_ORDER is LOW, MEDIUM,\nHIGH, CRITICAL - the charters were right and the checker was wrong. Fixed.\n\nmetaverse-group gains the charter it never had: six roles, four families left\ndeliberately empty, and its emitter now reads the charter so the two cannot\ndisagree.\n\n11 fragments, 199 nodes, 188 edges, 100% freshness, zero errors.",
      "refs": {
        "commit": "440a67e923c050cbf3bc743a72a36ba764d78c12"
      },
      "digest": "f5ec190aad9c3eabd48e47a149035d451c6a703273b08962360cd40c2b6bf830"
    },
    {
      "id": "ship/flashy-academy/4e1603424a6d",
      "repo": "repo/flashy-academy",
      "at": "2026-08-28T18:04:22+00:00",
      "kind": "infra",
      "title": "Gate the directory fragment in CI, in the repository that produces it",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The estate-wide merge catches contested authority and dangling references, but\nit runs elsewhere and cannot say which repository caused them. This runs here,\non every push, and fails at the point the mistake is made.\n\nscripts/check-directory.mjs is dependency-free on purpose - a validator that\nneeds an install is a validator that gets skipped. It is vendored byte-identical\ninto every repository in the estate; repository-specific values are passed as\n--external flags rather than edited in, so the copies cannot drift.\n\n.github/workflows/directory.yml runs three steps: emit from the charter, check\nthe fragment, then `git diff --exit-code` on the committed fragment. The third\nis the one that matters - a committed fragment differing from a freshly emitted\none means someone edited the JSON instead of the source it comes from.\n\nVerified against six real failure modes, each caught with the right code:\na claim defined twice, a deleted accountability edge, a reference to a node\nnobody emits, an expiry before its assertion, an ownership edge with no\ninstrument, and hand-reordered nodes.\n\nEleven repositories still merge clean: 193 nodes, 182 edges, 100% freshness.",
      "refs": {
        "commit": "4e1603424a6d5ac0d052fa6f97e6ccaa8dd33661"
      },
      "digest": "d60db61e1735376e068d01c1e529900b58881c285993fff9a6969ef907945e9c"
    },
    {
      "id": "ship/flashy-academy/c133312ce5e0",
      "repo": "repo/flashy-academy",
      "at": "2026-08-28T17:23:51+00:00",
      "kind": "feature",
      "title": "Emit this repository's directory fragment",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Reads flashyos.roles.json and emits the organisation, each declared role as an\nagent, the accountability edge, and the properties this repository operates.\nThe charter and the fragment cannot disagree because the fragment is generated\nfrom the charter.\n\nReferences person/michael rather than defining it - only repo/gord-holdings is\nthe authority for people. Merges clean with the rest of the estate.",
      "refs": {
        "commit": "c133312ce5e0c7cea55aaf471dd299ed79873859"
      },
      "digest": "976fedf8e87ad6382d9aa5bd615c7e22952c0e39d0b15e088d291ed44baf5d5f"
    },
    {
      "id": "ship/flashy-academy/e0631dcb3457",
      "repo": "repo/flashy-academy",
      "at": "2026-08-28T00:29:53+00:00",
      "kind": "feature",
      "title": "Merge the mesh handshake into main",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Keeps main's newer grouped, repo-aware dependabot config over the\nhardening baseline's simpler one; the handshake and its test come across\nunchanged.\n\nCo-Authored-By: Claude <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01VgrPGGUFKMq9zXBHnfcTgs",
      "refs": {
        "commit": "e0631dcb3457da9867e216c799d73407cce429e3"
      },
      "digest": "573baa7da0c9ee102eb9f74ea8dc567e837565ccebadcbd793ec9f7ab041041e"
    },
    {
      "id": "ship/flashy-academy/79d4d87cf84d",
      "repo": "repo/flashy-academy",
      "at": "2026-08-27T22:59:31+00:00",
      "kind": "feature",
      "title": "Merge main; certificate engagement reports carry credentialId as sourceRef",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Main reshaped checkAndIssueCertificate's certificate to\n{ credentialId, trackTitle } for the payout outbox; the engagement\nreport's sourceRef follows it. credentialId is the public, stable\nidentifier, which is exactly what a retryable report should carry.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "79d4d87cf84df015ae0c1c86b5b3892a56c713eb"
      },
      "digest": "b92c73125f790ec3d81caa4265c580f5cb1cb415775253252437a3c5fb3436b2"
    },
    {
      "id": "ship/flashy-academy/55b1138fb812",
      "repo": "repo/flashy-academy",
      "at": "2026-08-26T20:32:54Z",
      "kind": "infra",
      "title": "Phase 3: gate mesh reporting on conformance, and report the live checks",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Reporting to the public directory is now a privilege a charter buys. The\nmesh sync will not run unless the charter passes conformance first — an org\nwhose charter does not parse has no roles, so every agent it reports is an\nagent nobody declared. That is not hypothetical: the first version of the\nbranch sync made every git branch its own agent, and the roster filled with\nbuild logs.\n\nThe gate runs static checks only, on purpose. The live checks read the\npublic directory this workflow is about to write to, so gating on them\nwould make the gate depend on its own output.\n\nThe live checks now run too, as a separate report-only job. They are\ndeliberately not required yet, because today they fail on real\norganizations for reasons no pull request can fix — rosters still carrying\nagents minted before the charter existed, and orgs that have not opted into\na public record at all. A gate that fires on those gets disabled within a\nweek, which is how a gate becomes decoration. It reports until the estate\nis clean and becomes required after. That ordering is the point.",
      "refs": {
        "commit": "55b1138fb8123985bd2bc4564740b01090960c7c"
      },
      "digest": "4b276c2bc11689102ad1f8ad551ba83db82e3362cc976ef8360241fbcca7bb14"
    },
    {
      "id": "ship/flashy-academy/78d2c9dc80ae",
      "repo": "repo/flashy-academy",
      "at": "2026-08-26T20:09:31Z",
      "kind": "feature",
      "title": "Join the FlashyOS mesh: declare a charter and check it in CI",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Phase 2 of the estate rollout. This repository declares the standing roles\nit actually has, names the human accountable for them, and checks the\ncharter against the AAO conformance suite on every pull request.\n\nA role is a standing responsibility that exists whether or not work is in\nflight. A branch is an assignment and lives under its role as\n<role>/<workstream>. Naming both with one string is how a public roster\nends up reading like a git log — fifty-five of the first hundred and two\nagents on the network were branch names, which is the regression this\nordering exists to prevent.\n\nFamilies left empty are left empty. Inventing a role to fill one is the\nroster inflation the standard exists to stop, and an empty family is an\nhonest statement about what this property does not yet do.\n\nCODEOWNERS is the other half. A charter that names an accountable human\nwhile anyone can merge anything is a declaration rather than a control, so\nthe roles and the branch rules have to say the same thing.\n\nVerified with `npx @flashyos/aao <slug>.roles.json` — five static checks\npass, three live checks deferred because they are runtime facts that\ncannot be declared.",
      "refs": {
        "commit": "78d2c9dc80ae00f3cd0923cd7ad58959c039e51c"
      },
      "digest": "125c0687eaef19f8b6c98417f98b50b881720cb148dddabd8357f8e7882dfdc9"
    },
    {
      "id": "ship/flashy-academy/b4ddfd2773e2",
      "repo": "repo/flashy-academy",
      "at": "2026-08-26T18:46:10Z",
      "kind": "feature",
      "title": "Adopt Flashy Brand Standards Rev 01",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The property had no favicon. It now ships src/app/icon.svg — the\nsingle-path bolt in Ember on Ink.\n\nAccent: Ember #FF8A4C. This file has now held three identities — violet,\nthen gold copied verbatim from ClaimYour.Gold, and now Ember — and the\nheader comment records why, because the second decision was made for a\ngood reason that Rev 01 answers differently. Sameness across the group is\ncarried by the neutrals, which are byte-identical everywhere; the accent\nis what tells a visitor which door they came through.\n\nThe --gold-* ramp survives, retuned to the canonical #FFC93C, because this\nproduct genuinely depicts Flashy Gold balances. Gold now appears on a\nreward and Ember on the chrome, which also settles the \"third gold\" the\nold comment flagged as unresolved.\n\nLockup: the header and footer marks were a gold-gradient tile with an \"F\"\nin it, which broke the standards twice — accents are never gradients, and\nno property substitutes a letter for the bolt. Both now use the lockup\nasset: the bolt inside FLASHY, ACADEMY set in Ember beside it.\n\nNeutrals: Ink #08090A and Paper #F5F5F3 throughout, replacing the warm\n30-40 degree greys. Hairlines move to Paper at low alpha so structural\nrules stop spending the accent.\n\nType: Archivo Black for display, Plus Jakarta Sans for body and UI,\nJetBrains Mono for domains, tokens, certificate ids and timestamps,\nreplacing Inter.\n\nNaming: \"Flashy OS\" in prose. Identifiers, env var names and hostnames\nare untouched.",
      "refs": {
        "commit": "b4ddfd2773e2bae1f6c3f0d6a277d7ae3055ec9d"
      },
      "digest": "6d4a37ae82d1e24efae19e27df61449bb25895df36a8459833d5b42a780c69aa"
    },
    {
      "id": "ship/flashy-academy/434aa44d347a",
      "repo": "repo/flashy-academy",
      "at": "2026-08-22T09:13:17-04:00",
      "kind": "infra",
      "title": "Point the ring at flashynetwork.com (#13)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The settlement record's address changed; the edges to it should not go\nstale. Replaces every flashy.network reference with flashynetwork.com —\nmachine surfaces (llms.txt, the entity JSON), cross-property nav entries\nand prose alike.\n\n\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "434aa44d347a6ae00da186ea94cd76e82703cb13",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/13"
      },
      "digest": "dc042990bd4f876ad7aafafb776aa031afd74120fa74674128e700903f19392f"
    },
    {
      "id": "ship/flashy-academy/66b4265159fd",
      "repo": "repo/flashy-academy",
      "at": "2026-08-21T17:02:03Z",
      "kind": "infra",
      "title": "Repoint the settlement record to flashynetwork.com",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Flashy Network is live at flashynetwork.com; flashy.network serves an unrelated\nWordPress site. Every reference here — cross-links, the advertised\nnetwork.json machine surface, and the prose naming the settlement layer — was\npointing at the wrong property.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01KxxGczxBxLF8qfXpcAW3rs",
      "refs": {
        "commit": "66b4265159fdfc4ada99340e19bc6322582dca0c"
      },
      "digest": "a8b2683173f3963c3881677b6bdcca87aef7623b17e8b8fc069cd001f7f49390"
    },
    {
      "id": "ship/flashy-academy/1e84c1bda916",
      "repo": "repo/flashy-academy",
      "at": "2026-08-21T14:16:58+00:00",
      "kind": "feature",
      "title": "Report what the XP was for, so Academy's engagement reports can be retried",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The client's own comment said retries become correct once an idempotency\nkey lands on the AMS route. The key is there now, but Academy should not\nbe the one building it: that would mean shipping the ledger package and\nits registry auth into every product that reports engagement, and two\nproducts deriving 'the same' key slightly differently is the failure the\nconvention exists to prevent.\n\nSo Academy sends sourceRef — the module id, the certificate id — and the\nservice that owns the hunter record derives the canonical key from it. A\nresent report for the same module now collides instead of paying twice.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_01YNESB1KMv7EFEYFFYU5JWY",
      "refs": {
        "commit": "1e84c1bda91677456fd670c94aa503c7cab36a98"
      },
      "digest": "93922f142247033b9961a602610299d3d4ccd9561e85a92b42542a3a1f844a00"
    },
    {
      "id": "ship/flashy-academy/c923542a946c",
      "repo": "repo/flashy-academy",
      "at": "2026-08-20T13:10:39+00:00",
      "kind": "infra",
      "title": "Link the practice lens to the procurement lens, and fix the GDA host",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Placement #9, the last unshipped cross-link from the mesh audit: both\nagent-economy curriculum modules now link to MLG Blockchain's matching\nbuild-lens answers — what an integration costs, and how to do it — so\nthe reader who has just learned to work inside an agent organization can\nreach the page about buying and building one. MLG's side already points\nback at the Academy.\n\nAlso normalizes five www.gda.group links to the bare host GDA itself\ncanonicalizes on, the same defect class as the www.gord.holdings one.",
      "refs": {
        "commit": "c923542a946cf051bab67f09082a35c35012995a"
      },
      "digest": "26a0e2e925a97aed5758c2708d9b6a1d0fb4f689bac9699c6cc020c0b44093ea"
    },
    {
      "id": "ship/flashy-academy/9b27a52f59f8",
      "repo": "repo/flashy-academy",
      "at": "2026-08-19T20:42:34+00:00",
      "kind": "feature",
      "title": "Merge the group-mesh branch: llms.txt host fix, dead-link fixes, slash normalization",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Root-layout metadata conflict resolved in favor of main's version, which\nsupersedes this branch's fix with a fuller one (groupSeo module with\nOrganization, parent, WebSite and DefinedTermSet schemas). Kept from this\nbranch: the gord.holdings host correction in llms.txt, the FAQ links\nrepointed at routes that exist, and flashyos concept links normalized to\ntheir canonical no-slash form.",
      "refs": {
        "commit": "9b27a52f59f8ef8d90a7c6a66f6862baf6a62d33"
      },
      "digest": "9a524d76ddec3aa21f1b8185aa401a83bddf9fa4e910e95d74ac89e25721fb5b"
    },
    {
      "id": "ship/flashy-academy/2119f2d424f5",
      "repo": "repo/flashy-academy",
      "at": "2026-08-19T18:26:04-04:00",
      "kind": "infra",
      "title": "MESH-11: shuffle quiz options behind a signed token, add failure cooldown and explanations (#12)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The quiz served fixed-order questions with unlimited, instant retries,\nand the failure screen named the wrong questions — each attempt leaked a\nslice of the answer key, so a certificate (public credential id, Ed25519\nattestation, employer-facing verify endpoint) could be brute-forced in a\nfew rounds.\n\n- The quiz page issues an HMAC-signed token (module+user bound, 2h) and\n  serves each question's options shuffled by the token's seed. No\n  permutation is stored or sent; submit reproduces it from the token.\n- The submit route requires the token — a bad token is a 403 and never a\n  fallback to the unshuffled order — and scoring maps each submitted\n  index back through the permutation before comparing with correctIdx.\n  Attempt rows store answers in the original index space.\n- Consecutive failures cost a growing cooldown (30s doubling, capped at\n  600s), enforced server-side from the last recorded attempt: 429.\n- AcademyQuestion gains an optional explanation, shown on the failure\n  screen: retries cost time, not learning. The public preview endpoint\n  shuffles with a throwaway seed and issues no token.\n\n\nClaude-Session: https://claude.ai/code/session_019pUgSYP9uuYUPC3BJUmCxo\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "2119f2d424f5378f76f9dbc44780a5802daead24",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/12"
      },
      "digest": "1a2cae28c06fd14602f532fde7d21d6af0b4abdfddb3a82ce6746fe615e8c2bc"
    },
    {
      "id": "ship/flashy-academy/a16e54d36680",
      "repo": "repo/flashy-academy",
      "at": "2026-08-19T18:09:26-04:00",
      "kind": "feature",
      "title": "SHIP-0: add TECHNICAL_ROADMAP.md at canonical v1.1 (#11)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "This repo never received the roadmap file the other two applications\ncarry. Added byte-identical to flashyos's v1.1 (2026-08-18) — one\ncanonical document, no drift.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "a16e54d36680758b007fb52684af1856d2b75962",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/11"
      },
      "digest": "c34c6b4b97e308fc371b795d693fe20d374a3b238c80d1473fead7d64b4cc57c"
    },
    {
      "id": "ship/flashy-academy/56c05d262890",
      "repo": "repo/flashy-academy",
      "at": "2026-08-19T18:02:20-04:00",
      "kind": "feature",
      "title": "Merge pull request #10 from FlashyLabs/claude/seam-4-phase-2",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "SEAM-4 Phase 2: flip the bridge sender to the canonical service pair",
      "refs": {
        "commit": "56c05d262890308002c40d5d0c9d36b6813c9631",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/10"
      },
      "digest": "f82c897e747871113b89a782c0e16fd90d7d5d7d79559a1d73500d7b0ec8c2b0"
    },
    {
      "id": "ship/flashy-academy/7d12d0abd670",
      "repo": "repo/flashy-academy",
      "at": "2026-08-19T16:10:16-04:00",
      "kind": "feature",
      "title": "Merge pull request #9 from FlashyLabs/claude/node-22",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Run on Node 22 — Node 20 is end-of-life",
      "refs": {
        "commit": "7d12d0abd6708fbaf51d6e5a50c28518cbc65cf9",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/9"
      },
      "digest": "2ab954db86b4ad938120b44a26ecae2f1fa15dfcf9b2d56e7c5de981064b8db2"
    },
    {
      "id": "ship/flashy-academy/b5672f59a368",
      "repo": "repo/flashy-academy",
      "at": "2026-08-19T16:08:52-04:00",
      "kind": "feature",
      "title": "Merge pull request #8 from FlashyLabs/claude/seam-4-service-identity",
      "by": [
        "person/michael"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "SEAM-4 Phase 1: one gate for service-to-service calls",
      "refs": {
        "commit": "b5672f59a368911bc900cdb1b738d668662002f9",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/8"
      },
      "digest": "48eb3f55a549b924cce0a5b77d3acf8ff4c884ec3af7986e917a8648000722e7"
    },
    {
      "id": "ship/flashy-academy/097351539ade",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T21:57:53+00:00",
      "kind": "other",
      "title": "LEARN-6: wallet/quest strip on /academy/progress",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Closes the last gap \"Learn, Both Directions\" set out to fix: Academy's\nown progress page showed Academy data in total isolation from the\nwallet and quests a hunter is presumably also using on claimyour.gold.\n\nportalSummaryClient.ts calls flashygoldams' new GET\n/internal/portal/summary (LEARN-5) and the result is threaded through\nthe existing /api/v1/academy/progress route rather than a second fetch\nfrom the page — that route already resolves session.customerId once,\nso this rides the same request instead of adding a round trip.\n\nBest-effort: null on any failure and the strip is simply omitted, same\nnon-fatal contract as hunterEngagementClient. Needs\nFLASHYGOLDAMS_API_URL configured in Secret Manager/Cloud Run env —\nINTERNAL_SERVICE_KEY is already shared between the two services.\n\nThis closes out LEARN-2 through LEARN-6 — \"Learn, Both Directions\" is\nfully implemented on both sides now. Still needed before any of it is\nverified in production: deploy both services with these changes, then\nwalk the six-step acceptance test.",
      "refs": {
        "commit": "097351539ade3415c0557c4013357b800865140b"
      },
      "digest": "711e39842d0d8dedf66642e51f0b3b3d3fe11249484a96c1ee8ae1d7bbf96ffa"
    },
    {
      "id": "ship/flashy-academy/8d7151706eb7",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T21:50:34+00:00",
      "kind": "other",
      "title": "LEARN-4 data source: full track/certificate detail for CYG's /portal/learn",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "New GET /api/v1/internal/academy/learn-detail?customerId=<id>, same\nx-internal-key trust boundary as /internal/academy/summary (LEARN-2).\n\nA separate route rather than adding fields to LEARN-2: that endpoint's\njob is staying a fixed six scalar fields for a dashboard card, and a\nper-track array is a different shape for a different consumer — the\nfull track/certificate picture flashygoldams' /portal/learn page needs,\nnot the dashboard's fast-path summary.\n\nThree lists: completed (from AcademyCertificate, which already carries\ntrackSlug/trackTitle denormalized at issuance — no join needed),\ninProgress (tracks with at least one passed module, not yet completed,\nwith percentComplete), and available (everything else in the active\ncatalogue). Reuses getHunterProgress/listActiveTracks rather than a new\nread path against the same tables.",
      "refs": {
        "commit": "8d7151706eb79ad9a39e2c021412268ba1e8fbda"
      },
      "digest": "1ea13439016c7866bda86c62cd279dafd68e24cfebbf52cd59f11c8a597c131a"
    },
    {
      "id": "ship/flashy-academy/9c63036b5cc1",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T21:44:50+00:00",
      "kind": "feature",
      "title": "LEARN-2: expose a cross-product Academy summary for ClaimYour.Gold",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "New GET /api/v1/internal/academy/summary?customerId=<id>, guarded by the\nsame x-internal-key/INTERNAL_SERVICE_KEY pattern POST\n/internal/hunter-engagement already uses on the other side — a service\ncalling in, not a person.\n\nSix fields (hasActivity, streakDays, civilizationAge, activeTrack,\ncertificatesEarned, totalGoldEarnedFromAcademy), not the whole\nHunterProgress record: shaped by the one dashboard card that's going to\nrender it (LEARN-3, on flashygoldams), not by what happens to exist in\nAcademy's schema. Reuses the existing getHunterProgress/getStreak/\nlistActiveTracks/civilizationAge helpers rather than a second read path\nagainst the same tables.\n\nPart of \"Learn, Both Directions\" — the signed-in claimyour.gold/\nflashy.academy product surfaces currently know nothing about each other\ndespite sharing one identity and one database.",
      "refs": {
        "commit": "9c63036b5cc12d30f016baec7079f77c17bbe956"
      },
      "digest": "c98833be468e904bce63f60a318b4fdfd2a243fa37461a4620656aeb8e6b9883"
    },
    {
      "id": "ship/flashy-academy/17a94501c6ae",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T19:41:40+00:00",
      "kind": "feature",
      "title": "Merge claude/sso-0000-redirect-fix: fix SSO redirect to 0.0.0.0",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "17a94501c6ae9e9dce79bb82049392309bfa4f81"
      },
      "digest": "7dab7b073500ea9fa7bba28decd84e7ba74290d3d99fa425b91260a1e4d74a5b"
    },
    {
      "id": "ship/flashy-academy/e5e79b6e8446",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T18:11:41+00:00",
      "kind": "feature",
      "title": "Merge claude/github-repo-setup-8w9e4m: Academy sign-in round trip",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Brings in the /portal/handoff return leg (loginHref wired into the header,\nprogress page, and quiz), and commits quizIntegrity.ts (not yet wired).",
      "refs": {
        "commit": "e5e79b6e8446ea353edac3e25561b1f15ddf3cce"
      },
      "digest": "8c35301e555fc6d7cecb3d40b18e73686407bf724c31ee9a93a7c3e98cfda470"
    },
    {
      "id": "ship/flashy-academy/dd5c46839e82",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T15:14:21+00:00",
      "kind": "fix",
      "title": "Stop track pages being dead ends: FAQ, breadcrumbs, and links out",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "A track page is the terminal destination of every cluster in the group. GDA\nanswers, FlashyOS concepts and Academy pillars are all meant to route here, and\nuntil now the page linked to its own modules and back to the catalogue and\nnowhere else. Authority arrived and stopped.\n\nFOUR THINGS ADDED, ONE FIXED\n\nFAQ, with FAQPage markup. Academy carried FAQ structured data on comparison\npages, guides and audience landers, and none at all on track pages -- the page\nwhere someone decides to enrol, and the page a model must read to be able to\nrecommend the track. Four questions, built from the track's own data so they\ncite real numbers and cannot go stale when a module is added: what it covers,\nwhat it costs, what it pays, whether the certificate is verifiable. These are\nalso the enrolment copy, so the retrieval work and the conversion work are the\nsame work.\n\nSideways links to sibling tracks in the same pillar. This is what makes a\npillar a cluster rather than a folder.\n\nUpward links to the definition and the institution behind it -- deliberately\nsparse. Six of the nine tracks get none, because no concept or answer page\ncurrently defines what they teach, and inventing a link for them is exactly how\na citation mesh becomes a link scheme. The empty sections are the content\nbacklog, stated by their absence rather than papered over.\n\nBreadcrumbList, which the page implied visually and declared nowhere. A page\nthree levels deep with no declared ancestry reads to a crawler as a top-level\npage that happens to have a long URL.\n\nAnd the Course schema's url said /academy/tracks/{slug} while generateMetadata\ndeclared the canonical as /tracks/{slug} -- the structured data and the\ncanonical tag naming two different addresses for one page. It also minted its\nown Organization with a `sameAs` pointing at flashy.academy, asserting that\nflashy.academy is a reference page identifying Flashy Academy, which says\nnothing. Both now reference the canonical nodes by @id.\n\nsrc/lib/trackMesh.ts holds ",
      "refs": {
        "commit": "dd5c46839e82cee8035f992eda7382a71aa74790"
      },
      "digest": "c78ac3a68a3416933d143643617b0f4f668234ba2c590fdb87f645c37df1f3e8"
    },
    {
      "id": "ship/flashy-academy/02af544b2a0d",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T14:54:44+00:00",
      "kind": "infra",
      "title": "Rank for both spellings, using the construct that actually expresses synonymy",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "sameAs is the wrong tool for this too. It links a thing to other pages that\nidentify the same entity -- a Wikipedia article, a company profile -- and has\nnothing to say about two names for one concept. Using it that way would assert\nsomething false a second time, in a different field.\n\nThe right construct is DefinedTerm inside a DefinedTermSet, with alternateName\ncarrying the synonyms. That is precisely what it is for: this concept has a\ncanonical name and these other names refer to it. Retrieval systems read\nalternateName as a synonym relation, which is what makes a query for either\nstring resolve to the same definition instead of to two competing ones.\n\nThree terms are declared, each with its aliases:\n\n  Agentic Autonomous Organization <- AI Autonomous Organization, AAO,\n                                     Agentic Autonomous Organisation\n  Agentic economy                 <- agent economy, AI agent economy\n  RWA Rewards                     <- real-world asset rewards,\n                                     real-world value rewards\n\nTHE HALF MARKUP CANNOT DO\n\nStructured data describes a page; it does not create relevance the page does\nnot have. Nothing here ranks for \"AI Autonomous Organization\" unless that exact\nstring also appears in visible prose on a page that defines the concept. The\nmarkup makes the relationship explicit; the sentence is what gets indexed.\n\nSo the Academy home page now says both in the open -- \"an Agentic Autonomous\nOrganization (AAO), also called an AI Autonomous Organization\" -- with the\none-line definition attached. The canonical version of that sentence belongs on\nflashyos.com, which owns the category; this is the same treatment applied where\nthe vocabulary already lives.\n\nVerified: lint 0, tsc 0, 121 tests, and the built output emits four JSON-LD\nnodes -- Organization, parent Organization with 6 subOrganizations, WebSite,\nand the DefinedTermSet with all three terms and their aliases.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nC",
      "refs": {
        "commit": "02af544b2a0da4bf5f26df47a3f55053e4d2d75b"
      },
      "digest": "47048e83ff8984ff7c8f80c986bd548de444e5955c60adb7080de7b109c3a927"
    },
    {
      "id": "ship/flashy-academy/747172c6f5b4",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T14:44:15+00:00",
      "kind": "other",
      "title": "Model the group as a parent and its brands, not as nine identical entities",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "THREE CORRECTIONS, AND THE FIRST IS TO MY OWN WORK\n\n1. sameAs was the wrong predicate.\n\nIn schema.org, sameAs means \"a reference page that unambiguously indicates the\nitem's identity\" -- a Wikipedia entry, a company profile, a social account.\nListing sibling domains there asserted that flashy.academy IS flashy.gold. That\nis false, and it is a claim a crawler disproves by fetching either one.\n\nThe real relationship is a hierarchy: flashygroup.com is the parent company and\nevery other property is a brand beneath it. schema.org says that with\nparentOrganization from the child and subOrganization from the parent, and that\npair is what search engines use to build a brand entity graph. It is also the\nstronger signal, because it says something specific and true rather than\nsomething sweeping and wrong.\n\nEvery property now declares its parent by @id, and the parent node -- emitted\nfrom each property with the same @id -- enumerates the brands. A crawler\nmerging those fragments gets one company with nine brands instead of nine\ncompanies claiming to be each other.\n\nGDA Group stays modelled as funder. It is the capital partner, not a Flashy\nproperty, and folding an investor into the brand list would misdescribe the\nrelationship to exactly the machines this exists to inform.\n\n2. FLASHY_ECOSYSTEM omitted the product.\n\nSix entries, missing ClaimYour.Gold -- the wallet, the ledger and the game, the\nlargest property in the estate -- plus Flashy Network, Flashy Fun and Flashy\nMind. Survivable while it drove only a footer strip; not survivable once it\nbecame the source for the entity graph and academy.json.\n\nReconciled against flashy-group's PROPERTIES registry, which is authoritative\nand carries a status per property. Status is now on the record rather than\nfiltered at the source, so each consumer can be honest in its own way: the\nfooter and the subOrganization graph carry LIVE only, because a link and a\nmembership claim are both assertions a machine goes and checks; academy.json\nlis",
      "refs": {
        "commit": "747172c6f5b4e0d5742bffbadaa1d1dae0f8d4ff"
      },
      "digest": "e8ef1d76562144866d60ad8f477ea6e9ac49281906aad8c96ed43d7db7315f93"
    },
    {
      "id": "ship/flashy-academy/cc150f650b37",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T14:21:55+00:00",
      "kind": "spec",
      "title": "Define the 139 CSS variables the ported pages use, and stop a 401 blanking the page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "WHY THE SITE DID NOT LOOK LIKE IT USED TO\n\nA sweep of every var(--x) used in src/ against every --x defined in\nglobals.css found eleven tokens used and never defined, across 139 uses in 44\nfiles. The gold ramp is most of it: 87 uses of var(--gold), 27 of\nvar(--gold-hi), 13 of var(--gold-deep), 2 of var(--gold-mid). Then --bg,\n--bg-2, --bg-elevated, --ink, --ink-dim, --ink-faint, --glass-border,\n--danger-urgency, --text-body and --text-section for the remaining 47.\n\nPages ported from FlashyGoldAMS carry its class names; the variables behind\nthem did not come across. An undefined custom property is not an error -- the\ndeclaration is invalid at computed-value time, so it is dropped and the\nelement inherits. Nothing reports it, in the browser or the build. Track\ncards drew no border, gold figures rendered as body text, secondary text\nstopped being secondary, and elevated surfaces had no background.\n\nThis was the larger half of the visual regression, well beyond the accent\nhue. Values are AMS's so a page renders identically on either host.\n\nQUIZ SUBMISSION DESTROYED THE PAGE ON ANY ERROR\n\napiError() returns `error` as an object -- { message, httpStatus, code } --\nand QuizClient read it as a string: setError(json.error ?? '...'). setError is\ntyped string | null, but res.json() is any, so nothing objected at compile\ntime. At runtime the object reached {error} in the JSX, React refused to\nrender it, and the error boundary replaced the whole page with \"This page\ncouldn't load\".\n\nThe most common failure is the one that triggered it in production: POST 401,\nbecause there was nowhere on flashy.academy to sign in. So a signed-out\nvisitor finishing a quiz lost the page rather than being told to sign in.\n401 now says so and offers the reason; other failures read the message field.\n\n/quiz/null appears four times in the logs. Both articleSlug and quizSlug are\nnon-nullable in the schema and neither link site can produce it, so it is not\ndiagnosed here rather than guessed at.\n\nVerifie",
      "refs": {
        "commit": "cc150f650b3735e8a2fc909ba5fd6b0b1674c8c8"
      },
      "digest": "3515666503b738e459dc8891f5588ef5e0e20d50e2f9347b4bcfb60ae2a6bac1"
    },
    {
      "id": "ship/flashy-academy/2c023a9a1bb9",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T14:15:58+00:00",
      "kind": "infra",
      "title": "Put Academy on the group's SEO convention, and declare the ring and the clusters",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The rest of the group already had a convention and Academy was the one\nproperty not following it. flashy-group serves /group.json and /llms.txt from\nthe app root; flashy-gold serves /gold.json; flashy-network serves\n/network.json. Each carries a machine_surfaces block naming its own three.\n\nAcademy served no entity descriptor at all, and its llms.txt sat at\n/academy/llms.txt -- resolving only because the hostname rewrite happened to\ncatch it, and carrying the same /academy prefix bug as the sitemap: every URL\ninside pointed at an address whose page canonicalises elsewhere, so a model\nthat followed one landed somewhere that disagreed about its own name.\n\nTHE RING is horizontal -- six domains that are one company. Nothing states\nthat unless every property states it, in a machine-readable form, and states\nthe same thing. It is now declared three ways from one array: sameAs on the\nOrganization schema, the footer's visible links, and the ring block in\n/academy.json. All three are folds over FLASHY_ECOSYSTEM, so they are\nconsistent by construction rather than by remembering.\n\nTHE CLUSTER is vertical and is this property's own shape: six pillars, each\nwith tracks, each with quiz-verified modules. The hierarchy existed in\nACADEMY_PROGRAMS and was declared nowhere -- a crawler saw sixty sibling pages\nwith no parent and no topical grouping. pillarClusterSchema states pillar ->\ntrack as CollectionPage -> hasPart -> Course, which is the mechanism by which\nauthority accumulates on the hub instead of scattering across its depth.\nbreadcrumbSchema does the same for ancestry, which the site emitted nowhere.\n\nAlso: the root layout's metadata was a bare title with no description, no\nOpen Graph and no metadataBase. Without metadataBase, relative OG image paths\nanywhere in the app resolve against nothing and are dropped silently.\n\nThe Organization and WebSite nodes are separate with stable @ids so other\nproperties in the ring can reference this exact entity rather than describing\na simi",
      "refs": {
        "commit": "2c023a9a1bb9dacbf6fcd5ccfbe4ed7604a37a71"
      },
      "digest": "61052635b9956626e0533472468a86691872abe2232300799b4632f1165acca1"
    },
    {
      "id": "ship/flashy-academy/7f6b88a27d29",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T14:11:41+00:00",
      "kind": "feature",
      "title": "Give flashy.academy a header, a footer, one gold, and a way to be crawled",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The extraction left this site with no chrome at all. The monolith's Academy\nlayout rendered a shared GlobalHeader and its root layout a GlobalFooter;\nneither came across. Since the domain moved, all 62 pages have been served\nwith no navigation, no footer and nowhere to sign in -- reachable only by\ntyping the URL.\n\nCHROME\n\nNav data is shared: academyNav.ts is ported verbatim, pure data and pure\nfunctions, already written to resolve URLs correctly on both hosts. The chrome\nis Academy's own rather than a port of global-header.tsx, which is 808 lines\nand imports NotificationBell, HunterInboxBell, AnimatedGoldBalance and the\ncampaign registry -- portal machinery backed by APIs this service does not own.\nCopying it would drag the coupling the extraction just removed back across the\nboundary, to render a bell with nothing to ring. The two headers now agree on\nwhat exists because they read the same list, not because one is a copy.\n\nSign in points at claimyour.gold/portal/login, where the monolith's own header\npointed. Academy has no login of its own: customers authenticate with Telegram\nand the widget is domain-bound in BotFather. Session state is read in the\nserver layout rather than fetched in the header, so the button does not flicker\nbetween signed-out and signed-in on every page load.\n\nCOLOUR\n\nglobals.css defined a violet identity (hue ~255) on the documented reasoning\nthat a credentialing product should not borrow the game's rank-metal branding.\nReversed deliberately: this is one property in a group sharing a wallet, a\nsession and a hunter record, and a visitor crossing from claimyour.gold should\nnot experience a different company. The values are ClaimYour.Gold's verbatim,\nso the two are the same colour rather than two that merely look similar, and\nthe neutrals move to a warm bias because a violet-tinted grey under a gold\naccent reads as an accident.\n\nNoted in the file: flashy.gold defines a third gold (#d4a94e). Two golds in one\ngroup is one too many, but that proper",
      "refs": {
        "commit": "7f6b88a27d29fe9c042216cec8d535523b36a7fe"
      },
      "digest": "6faab8bd1d64565b6dbe6d2528ee0d2c86cd53e5a636d162fb86abe255006456"
    },
    {
      "id": "ship/flashy-academy/aed26ce6e7b3",
      "repo": "repo/flashy-academy",
      "at": "2026-08-18T14:00:22+00:00",
      "kind": "feature",
      "title": "Merge the Academy gate, host rewrite, SSO route, XP writer fix and lint gate",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "This branch has been serving flashy.academy in production since the domain\nmoved; main never had it. Merging so the deployed line and the default\nbranch are the same thing again.\n\nOne conflict, in src/app/academy/page.tsx: main added the AI-agents\ncurriculum import, the branch added the pillar-page and home-stats imports.\nBoth are used further down the file. Kept both.",
      "refs": {
        "commit": "aed26ce6e7b3c373b1feb55f86974567847bc360"
      },
      "digest": "10d13743e2fc78b53a8dc9f5db0db0a8ef4019266ca66be4a604bdae87bc81c2"
    },
    {
      "id": "ship/flashy-academy/b7296e21b52f",
      "repo": "repo/flashy-academy",
      "at": "2026-08-13T04:11:48+00:00",
      "kind": "feature",
      "title": "Add the Working With AI Agents curriculum",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Two free tracks teaching the group's own operating experience: Working\nInside an AI Organization (primitive 01, structure) and Directing Agents\nWell (primitive 07, performance). File-based rather than DB-backed — these\nare syllabus pages that render at build time, distinct from the Flashy Gold\nquiz tracks in academyService.\n\nEach lesson cites the property that owns the underlying claim. Linked from\nthe Academy home and listed in llms.txt under the shared eight-primitive\ntaxonomy, which this commit also adds.\n\nCo-Authored-By: Claude Opus 5 <noreply@anthropic.com>\nClaude-Session: https://claude.ai/code/session_0198vyysGCrfdioK9uQr3kbs",
      "refs": {
        "commit": "b7296e21b52fc79fc1195ca141d2c642cbd0740b"
      },
      "digest": "e9605718f60c6c9ccd0b473922cb9d5fc2880abb00e882f672edd01f3ef78a25"
    },
    {
      "id": "ship/flashy-academy/2bd8ea196892",
      "repo": "repo/flashy-academy",
      "at": "2026-08-11T16:51:04+00:00",
      "kind": "infra",
      "title": "Point the principal line at the live canonical record",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "2bd8ea196892c4b3f20f78c0bd32b71f35593b64"
      },
      "digest": "482b70cd68e6a29141a63fd72331ddb843ac63180269b42c550cbc6af45ff0b3"
    },
    {
      "id": "ship/flashy-academy/1137b92a0b57",
      "repo": "repo/flashy-academy",
      "at": "2026-08-11T16:42:17+00:00",
      "kind": "feature",
      "title": "Add llms.txt with the group ring block per the Group Surface Spec",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "refs": {
        "commit": "1137b92a0b5736cc02ff32365f033effa9d23d47"
      },
      "digest": "bd2d38cc31c7c05ea700155fad0a834c95a2d2f3af384a2f2a1145dde35866f4"
    },
    {
      "id": "ship/flashy-academy/9d514b39e24c",
      "repo": "repo/flashy-academy",
      "at": "2026-07-17T14:17:18+00:00",
      "kind": "infra",
      "title": "flashyos-branch-mesh-sync: exit 1 when every branch fails to sync",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Same fix as FlashyGoldAMS/flashyos — an all-branches-401 run reported\ngreen 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": "9d514b39e24cff90f425bf74e00fad5d1e114f12"
      },
      "digest": "6aafb6e47f997f391d6a8508c3604d1f85395114ddb90105041b69fdd6fcc5d0"
    },
    {
      "id": "ship/flashy-academy/cb12a928d9ac",
      "repo": "repo/flashy-academy",
      "at": "2026-07-14T19:52:14+02:00",
      "kind": "infra",
      "title": "Replace role-less portal-session gate with admin key on admin/academy routes (#5)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Mirrors the fix shipped in FlashyGoldAMS: 34 /api/v1/admin/academy/*\nroutes were gated either on getPortalSession alone -- a session shape\nshared with every regular customer login, carrying no role field -- or,\nin blog/route.ts, an OR-logic check that let any customer session\nthrough when the x-admin-key header was simply omitted. Any authenticated\ncustomer could reach payment intents, contracts/ROI reports, lead\nscores, funnel/cohort analytics, and webhook config.\n\nIntroduces requireAdminKey() (src/lib/adminKeyAuth.ts), reusing the\nx-admin-key/ADMIN_KEY shared-secret convention already correct on\njob-economy/route.ts and the cron routes, and swaps all 34 routes over\nto it with matching 403/2xx test coverage.\n\n\nClaude-Session: https://claude.ai/code/session_014iB7pEbPRZdFMXMHm8421u\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "cb12a928d9ac585eb102bbdf7f267d065d49dcda",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/5"
      },
      "digest": "03bd2157f5f9fb3ef079ac7b8572c23d27addaa14d6340e48859de0039bfa5fb"
    },
    {
      "id": "ship/flashy-academy/4f5b3a6dd1ac",
      "repo": "repo/flashy-academy",
      "at": "2026-07-14T14:26:03+00:00",
      "kind": "feature",
      "title": "Send the new FlashyOS agent-bootstrap-key header when minting CI tokens",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "flashyos locked down POST /orgs/:orgId/agents to require either a\nsession+OWNER/ADMIN or a bootstrap key -- this repo's branch-mesh-sync\nmints with no human session, so it needs the new\nx-agent-bootstrap-key header or minting will start failing (harmlessly,\neach branch's mint is try-caught individually, but silently).",
      "refs": {
        "commit": "4f5b3a6dd1ace11a5e26e861d48b361c25eac87f"
      },
      "digest": "b649dac8e83f73aae014b7bf663a66984ae147bc3575c6135e5fb8885887bd2d"
    },
    {
      "id": "ship/flashy-academy/388dfaf46489",
      "repo": "repo/flashy-academy",
      "at": "2026-07-11T03:15:13+02:00",
      "kind": "infra",
      "title": "Sync FLASHY_GROUP_ROADMAP.md to the exact canonical text (#3)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "No content change — matches the markdown formatting of the version\nalready committed in FlashyGoldAMS byte-for-byte.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "388dfaf46489345e074ed2c7c1a20a83814197cf",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/3"
      },
      "digest": "c181d522733755e2bb4e25bb85543bcd55739dc7f68052b48d2b614679c56d4e"
    },
    {
      "id": "ship/flashy-academy/73506667c1bb",
      "repo": "repo/flashy-academy",
      "at": "2026-07-11T03:14:12+02:00",
      "kind": "infra",
      "title": "Rename VISION.md to FLASHY_GROUP_ROADMAP.md for consistency with FlashyGoldAMS (#2)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Same document, no content change — matching the filename already\nestablished in FlashyGoldAMS.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "73506667c1bbbb56d8d6847e35e8c340a9a72ea9",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/2"
      },
      "digest": "2fadeab15e1b27a462a9feac84a3c7a10ef2ea3b5a3df54e4fad9238e3d80d7b"
    },
    {
      "id": "ship/flashy-academy/b065bb8c0e08",
      "repo": "repo/flashy-academy",
      "at": "2026-07-11T03:12:27+02:00",
      "kind": "feature",
      "title": "Add FLASHY GROUP unified vision, state of the union, and roadmap (#1)",
      "by": [
        "person/michael",
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Group-wide document produced from a full audit of flashyos, flashy-academy,\nand FlashyGoldAMS on 2026-07-10. Committed to the root of all three repos\nper its own header.\n\nCo-authored-by: Claude <noreply@anthropic.com>",
      "refs": {
        "commit": "b065bb8c0e082174c08695baada10fced0d023c6",
        "pr": "https://github.com/FlashyLabs/flashy-academy/pull/1"
      },
      "digest": "efe710364ae985805da1e9a38ca83bc3944f8763d08d5ca29e06e88698ef0ed6"
    },
    {
      "id": "ship/flashy-academy/ae2aec361808",
      "repo": "repo/flashy-academy",
      "at": "2026-07-10T19:38:47+00:00",
      "kind": "feature",
      "title": "Add persistent per-branch FlashyOS agent tiles (branch mesh sync)",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Scheduled job (every 30 min) enumerates every branch in this repo via\nthe GitHub API and reports each as its own FlashyOS agent tile under\nthe Flashy.Academy org — status/task derived from that branch's\nlatest commit recency.",
      "refs": {
        "commit": "ae2aec3618086009deb565b02ddd5d58912aa071"
      },
      "digest": "43875097413f70df240c48fe86f30354a831e5ac8e4e6069fa3b111247247611"
    },
    {
      "id": "ship/flashy-academy/7ae0c37dfabd",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T16:46:19+00:00",
      "kind": "other",
      "title": "Phase A2.5 batch 2: 13 more pages moved",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "badge, badge/[token], compare/[slug], embed/verify-frame, employers,\nemployers/[domain], employers/roi, guides/[slug],\nnewsletter/unsubscribe/[token], r/[code], resources,\ntools/salary-benchmark, tools/readiness-check — plus their backing\nservices (academyBadgeService, academyComparisonPages.ts,\nacademyEmployerTestimonialService). Everything else reused services\nalready moved in earlier batches (FAQ, pillar-page, gated-asset,\nnewsletter).\n\n26 of 60 pages now moved. Typecheck, next build, and tests all clean.",
      "refs": {
        "commit": "7ae0c37dfabdd782606849c21433d499b1926d27"
      },
      "digest": "d14187df99d1fcb3b2b75d8c069010ff0d3e42b79e84e75e4d787767498d28e9"
    },
    {
      "id": "ship/flashy-academy/730cd12f662a",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T16:35:41+00:00",
      "kind": "fix",
      "title": "Resolve the cross-domain auth gap by reusing FlashyGoldAMS's existing portal-bridge mechanism",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Checked FlashyGoldAMS's codebase before building anything and found it\nalready has POST /api/v1/academy/portal-bridge/token +\nPOST /api/v1/public/academy/portal-bridge/verify\n(academyPortalBridgeService.ts) — built for exactly this handoff,\nunused by this repo until now. Reused it instead of inventing a\nparallel mechanism.\n\nNew: src/lib/flashyGoldAmsClient.ts (calls the existing verify\nendpoint, lazy env reads), POST /api/v1/portal-bridge/exchange (takes\na bridge token, verifies it, mints a local portalSessionToken and sets\nit as this app's own cookie), POST /api/v1/academy/quiz/[slug]/submit\n(a server-side proxy — the client can't read this app's HttpOnly\ncookie to forward it itself, so the cross-domain forwarding happens\nserver-side where the cookie is readable, then relays to\nFlashyGoldAMS's real submit endpoint as a Bearer token).\nQuizClient.tsx now calls this local proxy, replacing an earlier\nversion that tried a client-side cross-origin fetch with\ncredentials: 'include' — correctly identified as unworkable (HttpOnly\ncookies aren't sent cross-domain regardless) and replaced.\n\nThe one FlashyGoldAMS-side change this required: getPortalSession()\nnow also accepts a Bearer token as a fallback when no cookie is\npresent — same HMAC verification either way, business logic\nuntouched. 4 new tests there, full 10,033-test suite still green.\n\nVerified the core cryptographic claim for real, not assumed: a\nstandalone script confirms a token minted by this repo's\ncreatePortalSessionToken is genuinely valid against FlashyGoldAMS's\nverification algorithm (both sign with the same NEXTAUTH_SECRET), and\ncorrectly rejected under a different secret.\n\n11/11 tests passing here (added a vitest.setup.ts so NEXTAUTH_SECRET\ndoesn't need to be passed inline). Typecheck and next build clean.\n\nOperational requirement documented in .env.example: both apps'\nNEXTAUTH_SECRET and PORTAL_BRIDGE_KEY must match exactly in production.",
      "refs": {
        "commit": "730cd12f662abebced61c2956d01bbaf0d085650"
      },
      "digest": "689785c9991a4c1fcb230d4dd7052e3eb3be4ab236baab5f366830fbb0d96b3f"
    },
    {
      "id": "ship/flashy-academy/61c41904069b",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T16:20:30+00:00",
      "kind": "fix",
      "title": "Resolve both domain-cutover blockers: real design system + the quiz page",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Design system (decided, not left open): Flashy Academy gets its own\nvisual identity — a real Tailwind v4 setup (postcss.config.mjs,\nglobals.css, layout.tsx wired to Inter) using the same token names\nFlashyGoldAMS's pages already use (--primary, --foreground,\n--muted-foreground, --border, --card, same @theme inline mechanism)\nbut a distinct violet/indigo accent instead of gold's amber, on its\nown ground. Every already-moved page needed zero class changes — only\nthe color values differ. Verified by inspecting the compiled CSS\noutput, not assumed.\n\nQuiz page: moved academy/quiz/[slug]/page.tsx + QuizClient.tsx. The\ndata fetch was already portable (academyService.ts barrel, Phase A3).\nprogress/page.tsx correctly NOT moved — same civilizationAgeConfig/\nicon-system coupling Phase A3 already found. Submission deliberately\nstill calls FlashyGoldAMS's own API rather than re-implementing the\nwars/streaks/referrals logic Phase A3 decided stays there.\n\nDocumented as a known gap, not silently worked around: FlashyGoldAMS's\nlearner session cookie is scoped to its own domain and won't be sent\ncross-domain to a flashy.academy-served page's fetch — credentials:\n'include' doesn't fix that. Real cross-domain auth (a bearer token,\nnot a shared cookie) is the actual remaining piece before quiz\nsubmission works end-to-end from the real domain, flagged concretely\nin code and in the migration plan rather than hidden inside a fetch\ncall that looks done but isn't.\n\n13 of 60 pages now moved. Typecheck, next build, and tests all clean.",
      "refs": {
        "commit": "61c41904069b023ee41057ff53849528295a646e"
      },
      "digest": "c438db7fadada499fefac9e5d6d1c50affa89a121e263783143df8f81ead645e"
    },
    {
      "id": "ship/flashy-academy/61b7445d3b35",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T15:59:39+00:00",
      "kind": "feature",
      "title": "Phase A2.5: start moving actual pages, not just API routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "The real gap flagged last session: flashy.academy is a live domain\ntoday, served entirely by FlashyGoldAMS's page tree via a hostname\nrewrite — API routes alone give this repo nothing to actually serve\nthere. Started moving pages using the same inventory-first,\nattempt-and-verify method as every API phase.\n\nMoved 12 of 60 pages: /academy (root), alumni, catalogue, cert-wall,\ncpd, faq, graduates, impact, partner, press, pricing, upgrade — plus\ntheir backing services/libs (academyFaq.ts, academyPressStats.ts,\nacademyPlanService.ts, academyCertWallService.ts,\nAcademyReferralCapture.tsx) and a real gap fill: the public impact API\nroute + academyImpactService had been missed in Phase A2, added now.\n\nTwo real infra fixes, same lesson as the earlier bullmq/ioredis\nversion pinning: this repo was scaffolded on Next 15 + React 18, but\nFlashyGoldAMS actually runs Next 16.2.6 + React 19.2.4 — upgraded to\nmatch exactly, since ported UI code needs the source's actual runtime,\nnot just a recent-enough one. Also added the missing DOM.Iterable lib\ntarget that FlashyGoldAMS's own tsconfig has always had.\n\nFound and correctly held back rather than silently fixed: a genuine\npre-existing FlashyGoldAMS bug in academy/teams/page.tsx (raw async\nonSubmit in a Server Component, confirmed by next build actually\nfailing on it) — not a migration decision to make unilaterally.\n\nDocumented honestly rather than guessed: no Tailwind config exists\nhere yet, so these 12 pages are structurally/functionally correct but\ncompletely unstyled. Whether Academy inherits ClaimYourGold's full\n2,586-line design system verbatim or gets its own visual identity is a\nreal product decision, flagged for one rather than assumed.\n\nTypecheck, next build (12 pages + 83 routes, all clean), and tests\nall pass.",
      "refs": {
        "commit": "61b7445d3b35e28eee79b73ef1948257db98d047"
      },
      "digest": "e3307d9f51162722d46c2e9f8fcf7af8fe64831acad969f000bbfbfbf3ebe11a"
    },
    {
      "id": "ship/flashy-academy/4d7a11476207",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T15:48:31+00:00",
      "kind": "docs",
      "title": "Document the real domain cutover mechanism + rebase onto main",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Real finding from inspecting FlashyGoldAMS's src/middleware.ts\ndirectly: flashy.academy is already a live production domain today,\nserved entirely by FlashyGoldAMS via a hostname rewrite to its\n/academy/* page tree — not by this repo. Phase A6's actual cutover\nstep is repointing that domain and removing the rewrite, not just\ndeleting old files, and it can't happen before this repo has its own\nequivalent of the /academy/* pages, which the plan hadn't scoped yet\n(API routes and services only, so far).\n\nAlso documents working alongside FlashyGoldAMS's other active\nbranches: rebased claude/multi-agent-workspace-view-84svas onto\norigin/main (9 commits behind, several real Academy features landed\nvia sage/inbound-pipeline and sage/inbound-qualified-leads, both\nalready merged) — clean rebase, Prisma client regenerated, full\n10,029-test suite still green, pushed. Establishes rebase-before-each-\nextraction-session as the norm so services get copied from\nFlashyGoldAMS's current state, not a stale snapshot.",
      "refs": {
        "commit": "4d7a114762078329178ba960405cb654b497715f"
      },
      "digest": "ddf26a26dbdfd86704b1f345f2ee4827f7c2e6cbe2ac98a98af45473dbeb9be3"
    },
    {
      "id": "ship/flashy-academy/158e2aaedf2b",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T15:39:15+00:00",
      "kind": "other",
      "title": "Phase A4 batch 4: 13 of 16 cron/academy routes, plus a real dependency-version fix",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Moved churn-intervention, contract-renewal, employer-score,\nevent-reminders, expire-trials, lead-routing, leaderboard-refresh,\nmentor-match, milestone-check, newsletter-send, re-engagement,\ntrial-drip, weekly-digest and their backing services.\n\nReverted abandoned-enrollment and the two BullMQ job files\n(academyGoldBalanceNudgeJob, academyStreakRecoveryJob) — all three\nread customer or wallet directly, core-game/money models.\n\nFound and fixed a real dependency-version issue: academyDripService's\nbullmq Queue producer bundles its own ioredis, and semver-range\ninstalls here resolved to different patch versions than\nFlashyGoldAMS's exact ones, which TypeScript correctly rejected as\nincompatible client types. Pinned bullmq and ioredis to\nFlashyGoldAMS's exact versions (no ^ range) rather than letting them\ndrift independently — this app's queue producer feeds FlashyGoldAMS's\nstill-in-place academyDripWorker.ts, so the versions genuinely have to\nmatch, not just semver-satisfy.\n\n83 of ~105 total routes now moved. Typecheck, next build, and tests\nall clean.",
      "refs": {
        "commit": "158e2aaedf2b72928e18dc6f8e032db6d2eb7426"
      },
      "digest": "85129361d25cca76c0f8f38703a5f5b97aef8cadfb9686adc3df4efeb6b01e16"
    },
    {
      "id": "ship/flashy-academy/78da4394280c",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T15:34:29+00:00",
      "kind": "other",
      "title": "Phase A4 batch 3: 22 more admin/academy routes moved",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Large batch attempted together (25 routes), 3 reverted after tsc\ncaught real cross-cutting model dependencies:\n\nMoved: cohort-analytics, cohort-retention, churn, conversion-funnel,\ndashboard (+ its dependency chain — academyIntelligenceService and\neverything it calls, all confirmed self-contained first), domain-verify\n(both routes), funnel-report, job-economy, lead-magnet-stats,\nlead-routing/stats, lead-score-distribution, lead-scores, team-domains,\nteam-inquiries/[id] (both routes), contracts (all 4 routes),\naffiliate-attribution, affiliates, payment-intents, seasons/[slug]/close,\ntracks/[slug]/activate-waitlist.\n\nAdded @paralleldrive/cuid2 as an explicit direct dependency (needed by\nacademyAffiliateService) — it was only a transitive dependency in\nFlashyGoldAMS's own package.json, not something to silently rely on\nhere too.\n\nReverted: featured-hunters, team-dashboard (both read a shared customer\nmodel), inbound-dashboard (reads clientGoldTransaction and quest, both\ncore-game models). All three sound Academy-specific but aren't —\nsame lesson as academyPublicProfileService/academyCertShareService.\n\n37 of ~45 admin routes and 33 of ~60 public routes now moved (70\ntotal). Typecheck, next build, and tests all clean.",
      "refs": {
        "commit": "78da4394280c795bf54b97be1a4c432afece5d36"
      },
      "digest": "5fb58a6c1faa9216de9b2b3d5f4d4a196ebc494bef19cb006ba3f92405f66782"
    },
    {
      "id": "ship/flashy-academy/17f7d502d108",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T15:15:30+00:00",
      "kind": "other",
      "title": "Phase A4 batch 1+2: 12 admin/academy routes moved",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Batch 1 (content management, on already-moved services): faqs,\ncase-studies, blog, events, gated-assets, pillar-pages,\ntestimonials/[id]. Ports src/lib/portalSession.ts (HMAC-signed session\ncookie, self-contained) and a trimmed src/lib/config.ts — only\nauth.secret, not FlashyGoldAMS's full config surface.\n\nBatch 2: waitlist, webhooks, experiments, employer-intent,\ntrack-demand (services: academyExperimentService,\nacademyEmployerIntentService, academyTrackDemandService,\nacademyWebhookService, academyWebhookEventService).\n\njob-poster-fraud-flags attempted and reverted: reads a shared\nclientGoldTransaction model. job-listings* routes scoped out without\nattempting — their service pulls in a BullMQ queue and a real\nmoney-movement service, deliberately deferred rather than copied\ncarelessly.\n\n12 of ~45 admin routes moved. Typecheck, next build, and tests clean.",
      "refs": {
        "commit": "17f7d502d108bffb1782e1b3da0c1f457be11c06"
      },
      "digest": "bde0da38f280dd46e17bc90c6cff17bd6120bc3dcc973902eebeff68b4fe28bd"
    },
    {
      "id": "ship/flashy-academy/939ea30b5106",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T14:05:20+00:00",
      "kind": "other",
      "title": "Phase A3: hunter-engagement decision + honest scope correction",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Documents the resolved civilization-age decision: hunter profile\n(level, XP, civilization age) stays owned by FlashyGoldAMS permanently,\nby explicit direction — not duplicated by Academy or any other\nproduct. Records the shipped POST /internal/hunter-engagement\n(commit 1bc8b61f) and its role as the seed of a real cross-product\nroadmap: hunters leveling up by engaging with Flashy Academy or any\nother FlashyLabs product, potentially brokered through FlashyOS's\nagent-mesh infra later — noted as direction, not committed to yet.\n\nAlso records attempting the actual learner-mutation route move next\nand finding it's bigger than scoped: quiz/[slug]/submit and progress\nreach into knowledgeWarService, academyStreakService,\nacademyReferralCodeService, academyEmailCaptureService,\nacademyDripService, academyLeadService, and raw customer PII access —\nFlashyGoldAMS's core engagement engine, not a clean second\nwallet-style cut. Flagged for a dedicated planning pass rather than\nforced under loop pressure.",
      "refs": {
        "commit": "939ea30b5106f8eca3d6e153b6aab6a3feebfb8b"
      },
      "digest": "76602f138613c9627c83f0b9eb0ad79037a90a569f62f08197e9d04ab470fba9"
    },
    {
      "id": "ship/flashy-academy/57204f9d3f5b",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T13:57:58+00:00",
      "kind": "other",
      "title": "Phase A3: internal wallet boundary + the first genuinely separable cut",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Documents the internal wallet-credit endpoint shipped in FlashyGoldAMS\n(POST /api/v1/internal/wallet/credit, commit 3ac59093 on\nclaude/multi-agent-workspace-view-84svas).\n\nAlso a real finding that revises this phase's scope:\nacademyProgressService.ts bundles two things together — the portable\nwallet-credit call, and a recomputeAndStoreCivilizationAge() call that\nreaches into core game models (hunterProfile, customer). Splitting the\nwhole file isn't a clean cut until that coupling has its own decision.\n\nWhat IS clean and moved now: getCertificate + verifyCertificate, split\ninto a new academyCertificateReadService.ts — confirmed neither touches\nthe wallet or civilization age. cert/verify route moved with them.\n32 of ~60 public routes now moved. Typecheck and next build clean.\n\nsubmitQuizAttempt and checkAndIssueCertificate stay in FlashyGoldAMS\nuntil the civilization-age boundary is decided — forcing that split\nnow would be the same mistake Phase A2 avoided with academyPublicProfileService.",
      "refs": {
        "commit": "57204f9d3f5bbe96fc096dec77b0427ef76a40fc"
      },
      "digest": "3be4ab501fa44331ab61d5c1e81a7e449a60b85f0576a0b80eab422bc6b17a13"
    },
    {
      "id": "ship/flashy-academy/d4aa40671098",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T13:34:24+00:00",
      "kind": "other",
      "title": "Phase A2 batch 6: Redis-backed rate limiting + 3 more public routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Ports src/lib/redis.ts and src/lib/rateLimit.ts verbatim (same shared-\ninfra pattern as the DB — one Redis instance across both apps during\nthis phase, not a separate one). Adds ioredis + rate-limiter-flexible.\n\nUnlocks tracks, tracks/[slug], quiz/[slug] (all via\nacademyCatalogService — note: a different file from\nacademyCatalogueService moved earlier for catalogue.json/.xml, despite\nthe near-identical name). Adds a local academyService.ts barrel that\nre-exports only academyCatalogService, not academyProgressService —\nthe wallet-credit path stays out until Phase A3.\n\nleaderboard (un-slugged) attempted and reverted: academyPublicProfileService\nis deeply coupled to core game models (hunterProfile, customer) despite\nits name — not a clean Academy cut.\n\n31 of ~60 public routes now moved. next build verified to fail loudly\nwithout REDIS_URL in production (by design in redis.ts), passes with a\nplaceholder value.",
      "refs": {
        "commit": "d4aa406710987eecd22976fa5320702a6dee7cc8"
      },
      "digest": "b4798fa287e371473c072fd0d9fbab872e12492bd7aae49e2c7135515e1f7cf0"
    },
    {
      "id": "ship/flashy-academy/df0589a0f30d",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T13:31:02+00:00",
      "kind": "other",
      "title": "Phase A2 batch 5: 7 more self-contained public Academy routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "alumni, bulk-verify, catalogue.json, catalogue.xml, graduates,\ntestimonials, verify/[certId] — ported with their backing services\n(academyAlumniService, academyBulkVerifyService, academyCatalogueService,\nacademyShowcaseService, academyLearnerTestimonialService,\nacademyCertVerificationService).\n\ncert-og/[credentialId] attempted and reverted: academyCertShareService\nreads a shared, non-Academy customer model. Also confirmed\ncert/verify's verifyCertificate lives in academyProgressService — same\nfile that credits the gold ledger — so that route correctly waits for\nPhase A3 rather than being split out separately.\n\n28 of ~60 public routes now moved. Typecheck and next build clean.",
      "refs": {
        "commit": "df0589a0f30dc1946badc1bc535c5fd29e72210b"
      },
      "digest": "65eaee7310071c400c93ff59e224a516823995c26af214a7dbabea1a7bebc1c7"
    },
    {
      "id": "ship/flashy-academy/54f7097c208a",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T13:19:10+00:00",
      "kind": "other",
      "title": "Phase A2 batch 4: the held-back lead-capture POST routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "waitlist, newsletter/subscribe, gated-assets/[slug]/unlock, assessment\n(submit), study-groups/join — services academyWaitlistService and\nacademyStudyGroupService added; the rest reuse services already moved\nin earlier batches.\n\nfunnel-event was attempted and reverted: its service\n(academyAnalyticsService) writes to a shared, non-Academy-prefixed\nAnalyticsEvent model not in this repo's schema — a real cross-cutting\ndependency, not a clean cut. referral/capture and war-invite scoped\nout for the same reason (Redis-backed rate limiter infra not stood up\nhere; a shared non-Academy game service, respectively).\n\n22 of ~60 public routes now moved. Typecheck and next build clean.",
      "refs": {
        "commit": "54f7097c208a15832bc023661a307ad3c4e285a1"
      },
      "digest": "021f4850287db863367f9dbdbea316207627d584f8d586c1a52df46f09e783ea"
    },
    {
      "id": "ship/flashy-academy/11bdc397a139",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T13:15:23+00:00",
      "kind": "other",
      "title": "Phase A2 batch 3: 6 more GET-only public Academy routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "challenge, gated-assets (list), newsletter/confirm/[token],\nnewsletter/unsubscribe/[token], assessment/[token], cpd/verify/[token]\n— ported verbatim with their backing services (academyChallengeService,\nacademyGatedAssetService, academyLeadMagnetService,\nacademyNewsletterService, academyAssessmentService, academyCPDService).\n\nSibling POST routes on the same services (gated-assets unlock,\nnewsletter subscribe, assessment submit, waitlist, study-groups join)\nare deliberately held back for a separate mutation-route batch, not\nfolded into this read-only phase.\n\n17 of ~60 public routes now moved. Typecheck and next build clean.",
      "refs": {
        "commit": "11bdc397a13913dd16a8d1e0b99460fa21f490ba"
      },
      "digest": "45e5b122c302a6cd39ccc87ad7aeb2027e35e66755739d99f6778df699c66829"
    },
    {
      "id": "ship/flashy-academy/45821aeb0720",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T12:08:26+00:00",
      "kind": "other",
      "title": "Phase A2 batch 2: 10 more public read-only Academy routes",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "stats, pillar-pages, blog + blog/[slug], case-studies +\ncase-studies/[slug], leaderboard/[trackSlug], trust-badge/[domain],\nevents + events/[id] — all GET-only, ported verbatim along with their\nbacking services. Deliberately excludes events/[id]/register and other\nmutation routes from this read-only phase.\n\nAlso ports src/lib/AppError.ts (simplified: plain string error code,\nnot FlashyGoldAMS's shared ErrorCode registry — not enough call sites\nhere yet to justify it).\n\n11 of ~60 public routes now moved. Typecheck and next build clean with\nall routes compiling; FlashyGoldAMS's originals untouched.",
      "refs": {
        "commit": "45821aeb0720fb0b5ab4f97dca7ab3d8c5b56503"
      },
      "digest": "22c71732a225b6d74502bc616e4ea1e5788ee75a19d10aa69e400922b7757b91"
    },
    {
      "id": "ship/flashy-academy/3c6e0eac7e93",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T01:10:15+00:00",
      "kind": "infra",
      "title": "Phase A2: move the first public read-only Academy route",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "GET /api/v1/public/academy/faqs + academyFAQService.ts, ported\nverbatim from FlashyGoldAMS. Proves the per-route migration pattern\nend-to-end: service + route + mocked route test (2/2 passing).\n\nAlso ports the shared infra these routes need: apiError.ts (identical),\na simplified pino logger.ts (no lazy-proxy Telegram coupling needed\nhere), and @/* path aliasing in both tsconfig.json and vitest.config.ts.\n\nFlashyGoldAMS's copy is untouched — both repos serving identical\nread-only data off the same DB is intentional and safe until Phase A6\ncuts traffic over. Remaining ~59 public routes move the same way.",
      "refs": {
        "commit": "3c6e0eac7e932b9e1e2fe9ccd6acec91ec3667e5"
      },
      "digest": "290aefec2a9886fc163c330ca3b819511d262b91479928a4c015e17be589a4a5"
    },
    {
      "id": "ship/flashy-academy/7052151b0273",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T01:06:11+00:00",
      "kind": "feature",
      "title": "Phase A1: stand up flashy-academy's own Prisma client on the shared DB",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Extracts all 57 Academy*-prefixed models verbatim from FlashyGoldAMS's\nschema.prisma (same @@map collection names, checked 2026-07-09, no\ncross-schema enum dependencies) into this repo's own schema, pointed\nat the same physical MongoDB per the extraction plan's shared-DB-first\ndecision. Prisma client singleton mirrors FlashyGoldAMS's connection-\npool defaults.\n\nSchema validates, client generates, typecheck and build are clean.\nLive read verification against real shared data is blocked by this\nsandbox's network policy (no raw Mongo egress) — same constraint that\nblocked direct Postgres access during FlashyOS's Neon setup.\nscripts/verify-shared-db-read.mjs is ready to run wherever real\nDATABASE_URL access exists.",
      "refs": {
        "commit": "7052151b027367e7d751271428a6624671adcdd4"
      },
      "digest": "df648b0baa5faeec37182dc9ea991c32920b283f5306324aa76da4ca7e30d6eb"
    },
    {
      "id": "ship/flashy-academy/784a4bd3fbab",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T01:00:53+00:00",
      "kind": "feature",
      "title": "Add the Academy extraction plan",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Grounded in an actual inventory of what's coupled today: 108 service\nfiles, 165 API routes, ~50 Academy-prefixed Prisma models, one hard\ndependency on the shared gold ledger, shared BullMQ/Redis, and 4\nTelegram bot handlers. Recommends keeping the database shared through\nthe whole migration and only giving the gold-ledger write path a real\nservice boundary (POST /internal/wallet/credit) — everything else\nmoves by coupling risk: public reads first, the learner/wallet flow\nnext, admin/cron/Telegram last, physical DB split evaluated only after\nfull cutover if there's a real reason for it.",
      "refs": {
        "commit": "784a4bd3fbabdceea85afe5ea804916266ab0781"
      },
      "digest": "b0b32222888b9e5c9392d22c734edb94a1a79c92a3cde43e37123fbc212b1e97"
    },
    {
      "id": "ship/flashy-academy/97faf8a0f25e",
      "repo": "repo/flashy-academy",
      "at": "2026-07-09T00:54:13+00:00",
      "kind": "feature",
      "title": "Scaffold flashy-academy as a standalone Next.js app",
      "by": [
        "agent/claude"
      ],
      "asserted": "2026-08-30",
      "assertedBy": "agent/flashy-academy-ci",
      "visibility": "public",
      "detail": "Bare app shell (App Router, TypeScript, strict mode), a health check\nroute, and FlashyOS reporter wiring (own org, same explicit-instantiation\npattern as FlashyGoldAMS's integrations) — live-verified against the\nreal local FlashyOS API (heartbeat returns 200).\n\nThis is scaffolding only. Flashy Academy's actual features still live\nin FlashyGoldAMS (src/services/academy*.ts, src/app/api/v1/academy/*) —\nmigrating that code into this repo is separate, larger, follow-up work.",
      "refs": {
        "commit": "97faf8a0f25ede8dd838ac3be59a40bd74845e84"
      },
      "digest": "b7417edd9ab272f223af5d49710fdb30a5ecd815bb5cd6e01530fcd4e357da25"
    }
  ]
}
