Skip to main content

Keeping nself.org in sync with SPORT

How to update marketing copy, pricing, and plugin counts when SPORT source files change.

All version strings, prices, and plugin counts on nself.org are generated at build time from authoritative SPORT source files. Hand-editing these values in the website source will cause your changes to be overwritten on the next build.

What is SPORT?

SPORT (Single Point of Reference Truth) is a set of 15 Markdown files at .claude/docs/sport/F01-F15.md inside the nself monorepo root. These files are code-verified and read-only. They are the canonical source for:

  • Plugin counts (F03, F04)
  • Bundle membership (F06)
  • Pricing tiers (F07)
  • Version strings (F01 / MASTER-VERSIONS.md)

How the build pipeline works

SPORT source files  →  build scripts  →  generated files  →  Next.js pages

Three scripts run before every pnpm dev and pnpm build in web/org:

Script Input Output
scripts/sync-sport.mjs SPORT + MASTER-VERSIONS src/generated/sport.json
scripts/gen-pricing.mjs F06, F07, sport.json src/data/generated-pricing.ts
scripts/validate-sport-json.mjs sport.json CI gate (exits non-zero on errors)

The pages that consume generated data:

  • /pricing: imports GENERATED_TIERS and GENERATED_BUNDLES
  • /plugins: imports GENERATED_PLUGIN_COUNTS for header stats

Updating prices or bundle membership

  1. Edit the authoritative SPORT file:

    • Pricing changes → .claude/docs/sport/F07-PRICING-TIERS.md
    • Bundle membership changes → .claude/docs/sport/F06-BUNDLE-INVENTORY.md
  2. Regenerate the TypeScript data module:

    cd web/org
    node scripts/gen-pricing.mjs
  3. Verify the output in src/data/generated-pricing.ts matches your intent.

  4. Run tests to confirm no canonical values regressed:

    pnpm vitest run

Updating version strings

  1. Edit MASTER-VERSIONS.md at the nself monorepo root (.claude/docs/MASTER-VERSIONS.md).

  2. Regenerate sport.json:

    cd web/org
    node scripts/sync-sport.mjs
  3. The /pricing and /plugins pages pick up the new counts automatically via sport.json.

Updating plugin counts

Plugin counts are no longer derived from F03/F04 (those are now pointer-only docs). They come from plugins/counts.json (LOCKED SCHEMA v1, produced by plugins/scripts/plugin-counts.sh in the public nself-org/plugins repo), which sync-sport.mjs reads directly into sport.json’s counts.* fields. To update:

  1. Add or remove plugins in plugins/ or plugins-pro/, then regenerate counts.json with plugins/scripts/plugin-counts.sh in that repo.
  2. Run node scripts/sync-sport.mjs (from a checkout with a sibling plugins/ repo present) to update sport.json.
  3. Run node scripts/gen-pricing.mjs to propagate counts to generated-pricing.ts.

The plugins page header, /pricing, and any docs page importing GENERATED_PLUGIN_COUNTS from @/data/generated-pricing will now show the correct counts. Never hand-type a plugin count in prose — see PLUGIN_COUNT_PROSE_TARGETS in validate-sport-json.mjs, which fails CI on exactly that.

CI validation

validate-sport-json.mjs runs in CI as part of the “SPORT Drift Check” job (.github/workflows/ci.yml). It fails if:

  • sport.json is missing required keys (generatedAt, versions, bundles, pricingTiers, counts)
  • CLI version is not in vX.Y.Z format
  • Any superseded tier name (Basic, Pro, Elite, Business) appears in pricingTiers
  • Free plugin count drops below 25, or paid plugin count drops below 30
  • counts.totalPluginCount doesn’t equal free + paid minus the tier-paired overlap
  • Any page in PLUGIN_COUNT_PROSE_TARGETS states a literal plugin-count digit that disagrees with counts.*

Fix validation failures by regenerating sport.json or fixing the prose to render from GENERATED_PLUGIN_COUNTS, not by patching validate-sport-json.mjs.

Never hand-edit these files

File Why
web/org/src/generated/sport.json Overwritten on every build
web/org/src/data/generated-pricing.ts Overwritten by gen-pricing.mjs

Changes to these files will be silently discarded.