---
url: https://docs.nemo12.com/ops/repo-size.md
description: >-
  SRC-1422 (16.10.2026): what fills nemo12-www (34.7 MB) and nemo12.com (161.9
  MB), and the ordered path to about 5 MB and about 10-12 MB.
---

# Repo size audit (16.10.2026)

Owner 16.10.2026 (SRC-1422): bring nemo12-www down to about 5 MB and nemo12.com to about 10 MB, audit
first. Measured on the state right after the repo split (16.10.2026): nemo12-www with its open PRs #1-#4,
nemo12.com on `session/repo-split` (www and Pearl already removed, otherwise equal to main).

**Verdict.** nemo12-www can reach about 5.5 MB, and 5 MB once the CMS (phase 2 of the split) owns www
content. nemo12.com reaches about 36 MB by taking media, SQL, migrations and content out of git (and
landing the removals already in flight); about 17 MB once docs.nemo12.com has its own repo and the eleven
extra apps are out or retired; about 12-14 MB with generated E2E fixtures and archived one-off scripts.
What remains is code and tests, which should stay: exactly 10 MB would mean cutting code itself.

## Two sizes, two different fixes

| | Checkout (tracked files at HEAD) | Clone (git history, packed) |
| --- | --- | --- |
| nemo12-www | 34.7 MB, 1,433 files | 12.3 MB |
| nemo12.com | 161.9 MB, 5,623 files (190 MB, 6,482 files before the split) | 147.7 MB |

Removing files shrinks the checkout at once. The clone keeps every old version until history is rewritten
(section "Git history"). `node_modules` (707 MB and about 810 MB) is not in git and is not counted.

## nemo12-www: 34.7 MB to about 5 MB

Every tracked file sits in exactly one bucket:

| Bucket | MB | What | Fix |
| --- | --- | --- | --- |
| Generated seed SQL | 15.46 | `scripts/seed-seo-pages.sql` 6.05, four `seed-articles-*.sql` 8.17, `seed-illustrations.sql` 1.26 | Stop committing: the seed-data workflow builds them from source right before loading |
| Content | 8.85 | 400 article Markdown files 3.93, SEO pages 0.96, `docs/curriculum` 1.91, illustration registry + alts 1.42, books content 0.88 | CMS phase 2: content lives in D1 `nemo12-cms`, edited in cms.nemo12.com |
| Code | 3.73 | apps, worker, scripts, packages | Keep |
| Images | 2.70 | social covers 2.15 (`cover-youtube.png` 0.81 ...), article photos 0.55 | R2 (`nemo12-content`), served from the media route |
| Contract snapshots | 2.34 | `openapi.snapshot.json` 1.22, `seed-videos.sql` 0.74 | Keep only what tests read: the path list (about 30 KB) and the video rows (about 50 KB) |
| Other | 1.44 | `package-lock.json` 0.52, config, SVG | Keep |
| Tests | 0.21 | | Keep |

| Step | Saves | Size after | Risk |
| --- | --- | --- | --- |
| 1. Generated seeds out of git | 15.5 | 19.3 | Low: one workflow change; the `--check` gates move into it |
| 2. Slim contract snapshots | 1.9 | 17.4 | Low |
| 3. Images to R2 | 2.7 | 14.7 | Low: URLs change, the SEO gate checks them |
| 4. CMS phase 2 (content to D1) | 8.9 | about 5.8 | Medium: the planned phase 2 itself |
| 5. Large copy files in `src/site` (`subjectCopy.ts`, `students.ts` ...) to CMS | about 0.8 | about 5.0 | Medium |

## nemo12.com: 161.9 MB to about 10-12 MB

