# Contributing

Thanks for your interest in `@ironarachne/made-up-names`. This document covers
how to get set up, how changes get merged, and how releases are cut.

## Getting set up

```bash
git clone https://github.com/ironarachne/made-up-names.git
cd made-up-names
npm install
```

Node 20 or newer is required. CI tests against Node 20, 22, and 24.

## Everyday commands

| Command             | What it does                                        |
| ------------------- | --------------------------------------------------- |
| `npm run check`     | Lint, typecheck, build, and test — run before pushing. |
| `npm test`          | Run the Vitest suite.                                |
| `npm run lint`      | Check formatting and lint rules with Biome.          |
| `npm run lint:fix`  | Apply formatting and safe lint fixes.                |
| `npm run typecheck` | Typecheck `src/`, `tools/`, `tests/`, and `scripts/`. |
| `npm run build`     | Compile `src/` to `dist/`.                           |
| `npm run docs`      | Generate the TypeDoc site into `docs/`.              |

`dist/` and `docs/` are build output. They are gitignored and generated by CI —
never commit them.

## Name quality tooling

Culture generators are judged by the names they produce, so there are scripts
for looking at that directly rather than guessing:

| Command                        | What it does                                        |
| ------------------------------ | --------------------------------------------------- |
| `npm run generate:names`       | Print a sample from one culture and category.        |
| `npm run score:variety`        | Score how varied a generated sample is.              |
| `npm run score:corpus-structure` | Compare generated names to a research corpus.      |
| `npm run report:culture-quality` | Both scores together, per category, for a culture. |

Each takes `--` before its arguments, and prints usage with no arguments:

```bash
npm run generate:names -- fantasy town 20
npm run report:culture-quality -- "forest dweller"
```

The research corpora those scripts compare against live in `src/research/`, one
`<culture-slug>-corpus.json` per culture with a matching `.md` documenting where
the corpus came from. If you change a culture's patterns, run
`report:culture-quality` before and after and put both numbers in your pull
request.

## Repository layout

| Path            | Contents                                                    |
| --------------- | ----------------------------------------------------------- |
| `src/index.ts`  | The entire published API.                                    |
| `src/cultures/` | Pattern and word-element data, one JSON file per culture.    |
| `src/research/` | Research corpora backing the culture data. Not published.    |
| `tools/`        | Scoring and reporting modules. Development only.             |
| `scripts/`      | Command-line entry points over `tools/`.                     |
| `tests/`        | Vitest suite.                                                |

Only `src/` is compiled into `dist/` and published. `tools/` and `scripts/` are
development tooling and are typechecked but never shipped.

## How changes get merged

`main` is protected. Nothing is pushed to it directly; every change lands
through a pull request.

1. **Open an issue first** for anything beyond a small fix, so the approach can
   be agreed before you spend time on it.
2. **Branch from `main`.** Name it for the work: `fix/planet-name-repeats`,
   `feat/desert-nomad-culture`, `chore/bump-biome`.
3. **Write the change and its tests.** Follow [CODE_STYLE.md](CODE_STYLE.md) —
   in particular the rules on TSDoc, culture data, and determinism.
4. **Run `npm run check`.** CI runs the same thing; catching it locally is
   faster.
5. **Open a pull request** against `main` and fill in the template. Keep pull
   requests focused — one concern each. Unrelated cleanups belong in their own
   pull request.
6. **CI must pass.** The `Lint` and `Test` jobs are required checks; the merge
   button stays disabled until they are green.
7. **Get a review.** Address feedback with new commits rather than
   force-pushing, so reviewers can see what changed.
8. **Squash and merge.** The pull request title becomes the commit subject on
   `main`, so write it as one. Your branch is deleted automatically.

## Commit messages

Use [Conventional Commits](https://www.conventionalcommits.org/) for pull
request titles and commits. This keeps generated release notes readable.

```
feat: add desert nomad culture
fix: stop planet names repeating the same suffix
docs: document the seed argument on every generator
chore: bump biome to 2.4
```

Mark a breaking change with a `!` — `feat!: rework fantasy name patterns` — and
explain the impact in the pull request body.

## What counts as breaking

This library's contract is that a given seed always produces the same names.
Any change that alters that is breaking, even if no signature changes:

- Editing a culture's patterns or word element sets in `src/cultures/`.
- Changing how many times a generator draws from the RNG.
- Changing the order in which patterns are chosen or values consumed.

Such a change needs a major version bump and a clear note in the pull request.
Adding a *new* culture or generator is not breaking — existing seeds are
untouched.

## Reporting security issues

This library generates fictional names and is not a security boundary. If you
find something that nonetheless looks security-relevant, email ben@overmyer.net
rather than opening a public issue.

## Releasing

Releases are automated. Maintainers cut one by tagging `main`.

If you use Claude Code, `/release <patch|minor|major>` drives the whole
sequence below and verifies the result; `.claude/skills/release/SKILL.md` is
the source of truth for it. The manual steps are:

1. Land everything intended for the release on `main`.
2. Bump the version on a branch. `--no-git-tag-version` matters: `main` is
   protected, so the bump has to merge before the tag can point at it.

   ```bash
   git checkout -b release/2.5.0
   npm version 2.5.0 --no-git-tag-version
   git commit -aq -m "chore: release 2.5.0"
   git push -u origin release/2.5.0
   ```

3. Open a pull request for it and merge once CI is green.
4. Tag the merged commit on `main` and push the tag:

   ```bash
   git checkout main && git pull
   git tag -a v2.5.0 -m "Release 2.5.0"
   git push origin v2.5.0
   ```

Pushing a `v*` tag triggers `.github/workflows/release.yml`, which:

1. Verifies the tag matches `package.json`'s version, then lints, typechecks,
   builds, and tests. A mismatch fails the release before anything is
   published.
2. Publishes to npm with [provenance](https://docs.npmjs.com/generating-provenance-statements)
   attached.
3. Creates a GitHub Release with auto-generated notes from the merged pull
   requests.

Separately, every push to `main` rebuilds the TypeDoc site and deploys it to
[ironarachne.github.io/made-up-names](https://ironarachne.github.io/made-up-names).

### One-time maintainer setup

The release workflow needs these configured before the first tagged release:

- **npm trusted publishing** — on npmjs.com, under the
  `@ironarachne/made-up-names` package settings, add a trusted publisher with:

  | Field            | Value             |
  | ---------------- | ----------------- |
  | Organization     | `ironarachne`     |
  | Repository       | `made-up-names`   |
  | Workflow         | `release.yml`     |
  | Environment      | `release`         |

  The workflow filename is the basename only — not a path. The environment
  must read `release` to match the `publish` job, or be left blank.

  This replaces a long-lived `NPM_TOKEN`: the workflow authenticates over
  OIDC, so there is no publish secret stored in the repository at all.

- **Pages** — Settings → Pages → Source set to **GitHub Actions**.
- The `release` environment, which you can use to require manual approval
  before a publish goes out.
