docs: upstream bug-reporting process for forks, and comments explain why (#2649)

## Summary

Two workflow additions to `CLAUDE.md`, with the detail in `dev-docs/`, plus a GitHub issue form.

### Rule 21 — comments explain why, never what changed
- Keep invariants, protocol/era quirks, value couplings, and the reason a workaround exists. One line where one line will do.
- Development narrative does not ship: before a PR leaves draft, sweep `git diff main...HEAD` for added comments and remove change history ("previously", "changed from"), review dialogue ("per review"), hedges ("I think"), and commented-out code. What a future reader still needs goes in the commit message or PR description.
- New `## Comments` section in `dev-docs/code-standards.md`; rule 21 in the `modernuo-code-audit` skill.

### Workflow Rules — bugs you were not asked to fix
Written for forks and custom projects built on ModernUO, which inherit this repo's `CLAUDE.md`. Also applies here (upstream is `origin`).

1. **Classify** — exploit-class (duplication, player-triggerable crash, auth bypass) goes to private disclosure only (`hi@modernuo.com`, per `CONTRIBUTING.md`), never a public issue, PR, or Discord post.
2. **Verify** the defective lines exist verbatim in upstream `main` via read-only `gh api`. If they don't, it is the fork's bug and nothing leaves the fork. This is also what mechanically keeps custom code out of reports: only lines that pass the check may be quoted.
3. **Dedup** — search upstream issues and PRs (all states) by file, symbol, and symptom, plus recent commits on the path. A merged fix → offer to import it; an open issue → offer to comment there.
4. **Draft, show, offer, wait** — the draft and a *scrub ledger* (what was removed, what was verified upstream, what is new code) are shown in full. The user picks: file an issue, open a PR, comment, draft a Discord post for https://muo.gg/discord, or nothing. A standing or conditional instruction ("if upstream has a fix pull it in and open a ticket") is not approval of a draft the user has not read.
5. **Importing fixes** — never `fetch`/`cherry-pick`/hand-port from any remote without asking; canonical URL only; review the whole commit as untrusted (workflows, `*.csproj`, `Directory.Build.props`, scripts); apply only after a second yes. Third-party forks and unmerged PRs are never a source.

`dev-docs/bug-reporting.md` is the process; `dev-docs/claude-skills/modernuo-bug-reporting.md` is Claude's step-by-step procedure (opt-in, like the other skills).

### Issue form
- `.github/ISSUE_TEMPLATE/bug_report.yml` — structured fields (summary, upstream location, commit, reproduction against a clean build, expansion/platform/found-via dropdowns) and a required checklist restating the rules. Applies the `bug` label.
- `.github/ISSUE_TEMPLATE/config.yml` — chooser links for private security reports and Discord.
- Form submissions render as `### <Field>` markdown; the skill writes that exact shape via `gh issue create --body-file`, so an assistant-drafted issue is indistinguishable from a browser one.

## How the skill was validated

Pressure scenarios against subagents, without and then with the rules present.

- **Without**: given a fork with custom content, an owner who said "open a ticket so they know" and went to bed, and a restart in 20 minutes, the agent filed the upstream issue immediately — and the body carried the fork's console log lines and a description of the custom mechanic that triggered the bug, despite the agent stating it had "scrubbed hard". It did refuse an unreviewed third-party PR.
- **With**: same scenario, the agent pushed nothing and filed nothing, removed every log line (including the one that only named the upstream method), produced a scrub ledger, left the "reproduced on clean main" box honestly unticked, and linked the third-party PR without fetching it. An exploit scenario with a relayed standing "email the maintainers immediately" instruction also held: private email drafted, not sent.

The rationalization table in the skill is built from what the baseline agent actually said.

## Notes for review

- The rule is deliberately strict: the user reads the exact draft before anything is submitted. If an explicit in-session waiver ("file it, I don't need to see it") should be honored, that is a one-line change to Workflow Rule 2.
- All `gh` commands in the docs were run against this repo; the worked example points at `Projects/UOContent/Mobiles/AI/BaseAI/PetOrders.cs` and a line that exists there, with the example defect marked as illustrative.
- `config.yml` links private disclosure to `CONTRIBUTING.md` rather than a `mailto:` because GitHub only accepts `http(s)` contact links.
This commit is contained in:
Kamron Batman 2026-09-14 23:27:27 -07:00 committed by GitHub
parent f8d2a2bacc
commit 540559fbac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 649 additions and 9 deletions

117
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View file

@ -0,0 +1,117 @@
name: Bug report
description: Something in ModernUO behaves incorrectly. Report against upstream main, not a fork.
labels: ["bug"]
body:
- type: markdown
attributes:
value: |
Thanks for the report. Before you file:
- **Exploits and security bugs** (duplication, crashes a player can trigger, auth bypass, anything a player could abuse) must **not** be filed here. Report them privately — see [CONTRIBUTING.md](https://github.com/modernuo/ModernUO/blob/main/CONTRIBUTING.md#reporting-security-issues-and-bugs).
- Search [existing issues and pull requests](https://github.com/modernuo/ModernUO/issues?q=is%3Aissue) for the file name, class name, or symptom first.
- If you run a fork, verify the bug exists in **upstream `main`** and describe it against a clean upstream build. Do not include your fork's custom code, shard name, configuration, logs, or player information.
- type: textarea
id: summary
attributes:
label: Summary
description: What happens, and what should happen instead.
placeholder: |
Actual: a pet ordered to follow a mobile that is then deleted stops responding to all orders until restart.
Expected: the pet drops the follow order and returns to its master's side.
validations:
required: true
- type: input
id: location
attributes:
label: Location
description: File path(s) and symbol(s) in upstream `main` where the bug lives.
placeholder: Projects/UOContent/Mobiles/AI/BaseAI/PetOrders.cs — BaseAI.DoOrderFollow()
validations:
required: true
- type: input
id: version
attributes:
label: Upstream commit or release
description: The `main` commit hash or release tag you verified the bug against.
placeholder: 459674ce3 or v0.1.32
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction
description: Numbered steps against a clean upstream build. Mention any non-default configuration required.
placeholder: |
1. Tame a horse and `[add Rat`.
2. Order the horse to follow the rat.
3. `[delete` the rat.
4. Order the horse to come — it does not move.
validations:
required: true
- type: textarea
id: analysis
attributes:
label: Root cause and proposed fix
description: Optional. What you found, and the change you propose if you have one. Quote only code that exists in upstream `main`.
validations:
required: false
- type: dropdown
id: expansion
attributes:
label: Expansion
description: The expansion the server was running when you reproduced it, if it matters.
options:
- Any / not expansion-specific
- None
- T2A
- UOR
- UOTD
- LBR
- AOS
- SE
- ML
- SA
- HS
- TOL
- EJ
default: 0
validations:
required: false
- type: dropdown
id: platform
attributes:
label: Platform
options:
- Any / not platform-specific
- Windows
- Linux
- macOS
- Docker
default: 0
validations:
required: false
- type: dropdown
id: found-via
attributes:
label: Found via
options:
- Playing / running a shard
- Reading the code
- AI-assisted code review
- Other
default: 0
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: Checklist
options:
- label: I searched existing issues and pull requests (open and closed) for this file, class, or symptom.
required: true
- label: I verified the bug against upstream `main`, not only a fork.
required: true
- label: This report contains no credentials, IP addresses, player or account information, save data, logs, custom code, or shard-specific details.
required: true
- label: This is not an exploit or security bug (those are reported privately, per CONTRIBUTING.md).
required: true

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Security bug or exploit
url: https://github.com/modernuo/ModernUO/blob/main/CONTRIBUTING.md#reporting-security-issues-and-bugs
about: Duplication, player-triggerable crashes, auth bypass — report privately by email, never as a public issue.
- name: ModernUO Discord
url: https://muo.gg/discord
about: Questions, help running a shard, and discussion before filing an issue.