Skip to content

Releases: L3DigitalNet/project-standards

v3.0.0 — adopt CLI, validate-id, frontmatter suite, pre-commit hooks

12 Jun 17:07
v3.0.0
e69ab6b

Choose a tag to compare

Migration from v2. This is a major release; adopt it deliberately. Full step-by-step runbook: UPGRADING.md.

Breaking changes requiring migration before re-pinning:

  • validate-id now runs in CI. Ids in old-style kebab format (e.g. restart-netbox-after-config-change) will fail the validate-id step. Run validate-id --fix --config .project-standards.yml to auto-regenerate non-ADR ids. ADR ids must be updated by hand to adr-{NNNN}-{repo-name}-{short-title}.
  • Re-pin both refs to @v3. Bump validate-markdown-frontmatter.yml@v2@v3 and set standards-ref: 'v3' together so the workflow definition and installed validator don't drift.
  • Remove any duplicate top-level frontmatter keys. parse_frontmatter now rejects them (previously the last value silently won).

Added

  • format-frontmatter command — reformats YAML frontmatter to canonical style (--write / --check). Applies key ordering, single-quote wrapping, typedoc_type rename, block-list style for non-empty arrays.
  • validate-references command — opt-in cross-file checker (set markdown.frontmatter.references.enabled: true). Enforces id uniqueness, referential integrity, supersede reciprocity, date ordering, ADR-number uniqueness. No-op until opted in.
  • project-standards fix subcommand — three-phase pipeline: format → regenerate ids → re-run full validate as postcondition.
  • project-standards validate runs all three validatorsvalidate-frontmatter, validate-id, and validate-references combined.
  • validate-id command — enforces {doc_type}-{6-char base36}-{slug} for standard doc types; adr-{NNNN}-{repo-name}-{short-title} for ADRs. Skips files with no frontmatter or a custom schema.
  • project-standards adopt <standard> CLI — materializes canonical artifacts into a consumer repo. Idempotent, path-safe, atomic writes. Supports all four standards, individually or together. fragment artifacts reported for manual merge, never written.
  • Per-standard adopt.toml manifests under src/project_standards/bundles/.
  • .pre-commit-hooks.yaml — six hooks: format-frontmatter-fix, format-frontmatter-check, validate-id-fix, validate-id-check, validate-frontmatter, validate-references.
  • standards/python-coding/ — Python Coding standard (in-development draft, version 0.4). Reference-only; unregistered; not adoptable via CLI.

Changed

  • Reusable workflow now also runs validate-id and validate-references (references is a self-gated no-op unless opted in).
  • Copy-adopt scaffolds relocated from README prose into packaged bundles; each standard's adopt.md now references project-standards adopt <id>.

v2.0.0

07 Jun 07:37
v2.0.0
3ece2c9

Choose a tag to compare

Migration from v1. This is a major release; adopt it deliberately:

  • Re-pin to @v2. Bump the reusable-workflow pin validate-markdown-frontmatter.yml@v1@v2 and set standards-ref: 'v2' (the workflow now defaults standards-ref to v2). The opt-in body linter lint-markdown.yml@v2 becomes available at this tag.
  • The validator CLI now requires Python 3.14+. Installing the project-standards package via uv tool install needs Python 3.14 (requires-python >=3.11>=3.14).
  • Copy-adopters, on re-sync only: the Python Tooling baseline is now 3.14, and the §15 CI template SHA-pins astral-sh/setup-uv (the old @v8 tag no longer resolves).
  • Doc deep-links moved into the per-standard bundles (standards/<name>/…) and meta/. The validation contract is unchanged — reusable-workflow names, the validate-frontmatter entry point, and the bundled schema path are identical — so a repo that passed on @v1 keeps passing after re-pinning to @v2.

Added

  • Python tooling stack adopted from standards/python-tooling-ssot-standard.md: uv_build backend, src/ layout, the validator moved to src/project_standards/ with the schema bundled inside the package, basedpyright (strict), branch coverage (fail_under = 85), and pip-audit. CI gate consolidated to check.yml.
  • Opt-in ADR section check (markdown.adr.require_sections). A new, default-off config flag makes the validator additionally assert that every doc_type: adr document contains the three MADR-required level-2 sections — ## Context and Problem Statement, ## Considered Options, ## Decision Outcome. The match is exact and case-sensitive; headings inside fenced code blocks (e.g. template snippets) and the optional MADR sections are correctly ignored. It lives under a separate markdown.adr config namespace, keeping the validator's frontmatter remit distinct. This repo enables it to dogfood the shipped ADR example. Additive (default off) → MINOR.
  • Opt-in Markdown body linting (Stack B). A new reusable workflow .github/workflows/lint-markdown.yml runs markdownlint-cli2 (via DavidAnson/markdownlint-cli2-action@v23) against the repo's published .markdownlint.json, finally executing the Markdown body rules that previously shipped as config with no runner. It is separate from validate-markdown-frontmatter.yml so frontmatter-only consumers never inherit a Node toolchain — opt in with uses: L3DigitalNet/project-standards/.github/workflows/lint-markdown.yml@v2. The action bundles its own Node runtime and auto-discovers .markdownlint.json, so no committed Node project is required. Also adds .markdownlint-cli2.jsonc (a local-runner config that honors .gitignore, so a bare npx markdownlint-cli2 matches CI) and a github-actions Dependabot entry to keep the action pins current. Additive — pin @v2.
  • Per-standard contract versions. Each standard now carries its own major.minor contract version, selected independently in .project-standards.yml (markdown.frontmatter.version, markdown.adr.version, python_tooling.version). A bundled registry (src/project_standards/schemas/registry.json) maps versions to schemas and records ADR→Frontmatter compatibility, which the validator now enforces. All keys are optional and default to today's behaviour — a config with no version: keys validates byte-identically. The Python Tooling internal-revision counter is replaced by contract version 1.0. Additive — see meta/versioning.md.
  • Markdown Tooling Standard (standards/markdown-tooling/). A new governed bundle documenting the recommended linting/formatting tools and settings for Markdown and the structured-text files Prettier handles: markdownlint (the seedable .markdownlint.json rule set + the reusable lint-markdown.yml@v2 workflow), Prettier (copy-adopt formatter config; no reusable workflow, DEC-9), and EditorConfig. Source-backed, parallel to the Python Tooling standard, and cross-linked from the tool-neutral Frontmatter standard. Adds a validated markdown_tooling contract version (1.0) to registry.json, recognized by the validator (markdown_tooling.version; unknown values exit 2) like python_tooling.version. Additive — MINOR.

