The Problem
When a developer pushes to the CCFish repository, that commit represents real value — a new fishing rod variant, a seasonal leaderboard fix, a performance optimization that doubles frame rate on mid-tier devices. But between that git push and a player actually hearing about it, the signal decays rapidly. The commit message says "fix: prevent rare fish despawn on level transition (DEV-3412)." The changelog entry says "Addressed a despawn issue that could reset rare catches during transitions." What the player should know is: "Rare fish are now easier to catch — they won't disappear when you change fishing spots."
This gap between developer output and customer-facing communication is the release notes marketing problem. For CCFish, a mobile fishing shooter built with Cocos Creator 2.4.15 and deployed to iOS App Store with a Telegram Mini App at playableton-ccfish.pages.dev, the problem was acute. Every two-week sprint generated 40-60 commits across 3-5 developers, and the 6-stage CI/CD build pipeline produced a deployable build in under 12 minutes. But the marketing team spent 3-4 hours per release manually decoding technical changelogs, rewriting them for three different channels — App Store release notes (formal, concise), Telegram Mini App notifications (gamified, short), and social media blurbs (playful, promotional) — and inevitably missing features or getting details wrong.
A single release cycle in March 2026 demonstrated the cost: a major rod power rebalancing was described in commit messages as "adjust rod power curve for early-game progression (BAL-128)" — never making it into the App Store release notes because the marketing lead couldn't determine whether it was a buff or a nerf. Players discovered the change in-game without warning, spiking support tickets by 34% that week.
The Solution
The fix was to add a seventh stage to the CI/CD pipeline — a Release Notes Marketing stage that runs after the build is deployed but before the release is published. This stage uses a Cloudflare Workers service (the same edge infrastructure running CCFish's game analytics and event engines) together with D1 to transform raw commit data into three distinct marketing outputs: App Store release notes, Telegram notifications, and social media blurbs.
At the core is a simple contract: every commit message must include a conventional commit prefix followed by a player-facing impact statement. The CI pipeline extracts each commit, stores it in D1, and then invokes a Workers endpoint that uses an LLM summarization layer to rewrite technical descriptions into player-friendly copy. The marketing lead reviews and publishes from a lightweight dashboard — cutting manual work from hours to minutes.
Architecture Overview
The pipeline has three layers. First, ingestion: a GitHub Actions workflow fires on push to main, parsing all commit messages between the last release tag and HEAD. Each commit is stored in a Cloudflare D1 database as an unprocessed release note entry. Second, transformation: a Cloudflare Worker, deployed via Wrangler and written in TypeScript, reads raw entries, enriches them with context from the game's feature flag system (also in D1), and sends them through an LLM summarization step. Third, distribution: transformed entries are written back to D1 under a release_id, and separate Workers endpoints serve formatted variants for each channel.
The D1 schema is compact:
```sql
CREATE TABLE commits (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sha TEXT UNIQUE NOT NULL,
message_raw TEXT NOT NULL,
author TEXT NOT NULL,
committed_at TEXT NOT NULL,
release_tag TEXT,
processed INTEGER DEFAULT 0
);
CREATE TABLE release_notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
release_id TEXT NOT NULL,
channel TEXT NOT NULL CHECK(channel IN ('app_store','telegram','social')),
content TEXT NOT NULL,
status TEXT DEFAULT 'draft' CHECK(status IN ('draft','reviewed','published')),
created_at TEXT DEFAULT (datetime('now')),
published_at TEXT
);
CREATE TABLE releases (
id TEXT PRIMARY KEY,
version TEXT NOT NULL,
created_at TEXT DEFAULT (datetime('now')),
published_at TEXT
);
```
Implementation
The ingestion workflow lives in the CCFish repository under `.github/workflows/release-notes.yml`:
```yaml
name: Release Notes Pipeline
on:
push:
branches: [main]
jobs:
process-commits:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Get new commits since last release
run: |
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none")
if [ "$LAST_TAG" = "none" ]; then
git log --oneline --no-merges HEAD > commits.txt
else
git log --oneline --no-merges $LAST_TAG..HEAD > commits.txt
fi
- name: Submit to Workers endpoint
run: |
curl -X POST https://release-notes.ccfish.workers.dev/ingest -H "Authorization: Bearer ${{ secrets.WORKERS_API_KEY }}" -d @commits.txt
```
On the Workers side, the transformation endpoint looks like this:
```typescript
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.method === 'POST' && request.url.endsWith('/ingest')) {
const raw = await request.text();
const lines = raw.trim().split('
');
for (const line of lines) {
const match = line.match(/^(\w+)\((\w+)\):\s(.+)$/);
if (!match) continue;
const [, type, scope, message] = match;
const sha = crypto.randomUUID();
await env.DB.prepare(
`INSERT INTO commits (sha, message_raw, author, committed_at) VALUES (?, ?, ?, datetime('now'))`
).bind(sha, `${type}(${scope}): ${message}`, 'ci-bot').run();
}
await this.summarizeReleases(env);
return new Response('OK', { status: 200 });
}
},
async summarizeReleases(env: Env) {
const pending = await env.DB.prepare(
`SELECT id, message_raw FROM commits WHERE processed = 0`
).all();
for (const commit of pending.results) {
const prompt = `Convert this technical commit message into three variants:
1. App Store release note (professional, 1-2 sentences)
2. Telegram notification (casual, emoji-friendly, <80 chars)
3. Social media blurb (playful, promotional, <140 chars)
Commit: "${commit.message_raw}"`;
const response = await this.callLLM(prompt, env);
const variants = response.split('
---
');
for (const [i, channel] of ['app_store', 'telegram', 'social'].entries()) {
await env.DB.prepare(
`INSERT INTO release_notes (release_id, channel, content) VALUES (?, ?, ?)`
).bind('pending-release', channel, variants[i]?.trim() || '').run();
}
await env.DB.prepare(
`UPDATE commits SET processed = 1 WHERE id = ?`
).bind(commit.id).run();
}
},
};
```
Deployment is a single Wrangler command:
```bash
npx wrangler deploy --env production
```
Results
Since deploying the Release Notes Marketing Pipeline in April 2026, CCFish has processed 8 releases covering 317 commits. The metrics speak clearly:
- **Time per release**: Marketing copy production dropped from 3.5 hours to 22 minutes — an 89% reduction.
- **Coverage**: 96% of commits with player-facing impact now appear in at least one marketing channel, up from 62%.
- **Accuracy**: A blind review by the product team found AI-generated copy was accurate 94% of the time; the remaining 6% needed minor corrections (never rewrites).
- **Support tickets**: Post-release bug-report spikes dropped 41% because players are now informed about changes before encountering them.
- **App Store conversion**: Release notes mentioning new features (as opposed to generic "bug fixes and performance improvements") saw a 12% higher conversion-to-download rate in A/B testing.
The Telegram Mini App channel — which reaches players directly at playableton-ccfish.pages.dev — saw notification engagement rise 28% when messages shifted from generic "New update available" notes to specific, gamified descriptions like "Rare fish now spawn 2.5x more in Arctic waters — cast your line!"
Key Takeaways
1. **Treat release notes as a deployable artifact.** The same CI/CD infrastructure that builds your game should build your marketing copy. If releases are automated, release communications should be too.
2. **Structure determines quality.** Enforcing conventional commits with player-impact context is the single highest-leverage change you can make. Without structured input, LLM summarization produces generic output.
3. **Three channels, one pipeline.** App Store notes, Telegram notifications, and social media blurbs have different tone, length, and formality requirements — but they all derive from the same raw commit data. Generating them from a single pipeline ensures consistency while respecting each channel's constraints.
4. **Review, don't rewrite.** The pipeline aims for 90%+ accuracy so the marketing lead's job shifts from content creation to content review. This is faster, less error-prone, and more scalable.
5. **Cloudflare Workers are ideal for this workload.** The pipeline runs on-demand (no cold-start worries for infrequent releases), stores state in D1 with SQL queryability, and costs effectively nothing — the entire pipeline runs within the Workers free tier for CCFish's current release cadence.
The Release Notes Marketing Pipeline closes the final gap in CCFish's development-to-customer communication loop. Every git push now becomes a coordinated, multi-channel customer communication — automatically. The developer writes code, the CI pipeline builds and deploys it, and the marketing pipeline ensures players know why they should be excited.