Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 28 additions & 22 deletions ISSUE-FORMAT.md
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,10 @@ Labels: label1, label2, label3

When comparing labels for merge operations (Section 6.3), implementations
MUST trim whitespace and compare the resulting strings exactly
(case-sensitive).
(case-sensitive). Implementations SHOULD normalize labels to lowercase
before comparison to avoid case-variant duplicates (e.g., `bug` and `Bug`
being treated as distinct labels). This normalization is RECOMMENDED but
not REQUIRED, to preserve intentional casing (e.g., `iOS`, `API`, `UI`).

### 4.8 Formal Grammar (ABNF)

Expand All @@ -337,31 +340,31 @@ Form (ABNF, RFC 5234):
```abnf
issue-commit = root-commit / comment-commit / state-commit / merge-commit

root-commit = title CRLF CRLF description CRLF CRLF
"State: " state-value CRLF
root-commit = title LF LF description LF LF
"State: " state-value LF
[optional-trailers]
"Format-Version: 1" CRLF
"Format-Version: 1" LF

comment-commit = comment-subject CRLF CRLF comment-body
[CRLF CRLF state-trailers]
comment-commit = comment-subject LF LF comment-body
[LF LF state-trailers]

state-commit = change-subject CRLF CRLF change-body CRLF CRLF
"State: " state-value CRLF
state-commit = change-subject LF LF change-body LF LF
"State: " state-value LF
[state-trailers]

merge-commit = "Merge issue from " remote-name CRLF
[CRLF body]
CRLF CRLF
"State: " state-value CRLF
merge-commit = "Merge issue from " remote-name LF
[LF body]
LF LF
"State: " state-value LF
[merge-trailers]

title = TEXT-NO-LF ; max 72 characters recommended
title = 1*TEXT-NO-LF ; SHOULD be 72 characters or fewer
comment-subject = TEXT-NO-LF
change-subject = TEXT-NO-LF
comment-body = *( TEXT-NO-LF CRLF )
description = *( TEXT-NO-LF CRLF )
change-body = *( TEXT-NO-LF CRLF )
body = *( TEXT-NO-LF CRLF )
comment-body = *( TEXT-NO-LF LF )
description = *( TEXT-NO-LF LF )
change-body = *( TEXT-NO-LF LF )
body = *( TEXT-NO-LF LF )

state-value = "open" / "closed"
remote-name = TEXT-NO-LF
Expand All @@ -370,7 +373,7 @@ optional-trailers = *( trailer )
state-trailers = *( trailer )
merge-trailers = *( trailer )

trailer = trailer-key ": " trailer-value CRLF
trailer = trailer-key ": " trailer-value LF
trailer-key = "Labels" / "Assignee" / "Priority" / "Milestone" /
"Fixed-By" / "Release" / "Reason" / "Provider-ID" /
"Title" / custom-trailer-key
Expand All @@ -385,12 +388,14 @@ UTF8-3 = %xE0-EF 2UTF8-tail
UTF8-4 = %xF0-F7 3UTF8-tail
UTF8-tail = %x80-BF

CRLF = %x0A ; Git uses LF, not CRLF
LF = %x0A ; Git commit messages use LF, not CRLF
```

**Notes**:
- This grammar uses `CRLF` as a placeholder for line endings, but Git
commit messages use LF (`\n`, 0x0A) not CRLF (`\r\n`).
- Git commit messages use LF (`\n`, 0x0A), not CRLF (`\r\n`). The
grammar uses `LF` to reflect this accurately per RFC 5234.
- `title` uses `1*TEXT-NO-LF` (one or more characters) — empty titles
are invalid.
- The `TEXT-NO-LF` production allows any UTF-8 text except newline.
- Trailer values must not contain embedded newlines (security requirement
from Section 4.9 and Section 11.1).
Expand Down Expand Up @@ -549,7 +554,8 @@ known limitations:
**1. Case Variants**:
- `bug` and `Bug` are distinct labels
- Concurrent addition of both creates duplicates: `bug, Bug`
- Resolution: Manual cleanup or project conventions
- Resolution: Implementations SHOULD apply lowercase normalization per
Section 4.7. Projects SHOULD establish consistent casing conventions.

**2. Semantic Duplicates**:
- `enhancement` and `feature` are distinct labels
Expand Down