feat: sync issue template tags/categories from scripts.json - #65
Merged
Conversation
Category and tag lists were hardcoded in four places (validate_scripts.py, issue_to_scripts.py, and both issue form templates) and had already drifted once. scripts.schema.json is now the single canonical source: tags and categories are auto-promoted from actual usage in scripts.json (tags are a pure usage snapshot; categories are monotonic add-only since they drive the site's nav tabs and shouldn't vanish just because they're briefly empty). tools/sync_issue_template_options.py regenerates the schema's examples and both templates' marker-bounded option blocks, with --check/--write modes and tests. A new "New Category" free-text field mirrors the existing "Additional Tags" field, since the dropdown previously had no way to introduce a new value. CI (validate-issue-templates.yml) self-heals same-repo branches on push, gates PRs with --check, and — since GITHUB_TOKEN can never push to a fork — posts a sticky comment with the diff and self-resolve instructions on fork PRs via a carefully scoped pull_request_target job. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
No lock/requirements file exists in this repo for setup-uv to key a cache on, so it was warning that the cache could never invalidate. There's nothing to actually cache (the tools/*.py scripts are stdlib-only), so disable it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Same fix as the issue-template workflow — no lock/requirements file exists for setup-uv to key a cache on, so it was warning the cache could never invalidate. Nothing to cache here either. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Completes the same fix for gh-pages.yml and script-submission.yml — no lock/requirements file exists for setup-uv to key a cache on in this repo, so it was warning the cache could never invalidate. Nothing to cache here. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Plain sorted() put 'GPS & Mapping' before 'Games & Fun' (uppercase 'P' < lowercase 'a' in ASCII) — not the order a human reading the dropdown would expect. Also fixes a related bug the case-insensitive change would otherwise introduce: the schema-vs-current comparisons re-sorted both sides before comparing, which hid ordering drift in scripts.schema.json's own examples arrays (they're supposed to already hold the canonical sorted list, so a stale on-disk order needs to be caught, not normalized away). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Removing a stale, currently-unused category previously meant hand-editing scripts.schema.json's examples array directly. --prune-categories overrides the normal monotonic-add-only behavior for a single invocation, removing categories with zero current scripts.json entries from the schema and both templates in the same pass as a normal --write. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
4 tasks
pfeerick
added a commit
that referenced
this pull request
Aug 4, 2026
…#69) The push job in validate-issue-templates.yml was supposed to self-heal bot-created branches, but script-submission.yml's branch-creating push uses the default GITHUB_TOKEN, and GitHub Actions suppresses new workflow- triggering events (including push) for GITHUB_TOKEN-authored pushes — the same rule that prevents the sync job's own corrective commits from causing an infinite loop also silently prevented it from ever running in the first place for these branches. Confirmed against two real submissions (#67, #68): both landed with a permanently-failing check and no auto-fix. Rather than fight the retrigger suppression, run the sync script directly in script-submission.yml before committing, so the schema/templates are already correct in the very first commit of every bot-generated PR. The push job in validate-issue-templates.yml remains as a backstop for genuine human-authored pushes (e.g. direct-edit PRs), which aren't subject to this suppression. Also fixes a stale error-comment string referencing the category enum check that was removed in #65. Co-authored-by: Peter Feerick <5500713+pfeerick@users.noreply.github.com> Co-authored-by: Claude Sonnet 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.
Summary
categoryandtagswere hardcoded in four separate places (validate_scripts.py,issue_to_scripts.py, and both issue form templates) and had already drifted once (e.g. thebatterycheckbox was added to only one template).scripts.schema.jsonis now the single canonical source, withtools/sync_issue_template_options.pyregenerating both templates' marker-bounded option blocks and the schema'sexamplesfields from actual usage inscripts.json.unused_categoriesCI notice. A new--prune-categoriesflag lets a maintainer deliberately remove currently-unused categories on demand (--check --prune-categoriesto preview,--write --prune-categoriesto apply), rather than requiring a hand-edit of the schema JSON.issue_to_scripts.pyno longer hard-rejects unrecognized categories..vscode/settings.jsonassociatesscripts.schema.jsonfor editor-time validation/autocomplete onscripts.json.str.casefold) so e.g. "Games & Fun" sorts before "GPS & Mapping" as a human would expect, rather than plain ASCII order.CI (
validate-issue-templates.yml)check(PRs): read-only--check, gates on drift.sync(push): self-heals same-repo branches by running--writeand committing the correction back — this is what lands the fix directly in the PR that introduced a new tag/category, including direct-edit PRs that never went through an issue form. UsesGITHUB_TOKEN, so it can't push to forks and (deliberately) can't trigger further workflow runs, avoiding recursion.suggest-fix-for-fork-prs(pull_request_target, fork PRs only):GITHUB_TOKENcan never push to a fork under any trigger, so instead this safely computes the same fix (checks out the base branch's trusted script, only ever treats the PR'sscripts.jsonas inert data, never executes anything from the fork) and posts it as a sticky PR comment with both resolution paths — a maintainer pulling the branch in, or running--writelocally and committing it.enable-cache: falseadded to theirsetup-uvsteps — there's no lock/requirements file for uv to key a cache on, so it was warning that the cache could never invalidate.Test plan
uv run tools/test_sync_issue_template_options.py— 10 unit tests covering multi-region splicing, monotonic category retention vs. tag pruning,--prune-categories, drift detection, and idempotencyuv run tools/validate_scripts.py --scripts-json scripts.json— 58 entries valid, no new errorsuv run tools/sync_issue_template_options.py --check— in syncissue_to_scripts.pyfixture runs: dropdown-only, free-text-only, both (free text wins), neither (correctly rejected)pull_request_targetsticky-comment job against a real fork PR (can't be simulated locally)🤖 Generated with Claude Code