Repository navigation
feat(conventions): define .config/ concerns and wrap each tool in a task - #121
Merged
Merged
Conversation
Replace the `*` catch-all with the selective gate musher-dev/platform set for every repository: /.github/, /.repo/, the definitions every consumer inherits, and the agent merge guard. Pin, lock and vendored files stay unowned so bot pull requests merge on green CI. Refs #118 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add pass markers to validate.yml behind the CI_PASS_MARKERS kill switch, which merges unset. Each eligible job (repository_lint, checks, content, conventions, bundle) ends with .github/actions/sync-pass-marker, which saves a ci-pass-<key>-<run_id>-<attempt> cache entry on a same-repository pull_request or a push to main. On a same-repository pull_request, detect lists the markers on the PR ref and on main, re-proves each one against the API with .github/scripts/ci-pass.sh, and outputs passed_jobs. An eligible job skips when it is listed, and Validate / Required accepts that skip only when detect succeeded and listed the job. The key hashes the git object IDs of every path the job reads, from one table in the script. actionlint declares the variable, and Dependabot updates the new action's pins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Decision 0040 states the pass-marker design: the key, the record, the five checks detect proves, the excluded jobs and why, the security model (CI writes and reads, a local result never counts, the PR head is the gate with no merge queue), the kill switch and how to trial it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A repository that keeps one wrapper Taskfile per tool under taskfiles/tools/ had those files ignored: the launcher did not pass them to conftest, the Taskfile library did not count them, and CONF-04 did not take them as callers of a .config/ file. Each now reads that one extra directory level, so a config named only by its tool's wrapper has a caller, and a task call into a wrapper resolves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every tool the Taskfiles and git hooks run now has a wrapper in taskfiles/tools/<tool>.Taskfile.yml, included flattened and internal as tool:<tool>[:<detail>]: the only place its binary, config path, severity flags and default file set are written. Area fragments name every public task under their file (secrets:scan, schemas:*, generate*, prose:lint, checks:compile, cli:invariants, cli:classify); content.Taskfile.yml is split into schemas, generate and prose. `lint` now runs every linter and format check, and `lint:fix` every fixer; a fixer ends in `:fix`, so checks:fmt becomes checks:fmt:fix and checks:fmt:check stays the check. Deterministic wrappers fingerprint their sources, so a second `task check` skips unchanged gates (6m05s, then 19s here); `task --force check` reruns them all, and CI starts from a fresh checkout. A run given files goes to an uncached tool:<tool>:files task, so the hooks always run and never record a fingerprint. The secret scan, online zizmor, Spectral, invariants and the bundle stay uncached. Lefthook jobs run tasks, passing staged files after `--`, which Task hands on shell-quoted. The commit-msg job still runs committed directly, since COMMIT-03 reads that command. CI, the rules, CONTRIBUTING and AGENTS.md use the new task names. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A repository that keeps one wrapper Taskfile per tool under taskfiles/tools/ had those files ignored: the launcher did not pass them to conftest, the Taskfile library did not count them, and CONF-04 did not take them as callers of a .config/ file. Each now reads that one extra directory level, so a config named only by its tool's wrapper has a caller, and a task call into a wrapper resolves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Define a .config/ concern in EC-0011: it names the files its tool reads (actions, commits, docker, json, markdown, openapi, opentofu, python, rego, shell, sql, toml, typescript, yaml), or, for a tool that reads every file, what it looks for (prose, security, spelling); mise keeps mise/. State the boundary: .config/ is repository-wide quality configuration, and a product's language toolchain stays with it. - CONF-14: a .config/ subdirectory is a registered concern. - CONF-15: a known tool's configuration sits in its tool's concern. Move this repository's Vale config to .config/prose/vale.ini and point the editor, docs, COPY examples and COPY-01's message at it. Index the editor as a caller in .config/README.md, and drop two settings that only restated or loosened the preset: typos' "musher" entry and yamllint's comments overrides. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add EC-0044 Tool strictness: a tool's configuration starts from the tool's own preset and states every departure with a reason. - CONF-16: yamllint extends default. - CONF-17: markdownlint keeps its default rules on. - CONF-18: pyright and basedpyright check at strict or above. - CONF-19: a tsconfig.json turns strict on. - CONF-20: Biome keeps its recommended rules on. - CONF-21: a gitleaks [extend] keeps the default rules. - CONF-22 (review): a tool's warnings fail the gate that runs it. - CONF-23 (review): every departure from a preset has its reason. The hadolint and zizmor floors stay in IMAGE-07 and GHA-33. The runner now passes yamllint, markdownlint YAML, gitleaks and pyproject.toml to conftest, and parses markdownlint JSON, tsconfig.json, Biome and pyrightconfig.json with jsonnet first (decision 0015). Decision 0038 records the concern vocabulary and the floor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add COMM-09 (no `*`, `**` or `/**` line with an owner; a waiver in
.repo/conventions.toml is the allowlist) and COMM-10 (a root-anchored
literal path names a file or directory that exists) to EC-0036, proposed
at warning since 0.9.2. Owner resolution and write access need GitHub's
API and are left to `gh api repos/{o}/{r}/codeowners/errors`.
Fixtures whose layout drops platform-api/ get a CODEOWNERS that matches
it, and COMM-08's example no longer shows a catch-all.
Refs #118
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # docs/decisions/README.md # docs/repository.md
# Conflicts: # README.md
EC-0015 now describes four layers: rules in .config/<concern>/, one internal wrapper per tool in taskfiles/tools/<tool>.Taskfile.yml, area fragments in taskfiles/<area>.Taskfile.yml, and the verbs at the root. It also says what a cached task lists as sources, and splits a wrapper into a cached tool:<tool>:all and an uncached tool:<tool>:files run. - TASK-25: a wrapper is included with flatten and internal, and its tasks are named tool:<tool> or tool:<tool>:<detail>. - TASK-26: a wrapped tool's binary runs only in its wrapper. - TASK-27: a flattened fragment's public tasks are named under its area. - TASK-28: every sources glob matches something the repository holds. - HOOKS-15: a lefthook job runs a task, not a wrapped tool; committed in commit-msg stays COMMIT-03's. - TASK-20 (fix): no longer forbids internal on a tool wrapper's include; its internal message says so. - Wrappers are fragments for TASK-18, TASK-19, TASK-21 and TASK-22. Decision 0038 records why. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # docs/decisions/README.md
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
.config/gets a defined key. A concern names the files a tool reads (actions,markdown,yaml, …).A tool that reads every file is named for what it looks for (
prose,security,spelling).CONF-14 checks that a subdirectory is a registered concern. CONF-15 checks that a known tool sits in its own
concern. EC-0011 now says what
.config/is for: repository-wide quality configuration. A product's languagetoolchain configuration stays with the product. Vale moves from
markdown/toprose/.Tool strictness floors (new EC-0044, CONF-16 – CONF-23). Each tool starts from its maintained preset:
default;default;strict,recommendedorall;strict;recommended;Two review requirements add that warnings fail the gate, and that every departure from a preset carries its
reason.
A tool-wrapper task layer (TASK-25 – TASK-28, HOOKS-15, TASK-20 relaxed).
.config/holds the rules.taskfiles/tools/<tool>.Taskfile.ymlis the one internal place a binary, its--configand its severityflags appear.
sourcesglob that matches nothing. Such a task stays "up to date" forever.This repository adopts all of it.
secrets,schemas,generateandprosesplit out;checks:check→checks:compile;invariants/classify→cli:*;:fix.sources(checksum). The sources include the tool's config,mise.lockand the Taskfiles. A secondtask checkwith nothing changed takes about 20 s instead of about6 min.
task --force checkreruns everything.A CI pass-marker pilot (decision 0040),
off by default.
main, can skip.detectre-proves each one: key, ref, run, and that the workflow and actiontrees are unchanged.
push,merge_groupor forks.CI_PASS_MARKERS, which merges unset, so CI behaves exactly asbefore.
CODEOWNERS selective gate (feat: a shared CODEOWNERS check, and drop this repo's
*catch-all #118)./.github/,/.repo/,/engineering-conventions/definitions/and two.claudetrust paths.
Fixes #118 in part: the offline checks and this repository's file. Owner resolution and write access need the
GitHub API, so they stay on the issue.
Decisions 0038 (concerns and strictness),
0039 (tool wrappers and caching) and
0040 (pass markers) record the reasoning.
Consumer impact
.config/prose/vale.iniwarning→feat(a patch in 0.x). TASK-20 relaxed →fix.proposedatwarning..config/bucket outside the vocabulary, a Vale config inmarkdown/, a*catch-all in CODEOWNERS, and a fragment task named outside its area.
tsconfig.json,pyrightconfig.json,biome.json(c)and markdownlint JSON. A filejsonnet cannot parse gets a PARSE finding, as
devcontainer.jsonalready does.sinceis0.9.2, because release PR chore(release): release 0.9.2 #116 is still open. If chore(release): release 0.9.2 #116 merges first, these move to0.9.3.AI usage
Test plan
task --force checkpasses locally:conventions:selfreports "No findings." from both runners;updated.
task generate;generate:checkis clean.task checkskips unchanged gates;.mdreruns only markdownlint, typos and Vale;mise.lockinvalidates every cached gate;task tool:yamllintis refused as internal.lefthook run pre-commitwith staged files whose names need quoting.ci-pass.sh:keymode tests pass;provepasses 12 scenarios against a mockgh, including an edit-then-revert forgery, which it refuses.CI_PASS_MARKERS=onand follow decision 0040's "Trying it" steps.Follow-on issues
pull_request_targetjob, which the zizmor gate flags.
comments/,positioning/andpython/buckets;.config/;BEGIN_COMMIT_OVERRIDE
feat(conventions): key .config/ concerns on the files a tool reads
feat(conventions): set a strictness floor for tool configuration
feat(conventions): add TASK-25 to TASK-28 and HOOKS-15 for tool wrappers
fix(checks): let a tool wrapper's include set internal under TASK-20
feat(checks): read the Taskfiles in taskfiles/tools/
feat(conventions): forbid a CODEOWNERS catch-all and dead paths
fix(conventions): name .config/prose/vale.ini in the COPY message
END_COMMIT_OVERRIDE
🤖 Generated with Claude Code