docs(contributing): add issue templates and define the labeling standard #124

Merged
rootiest merged 3 commits from docs/issue-templates-and-labels into main 2026-09-01 03:36:03 +00:00
Owner

Summary

Follows the PR-template work in #123 with the two conventions it left open: a
template for issues, and a rule for labeling both issues and PRs.

  • Three issue templates under .github/ISSUE_TEMPLATE/, beside the PR
    template so the GitHub mirror offers the same set. bug.yml is a Gitea
    issue form rather than markdown — version, OS, area, reproduction,
    expected and actual behavior are required fields, so an unactionable bug
    report can't be submitted at all. feature.md and docs.md are
    comment-guided markdown in the same house style as
    .github/PULL_REQUEST_TEMPLATE.md, since what they ask for is open-ended
    prose. config.yml keeps blank issues enabled for what the three don't
    cover and links the canonical tracker plus the contributing and
    customization docs.
  • A labeling standard: every issue and PR carries exactly one Kind/ and
    at least one Area/. CONTRIBUTING.md now documents all 33 labels, which
    groups are exclusive, and who applies what.
  • 15 new labels created in Gitea (see below) — the stock set couldn't
    describe a refactor or a chore, and had no way to say which subsystem an
    item touched.
  • All 33 labels replicated on the GitHub mirror, and the templates fixed
    so they actually work there — see Mirror parity.
  • Two new CONTRIBUTING.md sections, ## Issues and ## Labels, plus a
    labeling bullet in the standing PR rules and TOC entries for both.

Why

Issues had no template at all, so a report arrived in whatever shape the
reporter chose — most often missing the fish version, a reproduction, or the
full error text, which is what actually stalls a bug. And the stock Gitea
label set was present but unused, because nothing said when to apply it.

How it works

bug.yml carries an Area dropdown mirroring the Area/ labels. That
exists because no forge maps a form field to a label, and contributors
without push access can't set labels themselves — so the dropdown is how a
reporter tells you, and a maintainer translates it at triage. The rest of the
maintainer-applied groups (Priority/, Reviewed/, Status/) are documented
as exactly that, so reporters aren't expected to touch them.

