# Development documentation These files explain **why** this project works the way it does: the decisions behind it, what was rejected, and the shortcomings and known issues we carry. They are written for maintainers and contributors of the project itself. The actionable rules — how to set up, run, test, and submit — live in [CONTRIBUTING.md](../CONTRIBUTING.md). This folder is the "why" behind those rules: read the relevant file here before changing an area, and update it when a decision changes, rather than leaving an obsolete reason behind. A rule and its reason drift apart when they live in one place and are maintained in two; keeping the rule in CONTRIBUTING.md and the reason here keeps each single-homed. User-facing documentation lives in [README.md](../README.md). A `docs/` folder is deliberately not used yet: the convention is that `docs/` is the future user documentation site, and deploying that site is out of scope. When it exists, these files stay here — they are not user documentation. ## Layout One file per category: | File | Covers | | -------------------------------- | ----------------------------------------------------------------------- | | [library.md](./library.md) | Public API design, the type-level contract, and its limitations | | [workflow.md](./workflow.md) | Branching and merging, script prefixes, feedback tiers, commit messages | | [tooling.md](./tooling.md) | Toolchain choices and configuration, editor setup | | [testing.md](./testing.md) | Test strategy and type-driven development | | [ci.md](./ci.md) | CI pipeline, runner image, coverage serving | | [publishing.md](./publishing.md) | Release and npm publishing | A category that outgrows one file becomes a folder with an index, but we start with one file per category because each area is small enough to hold in mind at once. When a category splits, the links in CONTRIBUTING.md and README.md keep pointing at the category, not at a single decision. ## Decision blocks Every non-obvious choice is recorded as a block inside the relevant category file, using this shape: ```md ## Runner image #### Decision (2026-09) Bake Node into the CI job image at the setup-node tool-cache layout instead of downloading per job. #### Why - ... #### Rejected - Gitea Pages / per-job download - force-pull #### Known issue - a Dockerfile-only change re-pushed under an unchanged tag is invisible to the runner - recover with `docker rmi ` ``` - The date is the month the decision was made, not the date the file was last edited. It is the anchor a reader uses to tell "this is current" from "this was current once". - `Rejected` is what makes the record worth keeping: it stops the project from re-litigating the same alternatives. An empty `Rejected` usually means the alternatives were never written down. - `Known issue` is where shortcomings live. If a caveat is not tied to one decision, put it under a `## Known issues` section at the end of the file. - A superseded decision is **replaced in place**, not archived in a second file — the file always describes the current world, and git history is the archive. ## Adding to these docs 1. Pick the category file for the area you are changing: `workflow`, `tooling`, `testing`, `ci`, or `publishing`. 2. Add or update a decision block. Keep the existing text unless the decision actually changed. 3. If the change alters an actionable rule, update [CONTRIBUTING.md](../CONTRIBUTING.md) in the same commit and cross-link the two.