From 95ddb6512751b1b68bff44442788f2ec1db239ee Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Sat, 4 Jul 2026 19:49:40 -0700 Subject: [PATCH 1/2] Add versioning and markdown-hygiene rules, enforce cspell en-US cspell: set language to en-US (a bare en accepts British spellings, silently passing the wrong spelling against the US-English rule); document the requirement in CODESTYLE and name it in the spec recurring.spelling assertion so it is machine-checkable. Verified 0 issues across all .md with the CI cspell image. Versioning (#228 s4): docs reference the 2-digit major.minor line, never a 3-digit build; issue-closing keywords go on the develop->main promotion PR (GitHub auto-closes only from the default branch). Markdown hygiene (#228 s7): URLs in fenced code blocks stay inline (reference links do not resolve there; exclude code from link-integrity checks), and removing a link also removes its orphaned reference definition. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Pieter Viljoen --- AGENTS.md | 4 +++- CODESTYLE.md | 2 +- cspell.json | 2 +- spec/project-types.json | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 657c00b..5115b57 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -53,6 +53,8 @@ The template uses a **two-phase model by default**: PRs build fast, publishing i - **Versioning is semantic and maintainer-controlled.** The `version` (major.minor) in [`version.json`](./version.json) is the version floor; NBGV appends the git height (the SemVer patch position) for the build version. `main` (the public release ref) builds a stable `X.Y.`; `develop` builds a prerelease `X.Y.-g`. The maintainer edits `version.json`; dependency bumps, CI/workflow fixes, and doc edits leave it untouched. - **Bump `version.json` only for functional changes, by maintainer instruction.** Raise the major/minor when the work being introduced warrants a new semantic version - a new feature, a behavior or API change, a breaking change - and do it in the PR that introduces that work (typically on `develop`). Do **not** bump on a fixed cadence or mechanically after a release. NBGV advances the patch (git height) on every commit automatically, so a release always gets a fresh build version without any `version.json` edit. - **No post-release bump; no develop-ahead requirement.** NBGV advances the patch (git height) on every commit, so a release always gets a fresh build version with no `version.json` edit and there is no `bump-version-X.Y` PR after a release. A `develop -> main` promotion carries whatever `version.json` is current: a promotion with a functional bump releases that new version on `main`; a maintenance-only promotion carries the unchanged `version.json` and `main` advances only its NBGV height. +- **Docs reference the 2-digit `major.minor` line, never a 3-digit build.** `README.md`, `HISTORY.md`, and release notes name the version as `Version 1.0` (the `version.json` floor); NBGV owns the patch/build position, so a concrete three-part number in a doc is both wrong (the real build height differs) and a maintenance trap. "Correcting" `1.0` to `1.0.0` is a defect, not a fix - it has blocked a release. +- **Issue-closing keywords (`Closes #N`, `Fixes #N`) go in the `develop -> main` promotion PR, not the feature -> develop PR.** GitHub auto-closes an issue only when the closing keyword merges into the **default branch** (`main`); a feature/develop PR merges into `develop`, so the keyword never fires there. Reference the issue in the develop PR body if useful, but put the actual closing keyword on the promotion PR. - **Wrapper repos that track an upstream release.** A repo wrapping an upstream release uses [`check-upstream-version-task.yml`](./catalog/snippets/workflows/check-upstream-version-task.yml): a resolver command prints the upstream version(s) as a **JSON object of `name -> version`**, written to a committed state file at the **repo root beside `version.json`** (default `upstream-version.json` - it is a build-input version source, not GitHub-platform config, so it does not belong under `.github/`), and opens a rolling App-signed bump PR per branch that the merge-bot auto-merges (`merge-upstream-version`). The object carries one key for the common single-version case (`{"version":"X"}`) or N keys for a wrapper that pins several upstream components (e.g. an image plus a companion tool), and the build reads each component by key; the bump PR's title/body name only the keys that actually moved. Call it from a scheduled entry-point workflow and matrix only the branches that ship the version (a CI-only version uses `["develop"]`). A merged bump ships on the **next publish**, not immediately - the two-phase latency tradeoff. ## Pull Request Title and Commit Message Conventions @@ -83,7 +85,7 @@ Clarify devcontainer setup steps in README ### Markdown -- **Reference-style links in human-facing docs.** Every markdown file **except** the agent-instruction files (`AGENTS.md` and `.github/copilot-instructions.md`, which optimize for agents and keep inline links) uses reference-style links only: every URI - internal path, anchor, external URL, or shield image - is defined at the **bottom of the file**, split into groups by type under an HTML-comment header (e.g. ``, ``, ``, ``) with each group's definitions alphabetized by reference name. No inline `[text](uri)` targets in prose. The one exception is the Table of Contents, whose entries stay inline anchor links (see Table of Contents below). +- **Reference-style links in human-facing docs.** Every markdown file **except** the agent-instruction files (`AGENTS.md` and `.github/copilot-instructions.md`, which optimize for agents and keep inline links) uses reference-style links only: every URI - internal path, anchor, external URL, or shield image - is defined at the **bottom of the file**, split into groups by type under an HTML-comment header (e.g. ``, ``, ``, ``) with each group's definitions alphabetized by reference name. No inline `[text](uri)` targets in prose. **A URL inside a fenced code block stays inline** - reference links do not resolve in code blocks, so do not extract it, and exclude fenced code from any link-integrity check (bracket literals like `["a", "b"]` otherwise read as undefined references). **Removing a link also removes its reference definition** - an orphaned definition fails the no-unused-defs rule. The one exception is the Table of Contents, whose entries stay inline anchor links (see Table of Contents below). - **Table of Contents.** Generate it with the Markdown All in One extension, which fills and auto-updates the list on save - leave the `## Table of Contents` heading for the extension to populate and never hand-author or hand-edit the entries. Exclude a heading with an inline `` marker on it (the badge/build header block and the `## Table of Contents` heading itself carry it); the workspace sets which heading levels appear. - One logical paragraph per line; no hard-wrap line-length limit. For an intentional hard line break within a block - stacked badges, status, or license lines - end the line with a trailing backslash (`\`); this explicit form is preferred over trailing whitespace and is not treated as a paragraph split. - Headings follow the title-case-with-short-bind-words rule from the PR-title section. diff --git a/CODESTYLE.md b/CODESTYLE.md index 6574d83..9f2b90d 100644 --- a/CODESTYLE.md +++ b/CODESTYLE.md @@ -34,7 +34,7 @@ Each language defines a **clean-compile** verification - the combination of buil These apply repo-wide, in every directory: 1. **Markdown linting**: All `.md` files must be lint-clean (error and warning free) via the VS Code `markdownlint` extension. [`.markdownlint-cli2.jsonc`][markdownlint-cli2] at the repo root is the single source of truth - the davidanson `markdownlint` extension and a command-line `markdownlint-cli2` run both read it, so the IDE and CLI stay in lock-step. Rules it deliberately disables (e.g. `MD013` line-length, `MD033` inline HTML) are **intentional** - do not "fix" them. Fix violations at the source rather than disabling rules. -2. **Spelling**: All spelling must be clean via the CSpell VS Code integration; words must be correctly spelled in **US English** (the repo-wide convention - see [AGENTS.md][agents]). Project-specific terms go in the workspace CSpell config. +2. **Spelling**: All spelling must be clean via the CSpell VS Code integration; words must be correctly spelled in **US English** (the repo-wide convention - see [AGENTS.md][agents]). The shared `cspell.json` sets `"language": "en-US"` so British spellings are flagged - a bare `"en"` accepts both US and British and silently passes the wrong spelling. Project-specific terms go in the workspace CSpell config. ## .NET diff --git a/cspell.json b/cspell.json index 0255e6b..b95a0db 100644 --- a/cspell.json +++ b/cspell.json @@ -1,6 +1,6 @@ { "version": "0.2", - "language": "en", + "language": "en-US", "ignorePaths": [ ".git/**", "reports/*/**", diff --git a/spec/project-types.json b/spec/project-types.json index 60ceae7..5a0925f 100644 --- a/spec/project-types.json +++ b/spec/project-types.json @@ -122,7 +122,7 @@ "checks": [ { "id": "recurring.comments", "verdict": "letter", "assert": "Comments are concise, only the non-obvious, no prose narration, and do not grow on re-edit.", "intentRef": "AGENTS.md#comments" }, { "id": "recurring.charset", "verdict": "letter", "assert": "ASCII only in agent-authored text: no em-dash (use a spaced hyphen), no smart quotes, no stray non-ASCII.", "intentRef": "AGENTS.md#character-set" }, - { "id": "recurring.spelling", "verdict": "letter", "assert": "US English spelling.", "intentRef": "AGENTS.md#pull-request-title-and-commit-message-conventions" }, + { "id": "recurring.spelling", "verdict": "letter", "assert": "US English spelling; the shared cspell.json sets language en-US (a bare en accepts British spellings too).", "intentRef": "AGENTS.md#pull-request-title-and-commit-message-conventions" }, { "id": "recurring.eol", "verdict": "letter", "assert": "Line endings follow .editorconfig (Windows+Linux friendly: CRLF default, LF for execution-sensitive files); edits preserve the file's endings.", "intentRef": "AGENTS.md#line-endings" } ] }, From 34bda4ddfb860180a4e17adbdf33992325eea126 Mon Sep 17 00:00:00 2001 From: Pieter Viljoen Date: Sat, 4 Jul 2026 19:53:44 -0700 Subject: [PATCH 2/2] Point recurring.spelling intentRef at the CODESTYLE spelling rule The assertion references the cspell en-US config, which is documented in CODESTYLE's Markdown and Spelling section, not the AGENTS PR-title section the intentRef named. Co-Authored-By: Claude Opus 4.8 (1M context) Signed-off-by: Pieter Viljoen --- spec/project-types.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/project-types.json b/spec/project-types.json index 5a0925f..6c3a5e4 100644 --- a/spec/project-types.json +++ b/spec/project-types.json @@ -122,7 +122,7 @@ "checks": [ { "id": "recurring.comments", "verdict": "letter", "assert": "Comments are concise, only the non-obvious, no prose narration, and do not grow on re-edit.", "intentRef": "AGENTS.md#comments" }, { "id": "recurring.charset", "verdict": "letter", "assert": "ASCII only in agent-authored text: no em-dash (use a spaced hyphen), no smart quotes, no stray non-ASCII.", "intentRef": "AGENTS.md#character-set" }, - { "id": "recurring.spelling", "verdict": "letter", "assert": "US English spelling; the shared cspell.json sets language en-US (a bare en accepts British spellings too).", "intentRef": "AGENTS.md#pull-request-title-and-commit-message-conventions" }, + { "id": "recurring.spelling", "verdict": "letter", "assert": "US English spelling; the shared cspell.json sets language en-US (a bare en accepts British spellings too).", "intentRef": "CODESTYLE.md#markdown-and-spelling" }, { "id": "recurring.eol", "verdict": "letter", "assert": "Line endings follow .editorconfig (Windows+Linux friendly: CRLF default, LF for execution-sensitive files); edits preserve the file's endings.", "intentRef": "AGENTS.md#line-endings" } ] },