Document the no-issue PR exception - #47
Merged
Merged
Conversation
AGENTS.md said "For every change: open a GitHub issue first", and CONTRIBUTING.md said the same. We stopped meaning it — a one-bullet docs fix now goes straight to a PR labelled no-issue, with a NO-ISSUE trailer saying why. Leaving that undocumented means the next agent either files an issue for a typo or reads a no-issue PR as a rule violation. The exception touches three steps, not one: a no-issue PR also has no number for the branch name, and nothing to put in "Closes #N". All three are amended in both files, with the reasoning in CONTRIBUTING.md, which is where the why belongs. settings.yml gains a labels block naming no-issue, recorded but not applied — apply-settings.py reads only repository, branches and rulesets, so labels are still created per repo by hand. Documenting a key we don't act on yet is this file's stated convention; wiring it up is left to the issue. The exception explicitly does not cover changes to the rules themselves, which is why this one has an issue. Closes #46 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CgLE8cg9huy2EZnRoXhmwp
The comment said wiring up label reconciliation was tracked by #46 — the issue this PR was closing. That made it a dangling reference: on merge it would have cited a closed issue that never did the wiring, which is the bare-TODO-with-a-link that AGENTS.md section 4 exists to prevent. Label reconciliation is in scope for #46, so the fix is for this PR to stop closing it. The comment now says what remains and that #46 stays open until it lands. Refs #46 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CgLE8cg9huy2EZnRoXhmwp
4 tasks
gavinbee
added a commit
that referenced
this pull request
Sep 4, 2026
Closes #46 ## What & why [#47](#47) added the `labels:` block to `settings.yml` as a documented-but-inert key: it named the canonical set, but `apply-settings.py` read only `repository`, `branches` and `rulesets`, so `no-issue` still had to be created by hand in every repo. This wires it up — the rest of #46. `apply-settings.py` now creates a label that is missing and corrects one whose colour or description drifted. Labels do not depend on visibility, so private repos get them too. ## Two decisions worth reviewing **Reconciliation is additive.** A label named in `settings.yml` is created or corrected; labels the YAML does not mention are left alone. Repos carry GitHub's defaults plus the ones Dependabot creates (`dependencies`, `python`), and deleting a label strips it from every issue and PR that used it — not something a weekly scheduled job should do unprompted. `settings.yml` is the minimum set, not the whole set. Making it authoritative and pruning is a different and much more destructive script; if that is wanted, it should be its own decision. **Verification re-reads and compares.** `verify_labels` lists the labels again and diffs them against the YAML, rather than assuming the write took. That is deliberately *not* the shape of `verify_ruleset`, which only checks that a ruleset name exists — the subject of #45. Adding a second instance of that blind spot while #45 is open seemed like the wrong move. ## Normalisation Three ways a naive comparison would report false drift, all covered by tests: - GitHub stores colours as six lowercase hex digits with no `#`, so `#EDEDED` in YAML and `ededed` from the API are the same colour. - The API returns `null`, not `""`, for a label with no description; that compares equal to an absent description in YAML. - A YAML entry with no `color` does not blank the colour already on the repo. Label names are matched case-insensitively, since GitHub treats them that way — a `No-Issue` on the repo will not read as missing against a `no-issue` here. `list_labels` pages with `--paginate --jq '.[]'`, which emits one compact object per line; `--paginate` alone concatenates raw JSON arrays into something `json.loads` cannot read. ## Testing `ruff check .` clean. `pytest -q` — **22 passed**, up from 11; the 11 new tests cover `normalize_color` and `label_updates`, both pure. Dry-run against real repos, read-only, no writes: ``` swimblocks/deck-eval-gen: 12 labels; has no-issue = True -> 'no-issue' present; in sync swimblocks/.github: 9 labels; has no-issue = False -> would CREATE 'no-issue' ``` The first case is the useful one: `deck-eval-gen`'s `no-issue` was created by hand with `gh label create`, and the reconciler reads it as already in sync — so the normalisation and comparison agree with what GitHub actually stores. Once this merges, the next reconciler run creates `no-issue` everywhere and the per-repo `gh label create` step goes away. ## Checklist - [x] Linked the issue this PR closes - [x] Tests added/updated and passing - [x] `ruff check .` clean (Python repos) - [x] Docs/README updated if user-facing behaviour changed — `settings.yml`'s comment now says the block is applied, and describes the additive rule 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.
Refs #46 — deliberately does not close it. This lands the documentation half; label reconciliation in
apply-settings.pyis the remaining work on that issue.What & why
AGENTS.md§3 said "For every change: 1. Open a GitHub issue first", andCONTRIBUTING.mdsaid the same. We stopped meaning it — a change small enough to explain itself now goes straight to a PR labelledno-issue, with aNO-ISSUE: <reason>trailer. First used indeck-eval-gen#20.Undocumented, that leaves the rule and the practice disagreeing, so the next agent either files an issue for a typo or reads a
no-issuePR as a violation of the canonical guide.Three touch points, not one
The exception affects more than step 1 — a
no-issuePR also has no number for the branch name, and nothing to put inCloses #N:NO-ISSUE:trailer stands in forCloses #NAGENTS.mdgets the short form;CONTRIBUTING.mdgets a### The no-issue exceptionsection carrying the reasoning, since that file is where the why lives.The label
settings.ymlgains alabels:block namingno-issue— the canonical set, not yet applied.apply-settings.pyacts onrepository,branchesandrulesetsonly, so labels are still created per repo withgh label create(asdeck-eval-genneeded).Teaching the reconciler to apply the block is in scope for #46 and is why this PR leaves it open. An earlier revision of the comment pointed at #46 as the thing that would wire it up while this PR closed it — a dangling reference that would have cited a closed issue, exactly the bare-TODO-with-a-link that AGENTS.md §4 forbids. Fixed in 801effe.
Verified inert: the YAML parses,
repositoryandrulesetsare unaffected, and the script loads unchanged.Note on this PR
The new text says the exception does not cover changes to the rules themselves — a policy whose reasoning nobody can find gets re-litigated. So this change has an issue, deliberately.
The first commit's message still reads
Closes #46. Harmless:settings.ymlsetssquash_merge_commit_message: PR_BODY, so the squash commit takes this description, not the branch commits' messages.Testing
Docs plus one inert YAML block.
ruff check .clean,pytest -q11 passed — both unchanged, before and after the fixup.Checklist
ruff check .clean (Python repos)🤖 Generated with Claude Code