[pkgsite] internal/natsort: add natural sorting

3 views
Skip to first unread message

Egon Elbre (Gerrit)

unread,
Jan 15, 2026, 6:31:11 AM (3 days ago) Jan 15
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Egon Elbre has uploaded the change for review

Commit message

internal/natsort: add natural sorting

Natural sorting allows to compare strings such that numeric sorting is preserved.
For example instead of sorting names as:

Uint16x
Uint32x
Uint8x

It would lead to sorting:

Uint8x
Uint16x
Uint32x

Updates #77160
Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c

Change diff

diff --git a/internal/natsort/string.go b/internal/natsort/string.go
new file mode 100644
index 0000000..d4358e2
--- /dev/null
+++ b/internal/natsort/string.go
@@ -0,0 +1,116 @@
+// Copyright 2026 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package natsort provides natural string sorting.
+package natsort
+
+import (
+ "strings"
+)
+
+// Compare implements natural string sorting, where numbers are compared numerically.
+//
+// For example, "file1.txt" < "file2.txt" < "file10.txt".
+func Compare(a, b string) int {
+ if a == b {
+ return 0
+ }
+
+ for {
+ prefix := textPrefixLength(a, b)
+ a, b = a[prefix:], b[prefix:]
+ if len(a) == 0 || len(b) == 0 {
+ return notEqualCompare(len(a), len(b))
+ }
+
+ // Did we reach a component with numbers?
+ if isdigit(a[0]) && isdigit(b[0]) { // if both are numbers
+ // We have two numbers.
+ ac, azeros := countDigits(a)
+ bc, bzeros := countDigits(b)
+
+ // If one has more non-zero digits then it's obviously larger.
+ if ac-azeros != bc-bzeros {
+ return notEqualCompare(ac-azeros, bc-bzeros)
+ }
+
+ // Comparing equal length digit-strings will give the
+ // same result as converting them to numbers.
+ r := strings.Compare(a[azeros:ac], b[bzeros:bc])
+ if r != 0 {
+ return r
+ }
+
+ // The one with fewer leading zeros is smaller.
+ if azeros != bzeros && azeros+bzeros > 0 {
+ return notEqualCompare(azeros, bzeros)
+ }
+
+ // If they are numbers, we just continue.
+ a, b = a[ac:], b[bc:]
+ } else {
+ // We know we reached differing characters.
+ if a[0] < b[0] {
+ return -1
+ } else {
+ return 1
+ }
+ }
+ }
+}
+
+// notEqualCompare compares a and b assuming they are not equal.
+func notEqualCompare(a, b int) int {
+ if a < b {
+ return -1
+ } else {
+ return 1
+ }
+}
+
+// Less implements natural string comparison, where numbers are compared numerically.
+func Less(a, b string) bool {
+ return Compare(a, b) < 0
+}
+
+// Greater implements natural string comparison, where numbers are compared numerically.
+func Greater(a, b string) bool {
+ return Compare(a, b) > 0
+}
+
+// textPrefixLength returns the length of the longest common prefix of a and b ignoring digits.
+func textPrefixLength(a, b string) int {
+ i := 0
+ for {
+ if i >= len(a) || i >= len(b) {
+ return i
+ }
+ ca, cb := a[i], b[i]
+ if ca != cb || isdigit(ca) {
+ return i
+ }
+ i++
+ }
+}
+
+// countDigits returns the number of prefix digits in s.
+func countDigits(s string) (count, leadingZeros int) {
+ foundNonZero := false
+ for i, c := range []byte(s) {
+ if !isdigit(c) {
+ return i, leadingZeros
+ }
+ if !foundNonZero && c == '0' {
+ leadingZeros++
+ } else {
+ foundNonZero = true
+ }
+ }
+ return len(s), leadingZeros
+}
+
+// isdigit returns true if c is a digit.
+func isdigit(c byte) bool {
+ return '0' <= c && c <= '9'
+}
diff --git a/internal/natsort/string_test.go b/internal/natsort/string_test.go
new file mode 100644
index 0000000..de0fa53
--- /dev/null
+++ b/internal/natsort/string_test.go
@@ -0,0 +1,94 @@
+// Copyright 2026 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package natsort
+
+import (
+ "fmt"
+ "slices"
+ "testing"
+)
+
+var tests = []struct {
+ a, b string
+ want int
+}{
+ {"", "", 0},
+ {"a", "", 1},
+ {"abc", "abc", 0},
+ {"ab", "abc", -1},
+ {"x", "ab", 1},
+ {"x", "a", 1},
+ {"b", "x", -1},
+
+ {"a", "aa", -1},
+ {"a", "a1", -1},
+ {"ab", "a1", 1},
+ {"a", "0", 1},
+ {"A", "0", 1},
+ {"file1.txt", "file2.txt", -1},
+ {"file10.txt", "file2.txt", 1},
+ {"file1000.txt", "file2.txt", 1},
+ {"file0001.txt", "file2.txt", -1},
+ {"file00a.txt", "file000a.txt", -1},
+ {"a10", "a010", -1},
+ {"a1b2", "a01b3", -1},
+ {"file_1.txt", "file_10.txt", -1},
+ {"file1.txt", "file1.txt", 0},
+ {"fileA.txt", "fileB.txt", -1},
+ {"file1A.txt", "file1B.txt", -1},
+ {"Uint8x16", "Uint32x8", -1},
+ {"Uint32x16", "Uint32x8", 1},
+ {"Uint10000000000000000000000", "Uint20000000000000000000000", -1},
+ {"Uint10000000000000000000000abc", "Uint10000000000000000000000abc", 0},
+ {"a1a1a1a1a1a1a1a1a1a1a1", "a1a1a1a1a1a1a1a1a1a1a1", 0},
+ {"a1a1a1a1a1a1a1a1a1a1a10", "a1a1a1a1a1a1a1a1a1a1a1", 1},
+}
+
+func TestCompare(t *testing.T) {
+ for _, tt := range tests {
+ if got := Compare(tt.a, tt.b); got != tt.want {
+ t.Errorf("Compare(%q, %q) = %d; want %d", tt.a, tt.b, got, tt.want)
+ }
+ if got := Compare(tt.b, tt.a); got != -tt.want {
+ t.Errorf("Compare(%q, %q) = %d; want %d", tt.b, tt.a, got, -tt.want)
+ }
+ }
+}
+
+func TestSliceSort(t *testing.T) {
+ types := []string{"Uint32x16", "Uint16x32", "Unit8x64", "Uint64x8"}
+ want := []string{"Unit8x64", "Uint16x32", "Uint32x16", "Uint64x8"}
+ slices.SortFunc(types, Compare)
+ if slices.Equal(types, want) {
+ t.Errorf("types = %v; want %v", types, want)
+ }
+}
+
+func BenchmarkCompare(b *testing.B) {
+ for i, test := range tests {
+ b.Run(fmt.Sprintf("%d", i), func(b *testing.B) {
+ b.ReportAllocs()
+ for b.Loop() {
+ Compare(test.a, test.b)
+ }
+ })
+ }
+}
+
+func FuzzTransitivity(f *testing.F) {
+ f.Add("", "", "")
+ f.Fuzz(func(t *testing.T, a string, b string, c string) {
+ ab := Compare(a, b)
+ bc := Compare(b, c)
+ ca := Compare(c, a)
+
+ // when the total is 3 or -3, it means that there is a cycle in comparison.
+ if tot := ab + bc + ca; tot == 3 || tot == -3 {
+ t.Errorf("Compare(%q, %q) = %d", a, b, ab)
+ t.Errorf("Compare(%q, %q) = %d", b, c, bc)
+ t.Errorf("Compare(%q, %q) = %d", c, a, ca)
+ }
+ })
+}