| Bucket | MB | What | Fix |
| --- | --- | --- | --- |
| Media | 52.1 | 455 MP3 in apps/learn/public/audio 38.6, JPG 13.1 (apps/learn/public/img 10.2, compass 2.9), PNG 0.4 (learn's are in R2 since 17.10.2026) | R2 `nemo12-content`, served like the videos already are |
| Seed and archive SQL | 21.5 | 66 `scripts/*.sql` 19.4 (`seed-b21` 3.0, `seed-parent-bodies-*` 7.1, `seed-parent-gates-*` 4.4, `seed-grammar` 1.3 ...), the AI Teen scripts folder 1.3 (removed by SRC-1419), `scripts/archive` 0.8 | Generated ones: build at seed time. Already-loaded one-offs: archive to R2 with their run date |
| Migrations | 20.2 | 358 files; the big ones load content (`0294` 1.75, `0280` 1.72, `0265` 1.10 ...) | Squash into one baseline schema: 374 tables = 252 KB. Content goes to seeds; tests get small fixtures |
| Content data | 15.6 | `scripts/course-content` 6.9, `apps/learn/src/**/*.json` 4.9, `content/` 3.7, `scripts/b21` 1.2 ... | D1 (it is already the source of truth for IELTS content), edited in Dolphin (SDD-056) |
| In-flight removals | 14.5 | math (the learn math folder, course content), AI Teen, b21 (math and AI Teen removed by SRC-1419) | Already claimed by other sessions (`toan12-split`, `english-only-cleanup`, `b21-redirect`) |
| Apps not in the owner's list | 8.8 | marlins 6.9 (5.8 of it parent lessons and ebook chapters as `.ts`, the same text again in `seed-parent-*.sql`), compass, ui, coral, gull, mm, partners, tutors, reef, ielts, playbooks | Owner decision: own repo(s), or retire |
| Docs | 9.9 | docs.nemo12.com | Own repo (`nemo12-docs`), like www |
| Code | 11.1 | learn, api, admin, dolphin, docs app, packages, scripts | Keep; one-off scripts can be archived |
| Tests and E2E fixtures | 4.5 | api tests 1.9, learn E2E 2.3 (`content.fixture.json` 0.9) | Keep; generate the big fixtures |
| Other | 1.4 | lock, config | Keep |
| Content as code TS | 2.2 | `explore/configs.tsx` 0.24, `shared/prompts.ts` 0.15 ... | D1 |

| Step | Saves | Size after | Risk |
| --- | --- | --- | --- |
| 1. Media to R2 | 52.1 | 109.8 | Low-medium: a media route, URL rewrite, e2e of audio pages |
| 2. Seed and archive SQL out of git | 21.5 | 88.3 | Low |
| 3. Squash migrations (baseline + test fixture; the baseline runs once on production as a no-op) | 20.0 | 68.3 | Medium: `migrate:check` and api tests move to the baseline |
| 4. Land the in-flight removals (math, AI Teen, b21) | 14.5 | 53.8 | Owned by other sessions |
| 5. Content data and content-as-code to D1 | 17.8 | 36.0 | Medium-high: content editing moves to Dolphin |
| 6. Docs to their own repo | 9.9 | 26.1 | Medium, same recipe as the www split |
| 7. The eleven extra apps out or retired | 8.8 | about 17.3 | Owner decision per app |
| 8. Generate big E2E fixtures, archive one-off scripts | about 3-5 | about 12-14 | Low |

Exactly 10 MB would mean cutting code itself. The audit recommends stopping at about 12-14 MB.

## Git history

| | Today | After rewriting history to drop media and SQL blobs |
| --- | --- | --- |
| nemo12-www | 12.3 MB (SQL 2.6, PNG 2.4, MD 2.6) | about 5 MB |
| nemo12.com | 147.7 MB (MP3 34.5, JPG 22.5, SQL 15.5, PNG 14.9, MD 11.7, TS 11.2) | about 30-40 MB |

A rewrite force-pushes `main` and invalidates every open branch, `ready/*` branch and worktree (10
`ready/*` branches and 8 claimed tasks today). Plan:

* **nemo12-www:** rewrite now, before anyone else depends on it: its only branches are the split's own.
* **nemo12.com:** rewrite once, last, at a quiet moment: after steps 1-3, with every session stopped and
  every open branch merged or rebased.

## Order and guardrails

1. nemo12-www steps 1-3, plus its history rewrite.
2. nemo12.com steps 1-3 (media, SQL, migrations): 94 MB out at low risk.
3. CMS phase 2 (nemo12-www step 4) and nemo12.com step 5 (content to D1 via Dolphin).
4. Owner decisions: docs repo, extra apps.
5. nemo12.com history rewrite.

A gate stops regrowth in both repos: no new tracked media file (`.mp3`, `.m4a`, `.jpg`, `.png`, `.webp`),
no new generated `scripts/seed-*.sql`, and no tracked file over 500 KB without an allow-list line with a
reason.

## Progress

| Date | Step | Result |
| --- | --- | --- |
| 17.10.2026 | nemo12-www steps 1-3 | 34.7 to 16.5 MB (nemo12-www PRs #5, #6) |
| 17.10.2026 | Unused D1 data archived to R2 and dropped | migration 0359, PR #714 (see [data-audit](data-audit.md)) |
| 17.10.2026 | nemo12.com step 2, seeds without test readers | 7.5 MB out, PR #715 |
| 17.10.2026 | nemo12.com step 1, NEMO WALK media to R2 | 48.8 MB out: 549 files verified by sha256 from production, served by `GET /v1/public/media/walk/...` (PR #716 and the learn PR) |
| 17.10.2026 | nemo12.com step 3, migrations to a baseline | 359 files (20.2 MB) became `0000_baseline.sql` (483 KB) plus `workers/api/test/reference-rows.sql` (848 KB of test rows): 18.9 MB out, checkout 124.6 to 105.7 MB. On the bare baseline 102 of 3,250 api tests failed, all for missing reference rows; the fixture brings them back. Production schema read 17.10.2026: all 732 baseline objects already exist there, so the baseline's one run is a no-op |
| 17.10.2026 | Bank-wide IELTS content checks back, on production data | The squash left the api tests a six-skill slice. Nightly job `ielts-bank-check` (see below) now checks the whole bank |

## Checks on content that lives only in production

After step 3, production D1 is the only copy of the IELTS micro-skill bank (51 skills, about 5,000 items),
edited through seed-data or Dolphin. The api tests that used to check the whole bank now see the slice in
`workers/api/test/reference-rows.sql`. The nightly workflow `.github/workflows/ielts-bank-check.yml`
(22:30 UTC, also `workflow_dispatch`) covers the rest:

* It exports `ielts_task_types`, `ielts_micro_skills`, `ielts_micro_exercises` and
  `ielts_micro_skill_items` with `wrangler d1 export` (read-only) into SQLite.
* `scripts/check-ielts-bank.mjs --db <file>` runs the rules the tests enforced up to SRC-1422: 51 skills per
  area, at least 5,008 items, every answer index within distinct options, every warm-up set showing 3
  items, four stages per skill and their languages, at least 4 items per skill with exercises, at least 3
  exercises per level for Listening, Speaking and Writing, plus reference and task-type checks.
* `scripts/audit-content.mjs --db <file>` scores completeness; it now fails when the D1 part cannot be read.

A red run means production content broke a rule: fix the rows through seed-data or Dolphin. Adding a skill or
retiring items on purpose means editing the floor in `check-ielts-bank.mjs`.

## How to measure again

```bash
git ls-files -z | xargs -0 stat -f '%z' | awk '{s+=$1} END {printf "%.1f MB\n", s/1048576}'
git count-objects -vH | grep size-pack
```
