Skip to main content
Version: 4.0 (next)

Contribute documentation

Orientation

Change the canonical page under website/docs; do not hand-edit immutable version snapshots. Keep the page focused on one reader task and preserve its selected-version context. C# is the canonical example language.

A user guide should orient the reader, show a runnable example, name a real pitfall, state version boundaries, and link to related guidance plus the same-version API root. Contributor-only detail belongs in this cluster rather than in the primary user path.

Example

Use front matter that identifies the page role and primary reader:

---
id: choose-a-culture
title: Choose a culture
diataxis: how-to
persona: application developer
example: illustrative
---

If an example is executable, add it to the documentation example harness and import the tested source. Mark non-executable fragments as illustrative and keep them syntactically honest.

Pitfall

Do not copy current behavior into a historical page without package or tagged source evidence. Do not link a historical guide to a current API route. Avoid hand-maintained language counts and lists; update locale YAML and rerun the one coverage generator.

Version notes

The canonical corpus includes main/preview as a first-class public preview. Published snapshots remain version-honest and immutable except for reviewed, targeted factual corrections through the snapshot workflow.

Validate a documentation change

Restore the pinned tools and site dependencies, then run the same gates used by the Pages workflow:

dotnet tool restore
pnpm --dir website install --frozen-lockfile
pwsh tools/docs/build.ps1 -Mode Validate
pwsh tools/docs/test.ps1 -RequireNativeAot
pnpm --dir website run check:content
pnpm --dir website run build
pnpm --dir website run check:links
pnpm --dir website run check:search-budget
pnpm --dir website run check:artifact
pnpm --dir website run test:unit
pnpm --dir website run typecheck
pnpm --dir website run test:ci

The build reads every published package and immutable snapshot from website/humanizer-versions.json. It does not check out historical branches or rewrite a published snapshot.

The repository-scoped Renovate GitHub App keeps Node, pnpm, and site dependencies current from .github/renovate.json; its pull requests run these same gates.

Publish a stable version

Before package publication, add one unpublished, NuGet-backed version entry, its bounded compatibility overlay, and its upgrade boundary and guide in a normal pull request. After the signed package is available from NuGet.org, dispatch the release workflow from main:

gh workflow run docs-release.yml --ref main \
-f version=3.1.0 \
-f promote_latest=true

The workflow uses the existing atomic snapshot command, validates the package hash and signature with bounded retries, runs the complete site gates, and opens a pull request containing only the generated snapshot, sidebar, selector, and manifest changes. A retry after the release branch is pushed resumes only when that branch changes no paths outside the defined release outputs and those outputs exactly match the newly validated result. Any conflict, or an already published snapshot, fails without force-pushing or changing the site. Production changes only after that pull request is merged and the ordinary main deployment succeeds.

Use the explicit historical-correction mode for a factual correction to an already published page; never regenerate the complete version:

pwsh tools/docs/snapshot.ps1 -Version 3.0.10 \
-CorrectPage scenarios/strings-and-casing.mdx

Deploy and roll back

.github/workflows/docs.yml validates every pull request. A successful main run uploads the complete Docusaurus output as one Pages artifact. After the build passes, automation stages the archive, checksum, and deployment manifest together in a draft docs-pages-candidate-v1-<run-id>-<attempt> prerelease. After the production smoke test passes, automation creates and publishes a separate immutable docs-pages-deployment-v1-<run-id>-<attempt> release. Failed or abandoned attempts therefore cannot become the current rollback source.

To restore a retained artifact, select its immutable deployment release and read the archive run ID and attempt from that release's manifest. These can differ from the deployment attempt after a failed-job rerun:

release_tag=docs-pages-deployment-v1-123456789-2
manifest=$(mktemp)
gh release download "$release_tag" \
--pattern 'deployment-*.json' \
--output "$manifest"
jq '{archiveRunId, archiveRunAttempt}' "$manifest"
gh workflow run docs.yml --ref main \
-f rollback_run_id="$(jq -r .archiveRunId "$manifest")" \
-f rollback_run_attempt="$(jq -r .archiveRunAttempt "$manifest")"

The rollback run verifies the retained artifact's custom domain, stable, historical, and preview roots, search data, redirects, sitemap, and link safety before redeploying it. It does not rebuild historical documentation.