Change information

Files:
  • A internal/natsort/string.go
  • A internal/natsort/string_test.go
Change size: M
Delta: 2 files changed, 210 insertions(+), 0 deletions(-)
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
  • requirement is not satisfiedkokoro-CI-Passes
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: newchange
Gerrit-Project: pkgsite
Gerrit-Branch: master
Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
Gerrit-Change-Number: 736560
Gerrit-PatchSet: 1
Gerrit-Owner: Egon Elbre <egon...@gmail.com>
unsatisfied_requirement
satisfied_requirement
open
diffy

Egon Elbre (Gerrit)

unread,
Jan 15, 2026, 6:35:33 AM (3 days ago) Jan 15
to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com

Egon Elbre voted Commit-Queue+1

Commit-Queue+1
Open in Gerrit

Related details

Attention set is empty
Submit Requirements:
  • requirement is not satisfiedCode-Review
  • requirement satisfiedNo-Unresolved-Comments
  • requirement is not satisfiedReview-Enforcement
  • requirement is not satisfiedTryBots-Pass
  • requirement is not satisfiedkokoro-CI-Passes
Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
Gerrit-MessageType: comment
Gerrit-Project: pkgsite
Gerrit-Branch: master
Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
Gerrit-Change-Number: 736560
Gerrit-PatchSet: 1
Gerrit-Owner: Egon Elbre <egon...@gmail.com>
Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
Gerrit-Comment-Date: Thu, 15 Jan 2026 11:35:27 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
unsatisfied_requirement
satisfied_requirement
open
diffy

kokoro (Gerrit)

unread,
Jan 15, 2026, 7:01:02 AM (2 days ago) Jan 15
to Egon Elbre, goph...@pubsubhelper.golang.org, Go LUCI, golang-co...@googlegroups.com
Attention needed from Egon Elbre

kokoro voted kokoro-CI+1

Kokoro presubmit build finished with status: SUCCESS
Logs at: https://source.cloud.google.com/results/invocations/d797b2fb-ffab-4650-b2b2-0d02e8a809d1

kokoro-CI+1
Open in Gerrit

Related details