Changed

  • Python Tooling standard — lint/format/type-check scope made explicit and flexible. The src/ requirement now governs the importable package/product only; repo tooling, scripts/, archived, and non-product Python may live outside src/ (still linted + formatted, not held to the strict-src/ typing bar). Directories owned by external programs (.claude/, .agents/, .codex/, .vscode/, .github/, .venv/, .continue/, …) are excluded from the toolchain (baseline gains [tool.ruff].extend-exclude). The full stack stays mandatory — only file scope is tunable. Loosening only; nothing previously-passing newly fails.
  • BREAKING (CLI consumers): requires-python raised >=3.11>=3.14. Installs via uv tool install now require Python 3.14+. The repo dogfoods its own Python Tooling baseline — .python-version, Ruff target-version, and BasedPyright pythonVersion all track 3.14.
  • BREAKING (Python Tooling standard, copy-adopted): default Python baseline raised 3.13 → 3.14. standards/python-tooling/ now scaffolds requires-python = ">=3.14", .python-version 3.14, Ruff target-version = "py314", and BasedPyright pythonVersion = "3.14" (3.14 is the current stable CPython release). Per meta/versioning.md, raising the required Python is MAJOR for a consumer that re-syncs scaffolds; the python_tooling contract-version label stays 1.0 (metadata-only, unenforced).
  • BREAKING (docs layout): standards/ restructured into one self-contained bundle per governing standardstandards/<name>/{README.md, adopt.md, templates/, examples/}. The flat top-level templates/ and examples/ trees were dissolved into the bundles, and versioning.md moved to meta/. Added standards/README.md (index + bundle anatomy) and per-standard adopt.md entries. Doc deep-links change; the consumer contract is unchanged — reusable workflow names, the validate-frontmatter package + entry point, and the bundled schema path are identical.
  • .markdownlint.json now states every rule explicitly (53 rules), not just the 13 overrides. A consuming repo that seeds its config from ours now gets deterministic linting that isn't shadowed by a contributor's personal editor/global markdownlint settings, and is pinned against default drift across markdownlint versions. Behaviour is identical to the previous sparse config in a clean environment (verified: the repo lints with zero errors either way, and the explicit config validates against the v0.40.0 config schema). One subtlety encoded: MD043 stays true (inert) rather than its schema-declared headings: [] default, which would otherwise demand zero headings (a tests/test_markdownlint_config.py guard pins that and the customisations). Because the explicit values track a markdownlint version, the markdownlint-cli2-action@v23 pin is load-bearing — re-verify on upgrade.
  • ADR Standard — body structure now lists three required sections, not four. standards/adr/README.md previously marked Consequences as a fourth required section; MADR 4.0 (and the repo's own templates and worked example) treat it as an optional ### Consequences sub-section of Decision Outcome. The required set is now the three MADR-required ## sections, matching the new opt-in validator check. Prose-only correction — no document that previously passed can newly fail.
  • .markdownlint.jsonMD024 (no-duplicate-heading) now false, matching MADR 4.0's own template/.markdownlint.yml (was { siblings_only: true }). MADR ADRs repeat option headings across the Considered Options and Pros and Cons sections; disabling the rule mirrors upstream tooling exactly. Strictly looser than before, so no previously-passing document can newly fail — additive.
  • ADR Standard — corrected the MADR acronym expansion from "Markdown Any Decision Records" to "Markdown Architectural Decision Records" in standards/adr/README.md. MADR 4.0 (2024-09-17) reverted the name to "Architectural"; the prior wording tracked the superseded MADR 3.x spelling.
  • ADR Standard — id now embeds the repo-name for cross-repo uniqueness. ADR ids become adr-NNNN-repo-name-short-title (e.g. adr-0001-homelab-use-postgresql-for-persistent-storage) so that an ADR referenced from another repository's related: list stays globally unambiguous across a fleet of repos. The filename keeps the adr-NNNN-short-title.md form — adr- prefix, no repo-name — making ADRs the one documented case where filename and id differ, consistent with the standard's existing "id is independent of file path" rule. Templates show the repo-name slot plus a save-as comment; the worked example and its two inbound related: references were updated to match. Deliberately diverges from MADR's bare-number filenames (MADR tooling is an optional convenience here, not a conformance target). Greenfield (no consumer ADRs exist yet) and filenames are not schema-validated, so nothing can newly fail — additive.
  • ADR Standard promoted to the source-checked documentation tier. standards/adr/README.md gains an Evidence convention, [Sxx] citations at the load-bearing MADR claims, a dated Source register, a Source coverage map, and a "Last source check" status banner — matching the Python/Markdown Tooling standards (previously it followed the narrative tier like the Frontmatter standard). MADR was re-verified against the live spec on 2026-06-07: 4.0.0 (2024-09-17) is the current release, and the acronym, the three required + five optional sections, the status vocabulary, and the MADR→canonical field mappings all match. Also refreshed stale updated/reviewed dates on ...
Read more