Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
25d5ea2
docs(repo): say release-please assigns commits by path, not by scope
justinmerrell Sep 13, 2026
4c5d668
docs(repo): ADR 0021 organize the repository around the family versio…
justinmerrell Sep 13, 2026
9f6338d
docs(repo): ADR 0022 the Musher Document Core Specification
justinmerrell Sep 13, 2026
76accb6
docs(repo): ADR 0023 published bytes are immutable release assets
justinmerrell Sep 13, 2026
b1a853d
ci(repo): accept the core scope
justinmerrell Sep 13, 2026
bf52b99
refactor(tools): group the tooling by concern
justinmerrell Sep 13, 2026
c6aa25f
docs(tools): stop saying the commit scope selects a release train
justinmerrell Sep 13, 2026
0ac1f07
fix(tools): read every repository path from the layout module, and fa…
justinmerrell Sep 13, 2026
85062d5
ci(tools): hold accepted ADRs to link-target-only edits
justinmerrell Sep 13, 2026
eebede6
refactor(conformance): colocate each corpus with the family version i…
justinmerrell Sep 13, 2026
373cbb5
refactor(repo): name the repository musher-dev/specifications and the…
justinmerrell Sep 13, 2026
0b1a63d
feat(tools): support a schema-less base family
justinmerrell Sep 13, 2026
fd1c8e3
feat(core): extract the Musher Document Core Specification (prose and…
justinmerrell Sep 13, 2026
fa81c00
feat(tools): run conformance against the core registry and check clau…
justinmerrell Sep 13, 2026
262e680
fix(core): align core prose with its corpus and record the generaliza…
justinmerrell Sep 13, 2026
bd6d750
docs(repo): cite the regrouped tool paths in ADRs 0021 and 0022
justinmerrell Sep 13, 2026
aaee323
fix(tools): fail check:adr when git fails instead of skipping ADR-04
justinmerrell Sep 13, 2026
dfae75a
build(repo): build schema bundles instead of committing them
justinmerrell Sep 13, 2026
b753456
docs(repo): name the bot user id and the App's permissions in ADR 0023
justinmerrell Sep 13, 2026
f6b0c7c
feat(tools): publish from verified immutable release assets against l…
justinmerrell Sep 13, 2026
ef93700
ci(repo): release through draft immutable GitHub Releases and deploy …
justinmerrell Sep 13, 2026
15d0e4d
docs(repo): make the repository navigable from its README
justinmerrell Sep 13, 2026
e20c187
docs(repo): rewrite contributor, governance and publication guidance …
justinmerrell Sep 13, 2026
75ec4a5
docs(repo): generate the ADR index, map the tooling, and close the na…
justinmerrell Sep 13, 2026
6f79318
fix(tools): close the release gaps the readiness review found
justinmerrell Sep 13, 2026
3f94452
docs(repo): make the guidance match the release pipeline and close na…
justinmerrell Sep 13, 2026
f8dfe20
docs(repo): reconcile the tooling map and ADR index with the release …
justinmerrell Sep 13, 2026
448c71b
test(tools): give the shallow-clone ledger test room on a loaded runner
justinmerrell Sep 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
12 changes: 7 additions & 5 deletions .config/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ container, it goes in here.
Policy and rationale:
[`docs/adr/0011-tooling-configuration-layout.md`](../docs/adr/0011-tooling-configuration-layout.md).
Enforcement: `task check:config` (CFG-01..CFG-08), implemented in
[`tools/src/config.ts`](../tools/src/config.ts).
[`tools/src/policy/config.ts`](../tools/src/policy/config.ts).

The convention is shared with `musher-dev/development-container` and
`musher-dev/platform`. Keeping the three aligned is the point: a contributor
Expand All @@ -31,9 +31,11 @@ Call sites are [`Taskfile.yml`](../Taskfile.yml), [`taskfiles/`](../taskfiles/),
`.config/lefthook.yml`, and [`.github/workflows/`](../.github/workflows/).
Tool versions are pinned in
[`tools/package.json`](../tools/package.json) for anything installed by Bun,
and in [`.devcontainer/mise.toml`](../.devcontainer/mise.toml) for the rest —
with the CI workflow mirroring the same version, because CI is not a mise host
and does not read that file.
and in [`.devcontainer/mise.toml`](../.devcontainer/mise.toml) for the rest.
CI is not a mise host and does not read that file. The CI workflows pin the
tools they install themselves, Task and actionlint, to the same versions.
ShellCheck is the exception: CI uses the copy preinstalled on the runner image,
which is not pinned and can differ from the container's.

## Rules

Expand Down Expand Up @@ -69,7 +71,7 @@ whole directory exists to prevent, and it is one command to rule out.
| `LICENSE`, `NOTICE` | Repo root | GitHub detects a licence at the root only, and Apache-2.0 expects NOTICE to travel with the work |
| `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md` | `.github/` | Community health files, which GitHub resolves from there |
| `biome.json`, `tsconfig.json` | `tools/` | They belong to the `tools/` package and are resolved by it — a package's own config, not a repo-level one |
| `catalog.json`, `published.json` | Repo root | Published data artifacts, not tool configuration |
| `published.json` | Repo root | A published data artifact, not tool configuration. The catalog is build output under `dist/`, never tracked |
| `mise.toml`, `devcontainer.json` | `.devcontainer/` | They provision the environment rather than checking the code |
| `dependabot.yml`, `release-please/`, `rulesets/`, `workflows/` | `.github/` | GitHub reads these from fixed locations |

Expand Down
5 changes: 4 additions & 1 deletion .config/actions/actionlint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ self-hosted-runner:
# is exhaustive on purpose -- with it, `vars.TYPO` is a build failure instead of
# an empty string that silently changes what a job does. Add a name here in the
# same change that adds the variable to the repository settings.
config-variables: []
config-variables:
# The release GitHub App's id. Its private key is the RELEASE_APP_PRIVATE_KEY
# secret. Read by release.yml and release-ledger.yml.
- RELEASE_APP_ID
20 changes: 11 additions & 9 deletions .config/lefthook.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
# Keep min_version in step with .devcontainer/mise.toml.
min_version: 2.1.10

# Standard `**` semantics. Under the default gobwas matcher `**/*.md` needs at
# least one directory, so a root README.md or tools/biome.json never matched
# the globs below. With doublestar, `*` stops at `/`: a glob meant for any
# depth says `**/`.
glob_matcher: doublestar

pre-commit:
parallel: true
jobs:
Expand Down Expand Up @@ -42,12 +48,8 @@ pre-commit:
glob: '**/*.md'
run: task check:md

- name: drift
glob: 'specifications/**/*.schema.json'
run: task check:drift

- name: shell
glob: '*.sh'
glob: '**/*.sh'
run: task check:shell:files -- {staged_files}

- name: workflow
Expand All @@ -71,11 +73,11 @@ commit-msg:
printf " Got: %s\n" "$first_line" >&2
printf "%s\n" "" >&2
printf "%s\n" " Types: feat, fix, chore, docs, style, refactor, perf, test, ci, build, revert" >&2
printf "%s\n" " Scopes: component, blueprint, listing, conformance, tools, ci," >&2
printf "%s\n" " devcontainer, docs, repo, deps" >&2
printf "%s\n" " Scopes: core, component, blueprint, listing, conformance, tools, ci," >&2
printf "%s\n" " devcontainer, docs, repo, deps, deps-dev" >&2
printf "%s\n" "" >&2
printf "%s\n" " The scope drives release-please. feat(component): cuts component/v1.x.0;" >&2
printf "%s\n" " an unscoped feat: releases nothing." >&2
printf "%s\n" " release-please picks the release from the paths a commit changes, not" >&2
printf "%s\n" " its scope: feat/fix/docs under specifications/<family>/ releases it." >&2
exit 1
fi
' -- {1}
Expand Down
6 changes: 3 additions & 3 deletions .config/spelling/cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@
"**/node_modules/**",
"site/**",
"tools/bun.lock",
"**/schemas/dist/**",
"dist/**",
// The dictionary itself, and a licence whose wording is not ours to edit.
".config/spelling/**",
"LICENSE",
// Checksums and opaque identifiers, not words.
"published.json",
// Conformance vectors are chosen for their bytes, including deliberate
// misspellings and malformed input. Correcting them would destroy the test.
"conformance/**/case.yaml",
"conformance/**/tree/**"
"specifications/*/v*/conformance/**/case.yaml",
"specifications/*/v*/conformance/**/tree/**"
],
"ignoreRegExpList": [
"/\\b[0-9a-f]{7,64}\\b/",
Expand Down
1 change: 1 addition & 0 deletions .config/spelling/musher.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ deserialisation

# --- Names and acronyms ------------------------------------------------------
bluemonday
CNAB
Consolas
Pydantic
Segoe
Expand Down
20 changes: 11 additions & 9 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// musher-dev/spec dev container.
// musher-dev/specifications dev container.
//
// Trimmed from the musher-dev/development-container template. This repository
// bundles and validates JSON — it builds no images, runs no services, and needs
Expand All @@ -9,7 +9,7 @@
// Kept: Bun and Node for tools/, Task as the runner, shellcheck for the
// devcontainer scripts, gh for release work.
{
"name": "Musher Specification",
"name": "Musher Specifications",

// Pinned to the LTS, not the floating :ubuntu tag — that one rolls to interim
// releases some upstream Features do not support.
Expand Down Expand Up @@ -145,19 +145,21 @@
},

// Authoring aid: bind the LOCAL bundles, not the published URLs, so
// examples and fixtures are checked against the working tree.
// examples and fixtures are checked against the working tree. They are
// build output under dist/: post-create runs `task bundle`, and so
// must you after editing schemas/src.
"yaml.schemas": {
"./specifications/component/v1/schemas/dist/component.schema.json": [
"./dist/component/v1/component.schema.json": [
"specifications/component/v1/examples/*.yaml",
"conformance/component/v1/**/case.yaml"
"specifications/component/v1/conformance/**/case.yaml"
],
"./specifications/blueprint/v1/schemas/dist/blueprint.schema.json": [
"./dist/blueprint/v1/blueprint.schema.json": [
"specifications/blueprint/v1/examples/*.yaml",
"conformance/blueprint/v1/**/case.yaml"
"specifications/blueprint/v1/conformance/**/case.yaml"
],
"./specifications/listing/v1/schemas/dist/listing.schema.json": [
"./dist/listing/v1/listing.schema.json": [
"specifications/listing/v1/examples/*.yaml",
"conformance/listing/v1/**/case.yaml"
"specifications/listing/v1/conformance/**/case.yaml"
]
},

Expand Down
1 change: 0 additions & 1 deletion .devcontainer/scripts/lib/motd.sh
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ _motd_quickref() {
echo ""
echo " ${_BOLD}Quick Reference${_RESET}"
echo " ${_DIM}${sep}${_RESET}"
echo " docker compose -f .devcontainer/compose.yaml up -d / down / logs -f"
echo " git status / log / diff"
echo " task Task runner"
echo " claude Claude Code AI"
Expand Down
18 changes: 18 additions & 0 deletions .devcontainer/scripts/post-create.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,23 @@ install_spec_tools() {
}
}

# Builds the schema bundles into dist/, which the editor's yaml.schemas
# bindings in devcontainer.json point at. Bundles are build output and not
# tracked, so a fresh container has none until this runs. Best-effort: a
# failure leaves the container usable, and `task bundle` recovers.
#
# Outputs:
# Writes progress to stderr via log()
build_schema_bundles() {
command -v task >/dev/null 2>&1 || return 0
command -v bun >/dev/null 2>&1 || return 0
log "Building schema bundles (task bundle)..."
(cd "${SCRIPT_DIR}/../.." && task bundle >/dev/null) || {
log "WARNING: task bundle failed; run it once the container is up"
return 0
}
}

# Entry point: runs the full post-create setup sequence.
#
# Arguments:
Expand All @@ -75,6 +92,7 @@ main() {
install_lefthook_hooks
# --- Repo-specific setup ---
install_spec_tools
build_schema_bundles
if ((status != 0)); then
log "Post-create setup completed with MISSING TOOLS (see the ✗ lines above)"
return "${status}"
Expand Down
9 changes: 2 additions & 7 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,11 @@
*.ts text eol=lf
*.sh text eol=lf

# Generated bundles are reviewed as text but should not inflate diff stats.
specifications/*/v*/schemas/dist/*.json linguist-generated=true

*.png binary
*.jpg binary
*.ico binary

# Two parser fixtures are *about* their bytes, so normalization would quietly
# destroy what they test. The CRLF case asserts CRLF endings are accepted; the
# `* text=auto eol=lf` rule above rewrote it to LF, and it passed while testing
# nothing. `-text` opts both out of every normalization.
conformance/component/v1/parser/013-crlf-line-endings/case.yaml -text
conformance/component/v1/parser/012-byte-order-mark/case.yaml -text
specifications/core/v1/conformance/parser/013-crlf-line-endings/case.yaml -text
specifications/core/v1/conformance/parser/012-byte-order-mark/case.yaml -text
15 changes: 9 additions & 6 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
# evaluated per changed file. Listing a path here is therefore a commitment to
# review every change to it — not a label.
#
# Invariants. Each one silently breaks the gate rather than failing loudly, so
# `task check:rulesets` enforces all of them:
# Invariants. Each one silently breaks the gate rather than failing loudly.
# `task check:rulesets` checks only part of this list: RUL-05 rejects a `*`
# catch-all, and RUL-06 checks each owner's syntax and that every root-anchored
# literal path exists. The rest are review obligations:
#
# - NEVER add a `*` catch-all. It makes every pull request code-owned and
# re-imposes the blanket gate this file exists to retire.
Expand All @@ -38,10 +40,11 @@
# CODEOWNERS entry naming a nonexistent user silently disables the review gate
# it appears to configure.
#
# What is deliberately NOT owned: `specifications/` and `conformance/` carry the
# normative contract, and GOVERNANCE.md still requires maintainer approval for a
# breaking change to either. That obligation is now social rather than
# mechanical — ADR 0015 records the trade and why it was accepted.
# What is deliberately NOT owned: `specifications/` carries the normative
# contract, every family's prose, schemas and conformance corpus, and
# `conformance/` holds only the fixture-format README. GOVERNANCE.md still
# requires maintainer approval for a breaking change. That obligation is social
# rather than mechanical — ADR 0015 records the trade and why it was accepted.

# The gate cannot be changed unreviewed. GitHub's own recommendation: protect
# CODEOWNERS with CODEOWNERS, and protect the ruleset the same way — between
Expand Down
Loading
Loading