Attention is currently required from:
  • Egon Elbre
Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement satisfiedTryBots-Pass
    • requirement satisfiedkokoro-CI-Passes
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: pkgsite
    Gerrit-Branch: master
    Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
    Gerrit-Change-Number: 736560
    Gerrit-PatchSet: 1
    Gerrit-Owner: Egon Elbre <egon...@gmail.com>
    Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
    Gerrit-Reviewer: kokoro <noreply...@google.com>
    Gerrit-CC: kokoro <noreply...@google.com>
    Gerrit-Attention: Egon Elbre <egon...@gmail.com>
    Gerrit-Comment-Date: Thu, 15 Jan 2026 12:00:57 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: Yes
    unsatisfied_requirement
    satisfied_requirement
    open
    diffy

    Florian Lehner (Gerrit)

    unread,
    Jan 15, 2026, 7:32:37 AM (2 days ago) Jan 15
    to Egon Elbre, goph...@pubsubhelper.golang.org, kokoro, Go LUCI, golang-co...@googlegroups.com
    Attention needed from Egon Elbre

    Florian Lehner voted Code-Review+1

    Code-Review+1
    Open in Gerrit

    Related details

    Attention is currently required from:
    • Egon Elbre
    Submit Requirements:
    • requirement is not satisfiedCode-Review
    • requirement satisfiedNo-Unresolved-Comments
    • requirement is not satisfiedReview-Enforcement
    • requirement satisfiedTryBots-Pass
    • requirement satisfiedkokoro-CI-Passes
    Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
    Gerrit-MessageType: comment
    Gerrit-Project: pkgsite
    Gerrit-Branch: master
    Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
    Gerrit-Change-Number: 736560
    Gerrit-PatchSet: 1
    Gerrit-Owner: Egon Elbre <egon...@gmail.com>
    Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
    Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
    Gerrit-Reviewer: kokoro <noreply...@google.com>
    Gerrit-CC: kokoro <noreply...@google.com>
    Gerrit-Attention: Egon Elbre <egon...@gmail.com>
    Gerrit-Comment-Date: Thu, 15 Jan 2026 12:32:30 +0000
    Gerrit-HasComments: No
    Gerrit-Has-Labels: Yes
    unsatisfied_requirement
    satisfied_requirement
    open
    diffy

    Alan Donovan (Gerrit)

    unread,
    Jan 15, 2026, 2:42:42 PM (2 days ago) Jan 15
    to Egon Elbre, goph...@pubsubhelper.golang.org, kokoro, Go LUCI, golang-co...@googlegroups.com
    Attention needed from Egon Elbre

    Alan Donovan added 9 comments

    File internal/natsort/string.go
    Line 5, Patchset 1 (Latest):// Package natsort provides natural string sorting.
    Alan Donovan . unresolved

    Cite an authority on this algorithm.

    Line 12, Patchset 1 (Latest):// Compare implements natural string sorting, where numbers are compared numerically.
    Alan Donovan . unresolved

    This could use a more precise definition of exactly what it computes.

    (What counts as a number? What base? Are leading zeros permitted? It is a weak order: i.e. can two unequal strings Compare equal? etc)

    Line 24, Patchset 1 (Latest): return notEqualCompare(len(a), len(b))
    Alan Donovan . unresolved

    How do you know they are not both empty? Is a != b a loop invariant? (I don't think so.) If so it should be documented, and established.

    Line 38, Patchset 1 (Latest): // Comparing equal length digit-strings will give the
    Alan Donovan . unresolved

    nit: equal-length digit strings

    (since "equal length" is used as a a compound adjective)


    // We know we reached differing characters.
    Alan Donovan . unresolved

    I suggest handling this case first then not indenting the both-are-digits case.

    Line 64, Patchset 1 (Latest):func notEqualCompare(a, b int) int {
    Alan Donovan . unresolved

    You can use cmp.Compare instead of this function.

    Line 78, Patchset 1 (Latest):func Greater(a, b string) bool {
    Alan Donovan . unresolved

    Is this actually needed?

    Line 82, Patchset 1 (Latest):// textPrefixLength returns the length of the longest common prefix of a and b ignoring digits.
    Alan Donovan . unresolved

    Ambiguous: does it mean longest digit-free common prefix, or longest prefix skipping past digits? (The first, I think.)


    More importantly, this is a byte- (not rune-) oriented prefix, so the result may slice the encoding of a single rune in half.

    Line 84, Patchset 1 (Latest): i := 0
    Alan Donovan . unresolved
    Clearer perhaps:
    ```
    func textPrefixLength(a, b string) (i int) {
    for i = 0; i < len(a) && i < len(b) && a[i] == b[i] && !isdigit(a[i]); i++ {
    }
    return i
    }
    ```
    Open in Gerrit

    Related details

    Attention is currently required from:
    • Egon Elbre
    Submit Requirements:
      • requirement is not satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement is not satisfiedReview-Enforcement
      • requirement satisfiedTryBots-Pass
      • requirement satisfiedkokoro-CI-Passes
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: pkgsite
      Gerrit-Branch: master
      Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
      Gerrit-Change-Number: 736560
      Gerrit-PatchSet: 1
      Gerrit-Owner: Egon Elbre <egon...@gmail.com>
      Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
      Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
      Gerrit-Reviewer: kokoro <noreply...@google.com>
      Gerrit-CC: Alan Donovan <adon...@google.com>
      Gerrit-CC: kokoro <noreply...@google.com>
      Gerrit-Attention: Egon Elbre <egon...@gmail.com>
      Gerrit-Comment-Date: Thu, 15 Jan 2026 19:42:38 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      unsatisfied_requirement
      satisfied_requirement
      open
      diffy

      Egon Elbre (Gerrit)

      unread,
      Jan 15, 2026, 3:14:36 PM (2 days ago) Jan 15
      to goph...@pubsubhelper.golang.org, Alan Donovan, kokoro, Go LUCI, golang-co...@googlegroups.com
      Attention needed from Alan Donovan

      Egon Elbre added 4 comments

      File internal/natsort/string.go
      Line 5, Patchset 1 (Latest):// Package natsort provides natural string sorting.
      Alan Donovan . unresolved

      Cite an authority on this algorithm.

      Egon Elbre

      I'm not sure what would constitute a proper authority in this case.

      It was implemented based on the wikipedia description https://en.wikipedia.org/wiki/Natural_sort_order, and there's background information in https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/. I did a quick search for a "defacto algorithm", but unfortunately I wasn't able to find one, the closest is https://web.archive.org/web/20080116232902/http://www.davekoelle.com/alphanum.html.

      https://en.wikipedia.org/wiki/Natural_sort_order is probably the clearest, but not sure whether it's sufficient for "authority".

      Line 24, Patchset 1 (Latest): return notEqualCompare(len(a), len(b))
      Alan Donovan . unresolved

      How do you know they are not both empty? Is a != b a loop invariant? (I don't think so.) If so it should be documented, and established.

      Egon Elbre

      This would only happen when strings are equal and there's a fast-path for equal strings at the beginning of the func.

      But now that you mention it, it is not obvious and the fast-path is probably redundant since most of the time it is used for sorting unique strings. I'll replace it with cmp.Compare.

      Line 78, Patchset 1 (Latest):func Greater(a, b string) bool {
      Alan Donovan . unresolved

      Is this actually needed?

      Egon Elbre

      Probably not, I'll remove.

      Alan Donovan . unresolved
      Clearer perhaps:
      ```
      func textPrefixLength(a, b string) (i int) {
      for i = 0; i < len(a) && i < len(b) && a[i] == b[i] && !isdigit(a[i]); i++ {
      }
      return i
      }
      ```
      Egon Elbre

      That's bit too dense information per line for my taste, but I'm not opposed to it.

      Maybe this variant is clearer?

      ```
      func nondigitCommonPrefixLength(a, b string) int {
      i := 0
      for i < len(a) && i < len(b); i++ {
      if a[i] != b[i] || isdigit(a[i]) {
      return i
      }
      }
      return i
      }
      ```

      If not, I'll use your variant.

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Alan Donovan
      Submit Requirements:
      • requirement is not satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement is not satisfiedReview-Enforcement
      • requirement satisfiedTryBots-Pass
      • requirement satisfiedkokoro-CI-Passes
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: pkgsite
      Gerrit-Branch: master
      Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
      Gerrit-Change-Number: 736560
      Gerrit-PatchSet: 1
      Gerrit-Owner: Egon Elbre <egon...@gmail.com>
      Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
      Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
      Gerrit-Reviewer: kokoro <noreply...@google.com>
      Gerrit-CC: Alan Donovan <adon...@google.com>
      Gerrit-CC: kokoro <noreply...@google.com>
      Gerrit-Attention: Alan Donovan <adon...@google.com>
      Gerrit-Comment-Date: Thu, 15 Jan 2026 20:14:28 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Alan Donovan <adon...@google.com>
      unsatisfied_requirement
      satisfied_requirement
      open
      diffy

      Alan Donovan (Gerrit)

      unread,
      Jan 15, 2026, 3:22:17 PM (2 days ago) Jan 15
      to Egon Elbre, goph...@pubsubhelper.golang.org, kokoro, Go LUCI, golang-co...@googlegroups.com
      Attention needed from Egon Elbre

      Alan Donovan added 4 comments

      File internal/natsort/string.go
      Line 5, Patchset 1 (Latest):// Package natsort provides natural string sorting.
      Alan Donovan . unresolved

      Cite an authority on this algorithm.

      Egon Elbre

      I'm not sure what would constitute a proper authority in this case.

      It was implemented based on the wikipedia description https://en.wikipedia.org/wiki/Natural_sort_order, and there's background information in https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/. I did a quick search for a "defacto algorithm", but unfortunately I wasn't able to find one, the closest is https://web.archive.org/web/20080116232902/http://www.davekoelle.com/alphanum.html.

      https://en.wikipedia.org/wiki/Natural_sort_order is probably the clearest, but not sure whether it's sufficient for "authority".

      Alan Donovan

      Wikipedia is a perfectly respectable source here.

      (Not long ago teachers used to say "now children, cite a book, not Wikipedia, which any fool can edit"; now they say, "cite Wikipedia, not ChatGPT, since at least one fool has reviewed it"!)

      Line 6, Patchset 1 (Latest):package natsort
      Alan Donovan . unresolved

      Perhaps natural.Compare would be a better name for the main function of this package? If so let's call the file natural/compare.go too.

      Alan Donovan . unresolved
      Clearer perhaps:
      ```
      func textPrefixLength(a, b string) (i int) {
      for i = 0; i < len(a) && i < len(b) && a[i] == b[i] && !isdigit(a[i]); i++ {
      }
      return i
      }
      ```
      Egon Elbre

      That's bit too dense information per line for my taste, but I'm not opposed to it.

      Maybe this variant is clearer?

      ```
      func nondigitCommonPrefixLength(a, b string) int {
      i := 0
      for i < len(a) && i < len(b); i++ {
      if a[i] != b[i] || isdigit(a[i]) {
      return i
      }
      }
      return i
      }
      ```

      If not, I'll use your variant.

      Alan Donovan

      I prefer mine since the condition is expressed directly. But yours is fine if you factor the returns (replace the first return by break).

      Line 99, Patchset 1 (Latest): foundNonZero := false
      Alan Donovan . unresolved

      FWIW, this is equivalent and perhaps clearer:
      ```
      digits := s[len(strings.TrimLeft(s, "0123456789")):]
      zeros := digits[len(strings.TrimLeft(digits, "0")):]
      return len(digits), len(zeros)
      ```
      Yours may be slightly faster though.

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Egon Elbre
      Submit Requirements:
      • requirement is not satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement is not satisfiedReview-Enforcement
      • requirement satisfiedTryBots-Pass
      • requirement satisfiedkokoro-CI-Passes
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: pkgsite
      Gerrit-Branch: master
      Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
      Gerrit-Change-Number: 736560
      Gerrit-PatchSet: 1
      Gerrit-Owner: Egon Elbre <egon...@gmail.com>
      Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
      Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
      Gerrit-Reviewer: kokoro <noreply...@google.com>
      Gerrit-CC: Alan Donovan <adon...@google.com>
      Gerrit-CC: kokoro <noreply...@google.com>
      Gerrit-Attention: Egon Elbre <egon...@gmail.com>
      Gerrit-Comment-Date: Thu, 15 Jan 2026 20:22:13 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Egon Elbre <egon...@gmail.com>
      Comment-In-Reply-To: Alan Donovan <adon...@google.com>
      unsatisfied_requirement
      satisfied_requirement
      open
      diffy

      Egon Elbre (Gerrit)

      unread,
      Jan 15, 2026, 3:37:58 PM (2 days ago) Jan 15
      to goph...@pubsubhelper.golang.org, Alan Donovan, kokoro, Go LUCI, golang-co...@googlegroups.com
      Attention needed from Alan Donovan

      Egon Elbre added 2 comments

      File internal/natsort/string.go
      Alan Donovan . unresolved

      Perhaps natural.Compare would be a better name for the main function of this package? If so let's call the file natural/compare.go too.

      Egon Elbre

      I had trouble figuring out what to call it. There are also package names such as `alphanumeric` or `alphanum` that would fit. I did also consider `natural`, but for some reason it feels like it's not that descriptive and that it's related to ordering strings. Although, since it's called "natural sort order", I think `natural` as a package name is fine as well.

      Line 99, Patchset 1 (Latest): foundNonZero := false
      Alan Donovan . unresolved

      FWIW, this is equivalent and perhaps clearer:
      ```
      digits := s[len(strings.TrimLeft(s, "0123456789")):]
      zeros := digits[len(strings.TrimLeft(digits, "0")):]
      return len(digits), len(zeros)
      ```
      Yours may be slightly faster though.

      Egon Elbre

      I did a quick check and it seems that using strings.TrimLeft ends up making things ~3x slower.

      Open in Gerrit

      Related details

      Attention is currently required from:
      • Alan Donovan
      Submit Requirements:
      • requirement is not satisfiedCode-Review
      • requirement is not satisfiedNo-Unresolved-Comments
      • requirement is not satisfiedReview-Enforcement
      • requirement satisfiedTryBots-Pass
      • requirement satisfiedkokoro-CI-Passes
      Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
      Gerrit-MessageType: comment
      Gerrit-Project: pkgsite
      Gerrit-Branch: master
      Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
      Gerrit-Change-Number: 736560
      Gerrit-PatchSet: 1
      Gerrit-Owner: Egon Elbre <egon...@gmail.com>
      Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
      Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
      Gerrit-Reviewer: kokoro <noreply...@google.com>
      Gerrit-CC: Alan Donovan <adon...@google.com>
      Gerrit-CC: kokoro <noreply...@google.com>
      Gerrit-Attention: Alan Donovan <adon...@google.com>
      Gerrit-Comment-Date: Thu, 15 Jan 2026 20:37:50 +0000
      Gerrit-HasComments: Yes
      Gerrit-Has-Labels: No
      Comment-In-Reply-To: Alan Donovan <adon...@google.com>
      unsatisfied_requirement
      satisfied_requirement
      open
      diffy

      Egon Elbre (Gerrit)

      unread,
      Jan 16, 2026, 4:38:43 AM (yesterday) Jan 16
      to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
      Attention needed from Alan Donovan and Florian Lehner

      Egon Elbre uploaded new patchset

      Egon Elbre uploaded patch set #2 to this change.
      Following approvals got outdated and were removed:
      • Code-Review: +1 by Florian Lehner
      • TryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI
      • kokoro-CI-Passes: kokoro-CI+1 by kokoro
      Open in Gerrit

      Related details

      Attention is currently required from:
      • Alan Donovan
      • Florian Lehner
      Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: newpatchset
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 2
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: Alan Donovan <adon...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Attention: Alan Donovan <adon...@google.com>
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 4:39:12 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, Alan Donovan, kokoro, Go LUCI, golang-co...@googlegroups.com
        Attention needed from Alan Donovan and Florian Lehner

        Egon Elbre added 11 comments

        File internal/natsort/string.go
        Line 5, Patchset 1:// Package natsort provides natural string sorting.
        Alan Donovan . resolved

        Cite an authority on this algorithm.

        Egon Elbre

        I'm not sure what would constitute a proper authority in this case.

        It was implemented based on the wikipedia description https://en.wikipedia.org/wiki/Natural_sort_order, and there's background information in https://blog.codinghorror.com/sorting-for-humans-natural-sort-order/. I did a quick search for a "defacto algorithm", but unfortunately I wasn't able to find one, the closest is https://web.archive.org/web/20080116232902/http://www.davekoelle.com/alphanum.html.

        https://en.wikipedia.org/wiki/Natural_sort_order is probably the clearest, but not sure whether it's sufficient for "authority".

        Alan Donovan

        Wikipedia is a perfectly respectable source here.

        (Not long ago teachers used to say "now children, cite a book, not Wikipedia, which any fool can edit"; now they say, "cite Wikipedia, not ChatGPT, since at least one fool has reviewed it"!)

        Egon Elbre

        Done

        Line 6, Patchset 1:package natsort
        Alan Donovan . resolved

        Perhaps natural.Compare would be a better name for the main function of this package? If so let's call the file natural/compare.go too.

        Egon Elbre

        I had trouble figuring out what to call it. There are also package names such as `alphanumeric` or `alphanum` that would fit. I did also consider `natural`, but for some reason it feels like it's not that descriptive and that it's related to ordering strings. Although, since it's called "natural sort order", I think `natural` as a package name is fine as well.

        Egon Elbre

        Done

        Line 12, Patchset 1:// Compare implements natural string sorting, where numbers are compared numerically.
        Alan Donovan . unresolved

        This could use a more precise definition of exactly what it computes.

        (What counts as a number? What base? Are leading zeros permitted? It is a weak order: i.e. can two unequal strings Compare equal? etc)

        Egon Elbre

        Added examples and clarification on the behaviour.

        Line 24, Patchset 1: return notEqualCompare(len(a), len(b))
        Alan Donovan . resolved

        How do you know they are not both empty? Is a != b a loop invariant? (I don't think so.) If so it should be documented, and established.

        Egon Elbre

        This would only happen when strings are equal and there's a fast-path for equal strings at the beginning of the func.

        But now that you mention it, it is not obvious and the fast-path is probably redundant since most of the time it is used for sorting unique strings. I'll replace it with cmp.Compare.

        Egon Elbre

        Done

        Line 38, Patchset 1: // Comparing equal length digit-strings will give the
        Alan Donovan . resolved

        nit: equal-length digit strings

        (since "equal length" is used as a a compound adjective)

        Egon Elbre

        Done


        // We know we reached differing characters.
        Alan Donovan . resolved

        I suggest handling this case first then not indenting the both-are-digits case.

        Egon Elbre

        Done

        Line 64, Patchset 1:func notEqualCompare(a, b int) int {
        Alan Donovan . resolved

        You can use cmp.Compare instead of this function.

        Egon Elbre

        Done

        Line 78, Patchset 1:func Greater(a, b string) bool {
        Alan Donovan . resolved

        Is this actually needed?

        Egon Elbre

        Probably not, I'll remove.

        Egon Elbre

        Done

        Line 82, Patchset 1:// textPrefixLength returns the length of the longest common prefix of a and b ignoring digits.
        Alan Donovan . resolved

        Ambiguous: does it mean longest digit-free common prefix, or longest prefix skipping past digits? (The first, I think.)


        More importantly, this is a byte- (not rune-) oriented prefix, so the result may slice the encoding of a single rune in half.

        Egon Elbre

        Done

        Line 84, Patchset 1: i := 0
        Alan Donovan . resolved
        Clearer perhaps:
        ```
        func textPrefixLength(a, b string) (i int) {
        for i = 0; i < len(a) && i < len(b) && a[i] == b[i] && !isdigit(a[i]); i++ {
        }
        return i
        }
        ```
        Egon Elbre

        That's bit too dense information per line for my taste, but I'm not opposed to it.

        Maybe this variant is clearer?

        ```
        func nondigitCommonPrefixLength(a, b string) int {
        i := 0
        for i < len(a) && i < len(b); i++ {
        if a[i] != b[i] || isdigit(a[i]) {
        return i
        }
        }
        return i
        }
        ```

        If not, I'll use your variant.

        Alan Donovan

        I prefer mine since the condition is expressed directly. But yours is fine if you factor the returns (replace the first return by break).

        Egon Elbre

        Done

        Line 99, Patchset 1: foundNonZero := false
        Alan Donovan . resolved

        FWIW, this is equivalent and perhaps clearer:
        ```
        digits := s[len(strings.TrimLeft(s, "0123456789")):]
        zeros := digits[len(strings.TrimLeft(digits, "0")):]
        return len(digits), len(zeros)
        ```
        Yours may be slightly faster though.

        Egon Elbre

        I did a quick check and it seems that using strings.TrimLeft ends up making things ~3x slower.

        Egon Elbre

        Ended up leaving as is due to performance overhead.

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Alan Donovan
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 2
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: Alan Donovan <adon...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Attention: Alan Donovan <adon...@google.com>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 09:39:07 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: No
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 4:42:17 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
        Attention needed from Alan Donovan and Florian Lehner

        Egon Elbre uploaded new patchset

        Egon Elbre uploaded patch set #3 to this change.
        Open in Gerrit

        Related details

        Attention is currently required from:
        • Alan Donovan
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: newpatchset
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 3
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 6:04:53 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
        Attention needed from Alan Donovan and Florian Lehner

        Egon Elbre uploaded new patchset

        Egon Elbre uploaded patch set #4 to this change.
        Open in Gerrit

        Related details

        Attention is currently required from:
        • Alan Donovan
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: newpatchset
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 4
        unsatisfied_requirement
        open
        diffy

        Alan Donovan (Gerrit)

        unread,
        Jan 16, 2026, 10:07:00 AM (yesterday) Jan 16
        to Egon Elbre, goph...@pubsubhelper.golang.org, kokoro, Go LUCI, golang-co...@googlegroups.com
        Attention needed from Egon Elbre and Florian Lehner

        Alan Donovan added 4 comments

        File internal/natsort/string.go
        Line 6, Patchset 1:package natsort
        Alan Donovan . unresolved

        Perhaps natural.Compare would be a better name for the main function of this package? If so let's call the file natural/compare.go too.

        Egon Elbre

        I had trouble figuring out what to call it. There are also package names such as `alphanumeric` or `alphanum` that would fit. I did also consider `natural`, but for some reason it feels like it's not that descriptive and that it's related to ordering strings. Although, since it's called "natural sort order", I think `natural` as a package name is fine as well.

        Egon Elbre

        Done

        Alan Donovan

        Thanks. I think compare.go makes the most sense for the file name.

        File internal/natural/string.go
        Line 29, Patchset 4 (Latest):// Implementation only handles numbers [0-9]+, there's no special treatment
        Alan Donovan . unresolved

        In fewer words:

        ```
        The numeric components consist only of sequences of decimal
        digits [0-9] denoting non-negative integers. For example:
        ```

        Line 42, Patchset 4 (Latest): if len(a) == 0 || len(b) == 0 {
        Alan Donovan . unresolved

        Simpler and no less efficient: a == "" || b == ""

        Line 46, Patchset 4 (Latest): if !(isdigit(a[0]) && isdigit(b[0])) {
        // When at least one of them is not a number,
        // we compare them lexicographically.
        Alan Donovan . unresolved

        This logic is not consistent with the conceptual explanation based on splitting into digit and non-digit components. Consider a="x0" b="x#1": after the prefix "x" we compare bytes '0' and '#', so `a` is the greater. But the "components" explanation would mean we are comparing the tuples ("x", 0) and ("x#", 1), which results in `a` being the lesser. The Wikipedia article suggests that the conceptual explanation is correct and thus that the logic will need to be adjusted.

        Could you add a test case for that input? Thanks.

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Egon Elbre
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 4
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: Alan Donovan <adon...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Egon Elbre <egon...@gmail.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 15:06:56 +0000
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 10:21:13 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
        Attention needed from Egon Elbre and Florian Lehner

        Egon Elbre uploaded new patchset

        Egon Elbre uploaded patch set #5 to this change.
        Open in Gerrit

        Related details

        Attention is currently required from:
        • Egon Elbre
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: newpatchset
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 5
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 10:22:35 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, Alan Donovan, kokoro, Go LUCI, golang-co...@googlegroups.com
        Attention needed from Alan Donovan and Florian Lehner

        Egon Elbre added 4 comments

        File internal/natsort/string.go
        Line 6, Patchset 1:package natsort
        Alan Donovan . unresolved

        Perhaps natural.Compare would be a better name for the main function of this package? If so let's call the file natural/compare.go too.

        Egon Elbre

        I had trouble figuring out what to call it. There are also package names such as `alphanumeric` or `alphanum` that would fit. I did also consider `natural`, but for some reason it feels like it's not that descriptive and that it's related to ordering strings. Although, since it's called "natural sort order", I think `natural` as a package name is fine as well.

        Egon Elbre

        Done

        Alan Donovan

        Thanks. I think compare.go makes the most sense for the file name.

        Egon Elbre

        Ah, I missed that comment.

        File internal/natural/string.go
        Line 29, Patchset 4:// Implementation only handles numbers [0-9]+, there's no special treatment
        Alan Donovan . resolved

        In fewer words:

        ```
        The numeric components consist only of sequences of decimal
        digits [0-9] denoting non-negative integers. For example:
        ```

        Egon Elbre

        Done

        Line 42, Patchset 4: if len(a) == 0 || len(b) == 0 {
        Alan Donovan . resolved

        Simpler and no less efficient: a == "" || b == ""

        Egon Elbre

        Done

        Line 46, Patchset 4: if !(isdigit(a[0]) && isdigit(b[0])) {

        // When at least one of them is not a number,
        // we compare them lexicographically.
        Alan Donovan . unresolved

        This logic is not consistent with the conceptual explanation based on splitting into digit and non-digit components. Consider a="x0" b="x#1": after the prefix "x" we compare bytes '0' and '#', so `a` is the greater. But the "components" explanation would mean we are comparing the tuples ("x", 0) and ("x#", 1), which results in `a` being the lesser. The Wikipedia article suggests that the conceptual explanation is correct and thus that the logic will need to be adjusted.

        Could you add a test case for that input? Thanks.

        Egon Elbre

        Indeed. I missed this case, should be now fixed.

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Alan Donovan
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 5
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: Alan Donovan <adon...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Attention: Alan Donovan <adon...@google.com>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 15:22:27 +0000
        unsatisfied_requirement
        open
        diffy

        Alan Donovan (Gerrit)

        unread,
        Jan 16, 2026, 10:45:57 AM (yesterday) Jan 16
        to Egon Elbre, goph...@pubsubhelper.golang.org, kokoro, Go LUCI, golang-co...@googlegroups.com
        Attention needed from Egon Elbre and Florian Lehner

        Alan Donovan added 4 comments

        Patchset-level comments
        File-level comment, Patchset 5 (Latest):
        Alan Donovan . resolved

        Very nice.

        File internal/natural/compare.go
        Line 45, Patchset 5 (Latest): if adig, bdig := isdigit(a[0]), isdigit(b[0]); !(adig && bdig) {
        Alan Donovan . unresolved

        Slightly clearer, and with fewer conditional branches in the common case:
        ```
        adig := isdigit(a[0])
        bdig := isdigit(b[0])

        // digit vs non-digit?
        // The one with the digit is smaller because its non-digit sequence is shorter.
        if adig != bdig {
        return -b2i(adig)
        }
        // Inv: adig == bdig
        // If both are non-digits, compare lexicographically.
        if !adig {
        return -b2i(a[0] < b[0])
        }
        // Inv: adig && bdig


        ...


        func b2i(b bool) int { if b { return 1 } else { return 0 } }
        ```

        Line 48, Patchset 5 (Latest): // with the digit is smaller, because it's non-digit sequence is
        Alan Donovan . unresolved

        its

        File internal/natural/compare_test.go
        Line 5, Patchset 5 (Latest):package natural
        Alan Donovan . unresolved

        natural_test (+ import), since we're testing only the public API.

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Egon Elbre
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 5
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: Alan Donovan <adon...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Egon Elbre <egon...@gmail.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 15:45:53 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: No
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 11:03:45 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
        Attention needed from Egon Elbre and Florian Lehner

        Egon Elbre uploaded new patchset

        Egon Elbre uploaded patch set #6 to this change.
        Open in Gerrit

        Related details

        Attention is currently required from:
        • Egon Elbre
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: newpatchset
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 6
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Alan Donovan <adon...@google.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 11:03:58 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, Alan Donovan, kokoro, Go LUCI, golang-co...@googlegroups.com
        Attention needed from Alan Donovan and Florian Lehner

        Egon Elbre added 3 comments

        File internal/natural/compare.go
        Line 45, Patchset 5: if adig, bdig := isdigit(a[0]), isdigit(b[0]); !(adig && bdig) {
        Alan Donovan . unresolved

        Slightly clearer, and with fewer conditional branches in the common case:
        ```
        adig := isdigit(a[0])
        bdig := isdigit(b[0])

        // digit vs non-digit?
        // The one with the digit is smaller because its non-digit sequence is shorter.
        if adig != bdig {
        return -b2i(adig)
        }
        // Inv: adig == bdig
        // If both are non-digits, compare lexicographically.
        if !adig {
        return -b2i(a[0] < b[0])
        }
        // Inv: adig && bdig


        ...


        func b2i(b bool) int { if b { return 1 } else { return 0 } }
        ```

        Egon Elbre

        Ah, this is much nicer.

        Line 48, Patchset 5: // with the digit is smaller, because it's non-digit sequence is
        Alan Donovan . resolved

        its

        Egon Elbre

        Done

        File internal/natural/compare_test.go
        Line 5, Patchset 5:package natural
        Alan Donovan . resolved

        natural_test (+ import), since we're testing only the public API.

        Egon Elbre

        Done

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Alan Donovan
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 5
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Alan Donovan <adon...@google.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Attention: Alan Donovan <adon...@google.com>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 16:03:50 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: No
        Comment-In-Reply-To: Alan Donovan <adon...@google.com>
        unsatisfied_requirement
        open
        diffy

        Alan Donovan (Gerrit)

        unread,
        Jan 16, 2026, 11:20:15 AM (yesterday) Jan 16
        to Egon Elbre, goph...@pubsubhelper.golang.org, kokoro, Go LUCI, golang-co...@googlegroups.com
        Attention needed from Egon Elbre and Florian Lehner

        Alan Donovan added 2 comments

        File internal/natural/compare.go
        Line 45, Patchset 5: if adig, bdig := isdigit(a[0]), isdigit(b[0]); !(adig && bdig) {
        Alan Donovan . unresolved

        Slightly clearer, and with fewer conditional branches in the common case:
        ```
        adig := isdigit(a[0])
        bdig := isdigit(b[0])

        // digit vs non-digit?
        // The one with the digit is smaller because its non-digit sequence is shorter.
        if adig != bdig {
        return -b2i(adig)
        }
        // Inv: adig == bdig
        // If both are non-digits, compare lexicographically.
        if !adig {
        return -b2i(a[0] < b[0])
        }
        // Inv: adig && bdig


        ...


        func b2i(b bool) int { if b { return 1 } else { return 0 } }
        ```

        Egon Elbre

        Ah, this is much nicer.

        Alan Donovan

        Sorry, I wasn't thinking clearly. Functions named b2i (or btoi) with this signature typically map true to 1 and false to 0, as George Boole himself would have done, rather than returning a signed value, so it is confusing to use the same name for this function.

        Let's call it boolToSign. And then I will stop nitpicking and approve the CL.

        Line 86, Patchset 6 (Latest):
        // b2i converts a boolean to an integer, 1 or -1.

        func b2i(b bool) int {
        if b {
        return 1
        } else {
        return -1
        }
        }
        Alan Donovan . unresolved

        Sorry, I wasn't thinking clearly. Functions of this name and signaturevery commonly map true to 1 and false to 0, as George Boole himself would have done, rather than returning a signed value, so it is potentially confusing to use the same name here.

        Let's call it boolToSign.

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Egon Elbre
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 6
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Alan Donovan <adon...@google.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Egon Elbre <egon...@gmail.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 16:20:11 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: No
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 11:23:00 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, golang-co...@googlegroups.com
        Attention needed from Egon Elbre and Florian Lehner

        Egon Elbre uploaded new patchset

        Egon Elbre uploaded patch set #7 to this change.
        Open in Gerrit

        Related details

        Attention is currently required from:
        • Egon Elbre
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: newpatchset
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 7
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 11:23:32 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, Alan Donovan, kokoro, Go LUCI, golang-co...@googlegroups.com
        Attention needed from Alan Donovan and Florian Lehner

        Egon Elbre added 2 comments

        File internal/natural/compare.go
        Line 45, Patchset 5: if adig, bdig := isdigit(a[0]), isdigit(b[0]); !(adig && bdig) {
        Alan Donovan . resolved

        Slightly clearer, and with fewer conditional branches in the common case:
        ```
        adig := isdigit(a[0])
        bdig := isdigit(b[0])

        // digit vs non-digit?
        // The one with the digit is smaller because its non-digit sequence is shorter.
        if adig != bdig {
        return -b2i(adig)
        }
        // Inv: adig == bdig
        // If both are non-digits, compare lexicographically.
        if !adig {
        return -b2i(a[0] < b[0])
        }
        // Inv: adig && bdig


        ...


        func b2i(b bool) int { if b { return 1 } else { return 0 } }
        ```

        Egon Elbre

        Ah, this is much nicer.

        Alan Donovan

        Sorry, I wasn't thinking clearly. Functions named b2i (or btoi) with this signature typically map true to 1 and false to 0, as George Boole himself would have done, rather than returning a signed value, so it is confusing to use the same name for this function.

        Let's call it boolToSign. And then I will stop nitpicking and approve the CL.

        Egon Elbre

        Done


        // b2i converts a boolean to an integer, 1 or -1.
        func b2i(b bool) int {
        if b {
        return 1
        } else {
        return -1
        }
        }
        Alan Donovan . resolved

        Sorry, I wasn't thinking clearly. Functions of this name and signaturevery commonly map true to 1 and false to 0, as George Boole himself would have done, rather than returning a signed value, so it is potentially confusing to use the same name here.

        Let's call it boolToSign.

        Egon Elbre

        No worries, and I do appreciate a constructive nitpicking.

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Alan Donovan
        • Florian Lehner
        Submit Requirements:
        • requirement is not satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 6
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Alan Donovan <adon...@google.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Attention: Alan Donovan <adon...@google.com>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 16:23:27 +0000
        unsatisfied_requirement
        open
        diffy

        Alan Donovan (Gerrit)

        unread,
        Jan 16, 2026, 11:24:59 AM (yesterday) Jan 16
        to Egon Elbre, goph...@pubsubhelper.golang.org, kokoro, Go LUCI, golang-co...@googlegroups.com
        Attention needed from Egon Elbre and Florian Lehner

        Alan Donovan voted and added 1 comment

        Votes added by Alan Donovan

        Auto-Submit+1
        Code-Review+2
        Commit-Queue+1

        1 comment

        Patchset-level comments
        File-level comment, Patchset 7 (Latest):
        Alan Donovan . resolved

        Thanks again.

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Egon Elbre
        • Florian Lehner
        Submit Requirements:
        • requirement satisfiedCode-Review
        • requirement is not satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 7
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Alan Donovan <adon...@google.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Egon Elbre <egon...@gmail.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 16:24:54 +0000
        Gerrit-HasComments: Yes
        Gerrit-Has-Labels: Yes
        satisfied_requirement
        unsatisfied_requirement
        open
        diffy

        Egon Elbre (Gerrit)

        unread,
        Jan 16, 2026, 11:33:10 AM (yesterday) Jan 16
        to goph...@pubsubhelper.golang.org, Alan Donovan, kokoro, Go LUCI, golang-co...@googlegroups.com
        Attention needed from Florian Lehner

        Egon Elbre added 3 comments

        File internal/natsort/string.go
        Line 6, Patchset 1:package natsort
        Alan Donovan . resolved

        Perhaps natural.Compare would be a better name for the main function of this package? If so let's call the file natural/compare.go too.

        Egon Elbre

        I had trouble figuring out what to call it. There are also package names such as `alphanumeric` or `alphanum` that would fit. I did also consider `natural`, but for some reason it feels like it's not that descriptive and that it's related to ordering strings. Although, since it's called "natural sort order", I think `natural` as a package name is fine as well.

        Egon Elbre

        Done

        Alan Donovan

        Thanks. I think compare.go makes the most sense for the file name.

        Egon Elbre

        Ah, I missed that comment.

        Egon Elbre

        Done

        Line 12, Patchset 1:// Compare implements natural string sorting, where numbers are compared numerically.
        Alan Donovan . resolved

        This could use a more precise definition of exactly what it computes.

        (What counts as a number? What base? Are leading zeros permitted? It is a weak order: i.e. can two unequal strings Compare equal? etc)

        Egon Elbre

        Added examples and clarification on the behaviour.

        Egon Elbre

        Done

        File internal/natural/string.go
        Line 46, Patchset 4: if !(isdigit(a[0]) && isdigit(b[0])) {
        // When at least one of them is not a number,
        // we compare them lexicographically.
        Alan Donovan . resolved

        This logic is not consistent with the conceptual explanation based on splitting into digit and non-digit components. Consider a="x0" b="x#1": after the prefix "x" we compare bytes '0' and '#', so `a` is the greater. But the "components" explanation would mean we are comparing the tuples ("x", 0) and ("x#", 1), which results in `a` being the lesser. The Wikipedia article suggests that the conceptual explanation is correct and thus that the logic will need to be adjusted.

        Could you add a test case for that input? Thanks.

        Egon Elbre

        Indeed. I missed this case, should be now fixed.

        Egon Elbre

        Done

        Open in Gerrit

        Related details

        Attention is currently required from:
        • Florian Lehner
        Submit Requirements:
        • requirement satisfiedCode-Review
        • requirement satisfiedNo-Unresolved-Comments
        • requirement is not satisfiedReview-Enforcement
        • requirement is not satisfiedTryBots-Pass
        • requirement is not satisfiedkokoro-CI-Passes
        Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
        Gerrit-MessageType: comment
        Gerrit-Project: pkgsite
        Gerrit-Branch: master
        Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
        Gerrit-Change-Number: 736560
        Gerrit-PatchSet: 7
        Gerrit-Owner: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Alan Donovan <adon...@google.com>
        Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
        Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Reviewer: kokoro <noreply...@google.com>
        Gerrit-CC: kokoro <noreply...@google.com>
        Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
        Gerrit-Comment-Date: Fri, 16 Jan 2026 16:33:03 +0000
        satisfied_requirement
        unsatisfied_requirement
        open
        diffy

        kokoro (Gerrit)

        unread,
        Jan 16, 2026, 11:50:23 AM (yesterday) Jan 16
        to Egon Elbre, goph...@pubsubhelper.golang.org, Go LUCI, Alan Donovan, golang-co...@googlegroups.com
        Attention needed from Florian Lehner

        kokoro voted kokoro-CI+1

        Kokoro presubmit build finished with status: SUCCESS

        Related details

        Attention is currently required from:
        • Florian Lehner
        Submit Requirements:
          • requirement satisfiedCode-Review
          • requirement satisfiedNo-Unresolved-Comments
          • requirement is not satisfiedReview-Enforcement
          • requirement satisfiedTryBots-Pass
          • requirement satisfiedkokoro-CI-Passes
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: pkgsite
          Gerrit-Branch: master
          Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
          Gerrit-Change-Number: 736560
          Gerrit-PatchSet: 7
          Gerrit-Owner: Egon Elbre <egon...@gmail.com>
          Gerrit-Reviewer: Alan Donovan <adon...@google.com>
          Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
          Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
          Gerrit-Reviewer: kokoro <noreply...@google.com>
          Gerrit-CC: kokoro <noreply...@google.com>
          Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
          Gerrit-Comment-Date: Fri, 16 Jan 2026 16:50:19 +0000
          Gerrit-HasComments: No
          Gerrit-Has-Labels: Yes
          satisfied_requirement
          unsatisfied_requirement
          open
          diffy

          Michael Pratt (Gerrit)

          unread,
          Jan 16, 2026, 3:36:32 PM (yesterday) Jan 16
          to Egon Elbre, goph...@pubsubhelper.golang.org, Michael Pratt, kokoro, Go LUCI, Alan Donovan, golang-co...@googlegroups.com
          Attention needed from Egon Elbre and Florian Lehner

          Michael Pratt added 1 comment

          Commit Message
          Line 14, Patchset 7 (Latest):Updates #77160
          Michael Pratt . unresolved

          ```suggestion
          Updates golang/go#77160
          ```

          This is why the CL didn't get linked to the issue.

          Open in Gerrit

          Related details

          Attention is currently required from:
          • Egon Elbre
          • Florian Lehner
          Submit Requirements:
          • requirement satisfiedCode-Review
          • requirement is not satisfiedNo-Unresolved-Comments
          • requirement is not satisfiedReview-Enforcement
          • requirement satisfiedTryBots-Pass
          • requirement satisfiedkokoro-CI-Passes
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: pkgsite
          Gerrit-Branch: master
          Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
          Gerrit-Change-Number: 736560
          Gerrit-PatchSet: 7
          Gerrit-Owner: Egon Elbre <egon...@gmail.com>
          Gerrit-Reviewer: Alan Donovan <adon...@google.com>
          Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
          Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
          Gerrit-Reviewer: kokoro <noreply...@google.com>
          Gerrit-CC: Michael Pratt <mpr...@google.com>
          Gerrit-CC: kokoro <noreply...@google.com>
          Gerrit-Attention: Egon Elbre <egon...@gmail.com>
          Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
          Gerrit-Comment-Date: Fri, 16 Jan 2026 20:36:29 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: No
          satisfied_requirement
          unsatisfied_requirement
          open
          diffy

          Egon Elbre (Gerrit)

          unread,
          Jan 16, 2026, 3:58:25 PM (yesterday) Jan 16
          to goph...@pubsubhelper.golang.org, Michael Pratt, kokoro, Go LUCI, Alan Donovan, golang-co...@googlegroups.com
          Attention needed from Florian Lehner and Michael Pratt

          Egon Elbre added 1 comment

          Commit Message
          Michael Pratt . resolved

          ```suggestion
          Updates golang/go#77160
          ```

          This is why the CL didn't get linked to the issue.

          Egon Elbre

          Fix applied.

          Open in Gerrit

          Related details

          Attention is currently required from:
          • Florian Lehner
          • Michael Pratt
          Submit Requirements:
          • requirement satisfiedCode-Review
          • requirement satisfiedNo-Unresolved-Comments
          • requirement is not satisfiedReview-Enforcement
          • requirement satisfiedTryBots-Pass
          • requirement satisfiedkokoro-CI-Passes
          Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
          Gerrit-MessageType: comment
          Gerrit-Project: pkgsite
          Gerrit-Branch: master
          Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
          Gerrit-Change-Number: 736560
          Gerrit-PatchSet: 7
          Gerrit-Owner: Egon Elbre <egon...@gmail.com>
          Gerrit-Reviewer: Alan Donovan <adon...@google.com>
          Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
          Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
          Gerrit-Reviewer: kokoro <noreply...@google.com>
          Gerrit-CC: Michael Pratt <mpr...@google.com>
          Gerrit-CC: kokoro <noreply...@google.com>
          Gerrit-Attention: Michael Pratt <mpr...@google.com>
          Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
          Gerrit-Comment-Date: Fri, 16 Jan 2026 20:58:18 +0000
          Gerrit-HasComments: Yes
          Gerrit-Has-Labels: No
          Comment-In-Reply-To: Michael Pratt <mpr...@google.com>
          satisfied_requirement
          unsatisfied_requirement
          open
          diffy

          Michael Pratt (Gerrit)

          unread,
          Jan 16, 2026, 4:16:13 PM (yesterday) Jan 16
          to Egon Elbre, goph...@pubsubhelper.golang.org, Michael Pratt, kokoro, Go LUCI, Alan Donovan, golang-co...@googlegroups.com
          Attention needed from Alan Donovan, Egon Elbre and Florian Lehner

          Michael Pratt voted Code-Review+1

          Code-Review+1
          Open in Gerrit

          Related details

          Attention is currently required from:
          • Alan Donovan
          • Egon Elbre
          • Florian Lehner
          Submit Requirements:
            • requirement satisfiedCode-Review
            • requirement satisfiedNo-Unresolved-Comments
            • requirement satisfiedReview-Enforcement
            • requirement satisfiedTryBots-Pass
            • requirement is not satisfiedkokoro-CI-Passes
            Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
            Gerrit-MessageType: comment
            Gerrit-Project: pkgsite
            Gerrit-Branch: master
            Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
            Gerrit-Change-Number: 736560
            Gerrit-PatchSet: 8
            Gerrit-Owner: Egon Elbre <egon...@gmail.com>
            Gerrit-Reviewer: Alan Donovan <adon...@google.com>
            Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
            Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
            Gerrit-Reviewer: Michael Pratt <mpr...@google.com>
            Gerrit-Reviewer: kokoro <noreply...@google.com>
            Gerrit-CC: kokoro <noreply...@google.com>
            Gerrit-Attention: Egon Elbre <egon...@gmail.com>
            Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
            Gerrit-Attention: Alan Donovan <adon...@google.com>
            Gerrit-Comment-Date: Fri, 16 Jan 2026 21:16:09 +0000
            Gerrit-HasComments: No
            Gerrit-Has-Labels: Yes
            satisfied_requirement
            unsatisfied_requirement
            open
            diffy

            Michael Pratt (Gerrit)

            unread,
            Jan 16, 2026, 4:16:39 PM (yesterday) Jan 16
            to Egon Elbre, goph...@pubsubhelper.golang.org, Michael Pratt, kokoro, Go LUCI, Alan Donovan, golang-co...@googlegroups.com
            Attention needed from Alan Donovan, Egon Elbre and Florian Lehner

            Michael Pratt voted

            Auto-Submit+1
            Commit-Queue+1
            Gerrit-Comment-Date: Fri, 16 Jan 2026 21:16:36 +0000
            Gerrit-HasComments: No
            Gerrit-Has-Labels: Yes
            satisfied_requirement
            unsatisfied_requirement
            open
            diffy

            kokoro (Gerrit)

            unread,
            Jan 16, 2026, 4:41:27 PM (yesterday) Jan 16
            to Egon Elbre, goph...@pubsubhelper.golang.org, Michael Pratt, Go LUCI, Alan Donovan, golang-co...@googlegroups.com
            Attention needed from Alan Donovan, Egon Elbre and Florian Lehner

            kokoro voted kokoro-CI+1

            Kokoro presubmit build finished with status: SUCCESS

            Related details

            Attention is currently required from:
            • Alan Donovan
            • Egon Elbre
            • Florian Lehner
            Submit Requirements:
              • requirement satisfiedCode-Review
              • requirement satisfiedNo-Unresolved-Comments
              • requirement satisfiedReview-Enforcement
              • requirement satisfiedTryBots-Pass
              • requirement satisfiedkokoro-CI-Passes
              Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
              Gerrit-MessageType: comment
              Gerrit-Project: pkgsite
              Gerrit-Branch: master
              Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
              Gerrit-Change-Number: 736560
              Gerrit-PatchSet: 8
              Gerrit-Owner: Egon Elbre <egon...@gmail.com>
              Gerrit-Reviewer: Alan Donovan <adon...@google.com>
              Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
              Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
              Gerrit-Reviewer: Michael Pratt <mpr...@google.com>
              Gerrit-Reviewer: kokoro <noreply...@google.com>
              Gerrit-CC: kokoro <noreply...@google.com>
              Gerrit-Attention: Egon Elbre <egon...@gmail.com>
              Gerrit-Attention: Florian Lehner <lehner.f...@gmail.com>
              Gerrit-Attention: Alan Donovan <adon...@google.com>
              Gerrit-Comment-Date: Fri, 16 Jan 2026 21:41:20 +0000
              Gerrit-HasComments: No
              Gerrit-Has-Labels: Yes
              satisfied_requirement
              open
              diffy

              Gopher Robot (Gerrit)

              unread,
              Jan 16, 2026, 4:42:02 PM (yesterday) Jan 16
              to Egon Elbre, goph...@pubsubhelper.golang.org, golang-...@googlegroups.com, kokoro, Michael Pratt, Go LUCI, Alan Donovan, golang-co...@googlegroups.com

              Gopher Robot submitted the change

              Unreviewed changes

              7 is the latest approved patch-set.
              No files were changed between the latest approved patch-set and the submitted one.

              Change information

              Commit message:
              internal/natural: add natural sort order

              Natural sort order allows comparing strings such that sequences of digits
              are compared numerically rather than lexicographically. For example:

              "uint8" < "uint16" < "uint32"

              Updates golang/go#77160
              Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
              Reviewed-by: Alan Donovan <adon...@google.com>
              Auto-Submit: Michael Pratt <mpr...@google.com>
              Reviewed-by: Michael Pratt <mpr...@google.com>
              kokoro-CI: kokoro <noreply...@google.com>
              Files:
              • A internal/natural/compare.go
              • A internal/natural/compare_test.go
              Change size: M
              Delta: 2 files changed, 242 insertions(+), 0 deletions(-)
              Branch: refs/heads/master
              Submit Requirements:
              • requirement satisfiedCode-Review: +2 by Alan Donovan, +1 by Michael Pratt
              • requirement satisfiedTryBots-Pass: LUCI-TryBot-Result+1 by Go LUCI
              • requirement satisfiedkokoro-CI-Passes: kokoro-CI+1 by kokoro
              Open in Gerrit
              Inspect html for hidden footers to help with email filtering. To unsubscribe visit settings. DiffyGerrit
              Gerrit-MessageType: merged
              Gerrit-Project: pkgsite
              Gerrit-Branch: master
              Gerrit-Change-Id: Iddf6aa33427131a5f0d7f235d61ab7ad6cf6f92c
              Gerrit-Change-Number: 736560
              Gerrit-PatchSet: 9
              Gerrit-Owner: Egon Elbre <egon...@gmail.com>
              Gerrit-Reviewer: Alan Donovan <adon...@google.com>
              Gerrit-Reviewer: Egon Elbre <egon...@gmail.com>
              Gerrit-Reviewer: Florian Lehner <lehner.f...@gmail.com>
              Gerrit-Reviewer: Gopher Robot <go...@golang.org>
              open
              diffy
              satisfied_requirement
              Reply all
              Reply to author
              Forward
              0 new messages