feature.md carries ## Acceptance criteria, the issue-side counterpart to a
PR's ## Verification — a definition of done agreed before the work starts
rather than argued about after. docs.md insists on naming the
docs/manual/** source rather than the generated page, since a fix applied to
docs/fish-config.md is overwritten by the next CI run.

Labels added

Created in Gitea as part of this change (33 total now, up from 18):

  • Kind/Refactor, Kind/Chore, Kind/Performance — the group now maps
    one-to-one onto the Conventional Commits types already in use, so a PR's
    label and its title agree.
  • A non-exclusive Area/ group over the ten subsystems: Functions,
    Completions, Config, Docs, Tests, CI, Integrations,
    Prompt & Theme, Components, Scripts.
  • good first issue and help wanted, unscoped on purpose. They'd fit
    naturally under Status/, but that group is exclusive and an issue is often
    both blocked and open for someone to pick up; outside the group they can
    coexist with a real status.

Mirror parity

GitHub reads the same .github/ISSUE_TEMPLATE/ files, and its schema differs
from Gitea's in two places that both fail silently:

  • config.yamlconfig.yml. Gitea accepts either
    (modules/structs/issue.go:267), GitHub only recognizes config.yml. Under
    the old name the mirror's chooser would have shown neither the contact links
    nor the blank-issue setting.
  • about:description: in the YAML form. GitHub requires
    description; Gitea's IssueTemplate.About is annotated "Using
    description in a template file is compatible"
    and falls back to it at
    modules/issue/template/unmarshal.go:126. description is the only
    spelling both accept. The markdown templates keep about:, correct for
    their format on both.

Both files now carry a comment explaining the constraint so neither gets
tidied back into a broken state.

All 33 labels were also created on the mirror, driven from the Gitea API so
the two can't drift, and GitHub's 7 stock defaults (bug, documentation,
duplicate, enhancement, invalid, question, wontfix) were deleted —
each duplicated a taxonomy label, and the mirror has never had an issue, so
nothing referenced them. The two forges now hold an identical 33-label set.

Keeping them aligned is manual by necessity: mirroring copies files, not
repository settings, and GitHub silently drops a labels: entry naming a
label it doesn't have. Note GitHub has no exclusive labels, so the one-of
rule on Priority/, Reviewed/, and Status/ holds only by convention
there.

Notes

  • Issue titles are plain descriptions, not Conventional Commits subjects
    mv clobbers a symlink when the target exists, not fix(mv): .... An issue
    states a problem; a commit states a change, and the type and scope are
    already carried by the Kind/ and Area/ labels. Documented under
    ### Issue titles.
  • The label taxonomy lives in the forges, not in a checked-in manifest — the
    ## Labels tables in CONTRIBUTING.md are the written source of truth, and
    the verification below checks all three against each other.
  • Issues on the mirror are discouraged rather than blocked: its tracker stays
    open so a report landing there isn't lost, and the chooser's first contact
    link steers people to the canonical Gitea tracker before they file.
  • No behavioral change: nothing here is read by fish, the manual pipeline, or
    CI.

Verification

  • fish tests/run-tests.fish10/10 passed.
  • python3 docs/verify-manual.py74/74 passed.
  • bug.yml parses and satisfies GitHub's required top-level keys (name, description, body), carries no leftover about:, and has 10 unique field ids.
  • config.yml parses: blank_issues_enabled: true, 3 contact links.
  • Frontmatter of feature.md and docs.md parses and uses about:, correct for markdown templates on both forges.
  • All in-document anchors in CONTRIBUTING.md resolve to real headings — no broken TOC or cross-reference entries.
  • Every label named in CONTRIBUTING.md exists in Gitea and every Gitea label is documented — cross-checked against the API, both directions empty.
  • Gitea and GitHub label sets compared by name, color, and description after the stock-label cleanup: 33/33 on both, exact parity, zero drift, no extras.
  • Open New Issue on Gitea and confirm the picker lists all three templates, the blank-issue option, and all three contact links, each with its about text.
  • Start a Bug report, submit it with a required field empty and confirm the form refuses; then submit a throwaway one and confirm it lands with Kind/Bug applied and the fish code block rendered. Close and delete the throwaway issue afterward.
  • Open Feature or enhancement request and Documentation issue and confirm each pre-loads its markdown body with the right Kind/ label attached.
  • After merge, once the mirror syncs: open New Issue on github.com/rootiest/fish-config and confirm the chooser renders all three templates and the contact links — the check that proves the config.yml and description: fixes landed.
## Summary Follows the PR-template work in #123 with the two conventions it left open: a template for issues, and a rule for labeling both issues and PRs. - **Three issue templates** under `.github/ISSUE_TEMPLATE/`, beside the PR template so the GitHub mirror offers the same set. `bug.yml` is a Gitea *issue form* rather than markdown — version, OS, area, reproduction, expected and actual behavior are required fields, so an unactionable bug report can't be submitted at all. `feature.md` and `docs.md` are comment-guided markdown in the same house style as `.github/PULL_REQUEST_TEMPLATE.md`, since what they ask for is open-ended prose. `config.yml` keeps blank issues enabled for what the three don't cover and links the canonical tracker plus the contributing and customization docs. - **A labeling standard**: every issue and PR carries exactly one `Kind/` and at least one `Area/`. `CONTRIBUTING.md` now documents all 33 labels, which groups are exclusive, and who applies what. - **15 new labels** created in Gitea (see below) — the stock set couldn't describe a refactor or a chore, and had no way to say which subsystem an item touched. - **All 33 labels replicated on the GitHub mirror**, and the templates fixed so they actually work there — see [Mirror parity](#mirror-parity). - **Two new `CONTRIBUTING.md` sections**, `## Issues` and `## Labels`, plus a labeling bullet in the standing PR rules and TOC entries for both. ## Why Issues had no template at all, so a report arrived in whatever shape the reporter chose — most often missing the fish version, a reproduction, or the full error text, which is what actually stalls a bug. And the stock Gitea label set was present but unused, because nothing said when to apply it. ## How it works `bug.yml` carries an **Area** dropdown mirroring the `Area/` labels. That exists because no forge maps a form field to a label, and contributors without push access can't set labels themselves — so the dropdown is how a reporter tells you, and a maintainer translates it at triage. The rest of the maintainer-applied groups (`Priority/`, `Reviewed/`, `Status/`) are documented as exactly that, so reporters aren't expected to touch them. `feature.md` carries `## Acceptance criteria`, the issue-side counterpart to a PR's `## Verification` — a definition of done agreed before the work starts rather than argued about after. `docs.md` insists on naming the `docs/manual/**` source rather than the generated page, since a fix applied to `docs/fish-config.md` is overwritten by the next CI run. ## Labels added Created in Gitea as part of this change (33 total now, up from 18): - `Kind/Refactor`, `Kind/Chore`, `Kind/Performance` — the group now maps one-to-one onto the Conventional Commits types already in use, so a PR's label and its title agree. - A non-exclusive `Area/` group over the ten subsystems: `Functions`, `Completions`, `Config`, `Docs`, `Tests`, `CI`, `Integrations`, `Prompt & Theme`, `Components`, `Scripts`. - `good first issue` and `help wanted`, **unscoped on purpose**. They'd fit naturally under `Status/`, but that group is exclusive and an issue is often both blocked *and* open for someone to pick up; outside the group they can coexist with a real status. ## Mirror parity GitHub reads the same `.github/ISSUE_TEMPLATE/` files, and its schema differs from Gitea's in two places that both fail *silently*: - **`config.yaml` → `config.yml`.** Gitea accepts either (`modules/structs/issue.go:267`), GitHub only recognizes `config.yml`. Under the old name the mirror's chooser would have shown neither the contact links nor the blank-issue setting. - **`about:` → `description:`** in the YAML form. GitHub requires `description`; Gitea's `IssueTemplate.About` is annotated *"Using `description` in a template file is compatible"* and falls back to it at `modules/issue/template/unmarshal.go:126`. `description` is the only spelling both accept. The markdown templates keep `about:`, correct for their format on both. Both files now carry a comment explaining the constraint so neither gets tidied back into a broken state. All 33 labels were also created on the mirror, driven from the Gitea API so the two can't drift, and GitHub's 7 stock defaults (`bug`, `documentation`, `duplicate`, `enhancement`, `invalid`, `question`, `wontfix`) were deleted — each duplicated a taxonomy label, and the mirror has never had an issue, so nothing referenced them. The two forges now hold an identical 33-label set. Keeping them aligned is manual by necessity: mirroring copies files, not repository settings, and GitHub silently drops a `labels:` entry naming a label it doesn't have. Note GitHub has **no exclusive labels**, so the one-of rule on `Priority/`, `Reviewed/`, and `Status/` holds only by convention there. ## Notes - **Issue titles are plain descriptions, not Conventional Commits subjects** — `mv clobbers a symlink when the target exists`, not `fix(mv): ...`. An issue states a problem; a commit states a change, and the type and scope are already carried by the `Kind/` and `Area/` labels. Documented under `### Issue titles`. - The label taxonomy lives in the forges, not in a checked-in manifest — the `## Labels` tables in `CONTRIBUTING.md` are the written source of truth, and the verification below checks all three against each other. - Issues on the mirror are discouraged rather than blocked: its tracker stays open so a report landing there isn't lost, and the chooser's first contact link steers people to the canonical Gitea tracker before they file. - No behavioral change: nothing here is read by fish, the manual pipeline, or CI. ## Verification - [x] `fish tests/run-tests.fish` → `10/10 passed`. - [x] `python3 docs/verify-manual.py` → `74/74 passed`. - [x] `bug.yml` parses and satisfies **GitHub's** required top-level keys (`name`, `description`, `body`), carries no leftover `about:`, and has 10 unique field ids. - [x] `config.yml` parses: `blank_issues_enabled: true`, 3 contact links. - [x] Frontmatter of `feature.md` and `docs.md` parses and uses `about:`, correct for markdown templates on both forges. - [x] All in-document anchors in `CONTRIBUTING.md` resolve to real headings — no broken TOC or cross-reference entries. - [x] Every label named in `CONTRIBUTING.md` exists in Gitea and every Gitea label is documented — cross-checked against the API, both directions empty. - [x] Gitea and GitHub label sets compared by name, color, and description after the stock-label cleanup: **33/33 on both, exact parity, zero drift, no extras**. - [x] Open **New Issue** on Gitea and confirm the picker lists all three templates, the blank-issue option, and all three contact links, each with its `about` text. - [x] Start a **Bug report**, submit it with a required field empty and confirm the form refuses; then submit a throwaway one and confirm it lands with `Kind/Bug` applied and the `fish` code block rendered. Close and delete the throwaway issue afterward. - [x] Open **Feature or enhancement request** and **Documentation issue** and confirm each pre-loads its markdown body with the right `Kind/` label attached. - [x] After merge, once the mirror syncs: open **New Issue** on github.com/rootiest/fish-config and confirm the chooser renders all three templates and the contact links — the check that proves the `config.yml` and `description:` fixes landed.
rootiest added the Kind/DocumentationArea/Docs labels 2026-09-01 03:09:46 +00:00
rootiest added 2 commits 2026-09-01 03:09:48 +00:00
Issues had no template at all, so a report arrived in whatever shape the
reporter chose — most often without a fish version, a reproduction, or the
full error text, which is what actually stalls a bug.

Add three templates under .github/ISSUE_TEMPLATE/, beside the PR template
so the GitHub mirror offers the same set:

- **bug.yaml** — a Gitea issue form rather than markdown. Version, OS,
  area, reproduction, expected and actual behavior are required fields, so
  an unactionable report can't be submitted in the first place. The Area
  dropdown exists because contributors without push access can't set an
  Area/ label themselves.
- **feature.md** and **docs.md** — comment-guided markdown in the same
  house style as PULL_REQUEST_TEMPLATE.md, since what they ask for is
  open-ended prose. feature.md carries `## Acceptance criteria`, the
  issue-side counterpart to a PR's `## Verification`. docs.md insists on
  the docs/manual/** source rather than the generated page, which the next
  CI run would overwrite.
- **config.yaml** — keeps blank issues enabled for what the three don't
  cover, and links the contributing guide and the customization docs.

Each template pre-applies its Kind/ label. Document the set, the plain-
description title convention (an issue states a problem; the conventional
subject belongs on the PR that closes it), and the triage split in a new
CONTRIBUTING.md § Issues.
The repo carried Gitea's stock label set with no written rule for applying
it, so labels were effectively unused. Establish the standard: every issue
and PR carries exactly one Kind/ and at least one Area/, and document what
each group means, which are exclusive, and who applies them.

Extend the taxonomy to make that workable:

- **Kind/Refactor, Kind/Chore, Kind/Performance** — the stock Kind/ group
  couldn't describe a refactor, a chore, or a perf change, which is much of
  this repo's history. The group now maps one-to-one onto the Conventional
  Commits types already in use, so a PR's label and title agree.
- **A new non-exclusive Area/ group** over the ten subsystems (functions,
  completions, config, docs, tests, CI, integrations, prompt & theme,
  components, scripts). This is what makes the tracker searchable by
  subsystem; Kind/ alone can't answer "what's outstanding in the docs
  pipeline?".
- **good first issue and help wanted**, deliberately unscoped rather than
  under Status/. Status/ is exclusive, and an issue is often both blocked
  and open for someone to pick up; keeping these outside the group lets
  them coexist with a real status.

Priority/, Reviewed/, and Status/ are documented as exclusive and
maintainer-applied, with the rules that keep them meaningful — no
Priority/ label means ordinary priority, Reviewed/Confirmed means actually
reproduced, and a Status/ label is removed once it stops being true.

Also add labeling to the standing PR rules in Branching & Pull Requests,
so it's visible where the rest of the PR checklist lives.
rootiest added 1 commit 2026-09-01 03:16:45 +00:00
The templates were written against Gitea's schema alone, but the mirror
serves the same .github/ISSUE_TEMPLATE/ files to GitHub, where two of them
would have silently failed:

- **config.yaml -> config.yml.** Gitea accepts either spelling
  (modules/structs/issue.go: `base == "config.yaml" || base == "config.yml"`),
  GitHub only recognizes config.yml. Under the old name the mirror's
  template chooser would have shown neither the contact links nor the
  blank-issue setting.
- **bug.yaml `about:` -> bug.yml `description:`.** GitHub requires
  `description` on a YAML issue form; Gitea's IssueTemplate.About carries
  the comment "Using description in a template file is compatible" and
  falls back to it at modules/issue/template/unmarshal.go:126. So
  `description` is the one spelling both forges accept. The markdown
  templates keep `about:`, which is correct for their format on both.

Both files now carry a comment explaining the constraint, so neither gets
"tidied" back into a broken state.

Also add a contact link pointing at the canonical Gitea tracker, so someone
arriving from the mirror is steered to the right place before they file,
and document mirror parity in CONTRIBUTING.md: the labels must be created
on both sides by hand, since mirroring copies files rather than repository
settings and GitHub drops a labels: entry naming a label it doesn't have.
Note too that GitHub has no exclusive labels, so the one-of rule on
Priority/, Reviewed/, and Status/ holds only by convention there.
rootiest merged commit a78c6a604d into main 2026-09-01 03:36:03 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rootiest/fish-config#124