Repository: go-kratos/kratos
Pull request #3525 (2025-01-24 09:09:39)

fix: Improve server stop handling with graceful shutdowns
参考 gRPC 官方示例，当 Server 未能及时优雅退出时，执行强制退出。

https://github.com/grpc/grpc-go/blob/2fd426d0919db7e9e7920e365dd30674c4c9fe90/examples/features/gracefulstop/server/main.go#L89-L100


shenqidebaozi: This pull request includes several changes to improve the stop functionality of both gRPC and HTTP servers, as well as adding corresponding tests to ensure graceful shutdowns or forced stops when necessary.

Improvements to gRPC server stop functionality:

* [`transport/grpc/server.go`](diffhunk://#diff-8092add2b44afc3e08fb97d49c66531be06284636d9aca154fe14b274a8e2e5dL226-R244): Modified the `Stop` method to attempt a graceful stop and fall back to a forced stop if the context times out.

Enhancements to HTTP server stop functionality:

* [`transport/http/server.go`](diffhunk://#diff-426e08d4de8df9b60466adbedc02481096caf3b15a6da446e7604d4f6c1ec7fbL346-R353): Updated the `Stop` method to handle graceful shutdowns and force stop the server if the context times out.

Additional imports for testing:

* [`transport/grpc/server_test.go`](diffhunk://#diff-941be77a2648ff454b1918add813c0fa3696e7c2b76e01eb2bf7e3806d92fe38R7): Added imports for `io` and `log` to facilitate the new test cases. [[1]](diffhunk://#diff-941be77a2648ff454b1918add813c0fa3696e7c2b76e01eb2bf7e3806d92fe38R7) [[2]](diffhunk://#diff-941be77a2648ff454b1918add813c0fa3696e7c2b76e01eb2bf7e3806d92fe38R21)
* [`transport/http/server_test.go`](diffhunk://#diff-63b85b47c66cba853ef12db7dfc98b18262fc900674c005fd2969462b3b250bdR4): Added imports for `bytes`, `net/http/httptest`, and `log` to support the new stop tests. [[1]](diffhunk://#diff-63b85b47c66cba853ef12db7dfc98b18262fc900674c005fd2969462b3b250bdR4) [[2]](diffhunk://#diff-63b85b47c66cba853ef12db7dfc98b18262fc900674c005fd2969462b3b250bdR13-R21)

New test cases for stop functionality:

* [`transport/grpc/server_test.go`](diffhunk://#diff-941be77a2648ff454b1918add813c0fa3696e7c2b76e01eb2bf7e3806d92fe38R376-R480): Added `TestStop` to verify both graceful and forced stop scenarios for the gRPC server.
* [`transport/http/server_test.go`](diffhunk://#diff-63b85b47c66cba853ef12db7dfc98b18262fc900674c005fd2969462b3b250bdR388-R466): Added `TestStop` to validate the graceful and forced stop behavior for the HTTP server.

Patch:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index e794e431..9e87d307 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -13,7 +13,7 @@ jobs:
   build:
     strategy:
       matrix:
-        go: [ 1.20.x, 1.21.x, 1.22.x ]
+        go: [ 1.21.x, 1.22.x, 1.23.x ]
     name: build & test
     runs-on: ubuntu-latest
     services:
diff --git a/app.go b/app.go
index bb406aac..cf85868a 100644
--- a/app.go
+++ b/app.go
@@ -41,7 +41,6 @@ func New(opts ...Option) *App {
 		ctx:              context.Background(),
 		sigs:             []os.Signal{syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT},
 		registrarTimeout: 10 * time.Second,
-		stopTimeout:      10 * time.Second,
 	}
 	if id, err := uuid.NewUUID(); err == nil {
 		o.id = id.String()
@@ -98,18 +97,23 @@ func (a *App) Run() error {
 			return err
 		}
 	}
+	octx := NewContext(a.opts.ctx, a)
 	for _, srv := range a.opts.servers {
 		server := srv
 		eg.Go(func() error {
 			<-ctx.Done() // wait for stop signal
-			stopCtx, cancel := context.WithTimeout(NewContext(a.opts.ctx, a), a.opts.stopTimeout)
-			defer cancel()
+			stopCtx := octx
+			if a.opts.stopTimeout > 0 {
+				var cancel context.CancelFunc
+				stopCtx, cancel = context.WithTimeout(stopCtx, a.opts.stopTimeout)
+				defer cancel()
+			}
 			return server.Stop(stopCtx)
 		})
 		wg.Add(1)
 		eg.Go(func() error {
 			wg.Done() // here is to ensure server start has begun running before register, so defer is not needed
-			return server.Start(NewContext(a.opts.ctx, a))
+			return server.Start(octx)
 		})
 	}
 	wg.Wait()
diff --git a/cmd/kratos/go.mod b/cmd/kratos/go.mod
index 64d03ae4..67de97ac 100644
--- a/cmd/kratos/go.mod
+++ b/cmd/kratos/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/cmd/kratos/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/AlecAivazis/survey/v2 v2.3.7
diff --git a/cmd/protoc-gen-go-errors/go.mod b/cmd/protoc-gen-go-errors/go.mod
index 1f5982d4..7663c050 100644
--- a/cmd/protoc-gen-go-errors/go.mod
+++ b/cmd/protoc-gen-go-errors/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2
 
-go 1.19
+go 1.21
 
 require (
 	golang.org/x/text v0.3.8
diff --git a/cmd/protoc-gen-go-http/go.mod b/cmd/protoc-gen-go-http/go.mod
index a286ceac..4fe6b849 100644
--- a/cmd/protoc-gen-go-http/go.mod
+++ b/cmd/protoc-gen-go-http/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2
 
-go 1.19
+go 1.21
 
 require (
 	google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd
diff --git a/contrib/config/apollo/go.mod b/contrib/config/apollo/go.mod
index 7d3596c9..162a22db 100644
--- a/contrib/config/apollo/go.mod
+++ b/contrib/config/apollo/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/apollo/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/apolloconfig/agollo/v4 v4.3.1
diff --git a/contrib/config/consul/go.mod b/contrib/config/consul/go.mod
index b4d58890..734bab2a 100644
--- a/contrib/config/consul/go.mod
+++ b/contrib/config/consul/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/consul/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/config/etcd/go.mod b/contrib/config/etcd/go.mod
index efb1351e..2b4477d6 100644
--- a/contrib/config/etcd/go.mod
+++ b/contrib/config/etcd/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/etcd/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/config/kubernetes/go.mod b/contrib/config/kubernetes/go.mod
index 1db59c6b..ff3fc92a 100644
--- a/contrib/config/kubernetes/go.mod
+++ b/contrib/config/kubernetes/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/kubernetes/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/config/nacos/go.mod b/contrib/config/nacos/go.mod
index cfd7bdeb..081f783e 100644
--- a/contrib/config/nacos/go.mod
+++ b/contrib/config/nacos/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/nacos/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/config/polaris/go.mod b/contrib/config/polaris/go.mod
index 11156487..eb20f21b 100644
--- a/contrib/config/polaris/go.mod
+++ b/contrib/config/polaris/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/config/polaris/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/encoding/msgpack/go.mod b/contrib/encoding/msgpack/go.mod
index e1990a56..f681bde0 100644
--- a/contrib/encoding/msgpack/go.mod
+++ b/contrib/encoding/msgpack/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/encoding/msgpack/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/errortracker/sentry/go.mod b/contrib/errortracker/sentry/go.mod
index b8ac1247..baa657ab 100644
--- a/contrib/errortracker/sentry/go.mod
+++ b/contrib/errortracker/sentry/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/errortracker/sentry/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/getsentry/sentry-go v0.25.0
diff --git a/contrib/log/aliyun/go.mod b/contrib/log/aliyun/go.mod
index d434fb55..8249271b 100644
--- a/contrib/log/aliyun/go.mod
+++ b/contrib/log/aliyun/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/aliyun/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/aliyun/aliyun-log-go-sdk v0.1.75
diff --git a/contrib/log/fluent/go.mod b/contrib/log/fluent/go.mod
index 10b1abbd..b7b3972d 100644
--- a/contrib/log/fluent/go.mod
+++ b/contrib/log/fluent/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/fluent/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/fluent/fluent-logger-golang v1.9.0
diff --git a/contrib/log/logrus/go.mod b/contrib/log/logrus/go.mod
index cbb5e897..aa01bdf7 100644
--- a/contrib/log/logrus/go.mod
+++ b/contrib/log/logrus/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/logrus/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/log/tencent/go.mod b/contrib/log/tencent/go.mod
index 1141256d..22160891 100644
--- a/contrib/log/tencent/go.mod
+++ b/contrib/log/tencent/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/tencent/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/log/zap/go.mod b/contrib/log/zap/go.mod
index a886a171..61a977ab 100644
--- a/contrib/log/zap/go.mod
+++ b/contrib/log/zap/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/zap/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/log/zerolog/go.mod b/contrib/log/zerolog/go.mod
index b99d1580..4f4d924e 100644
--- a/contrib/log/zerolog/go.mod
+++ b/contrib/log/zerolog/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/log/zerolog/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/middleware/validate/README.md b/contrib/middleware/validate/README.md
new file mode 100644
index 00000000..2f2c4f0d
--- /dev/null
+++ b/contrib/middleware/validate/README.md
@@ -0,0 +1,15 @@
+# Validator Middleware for Kratos Project
+
+This module provides a middleware for Kratos to validate request parameters, using schema defined in `.proto` files.
+
+There used to be a middleware named `Validator` in Kratos, which calls the generated validation functions
+from [PGV](https://github.com/bufbuild/protoc-gen-validate) at runtime. Since PGV has been
+in [maintenance](https://github.com/bufbuild/protoc-gen-validate/commit/4a8ffc4942463929c4289407cd4b8c8328ff5422), and
+recommend using [protovalidate](https://github.com/bufbuild/protovalidate) as an alternative.
+
+That's why we provide a new middleware that uses the schema definitions and validation functions provided by
+protovalidate.
+
+protovalidate no longer requires code generation at build time, but for compatibility with existing Kratos
+projects, we enable the legacy mode of protovalidate. For most users, no changes are needed to existing code. **But for
+users who have manually implemented the Validator interface, you need to migrate the relevant implementation yourself**.
\ No newline at end of file
diff --git a/contrib/middleware/validate/go.mod b/contrib/middleware/validate/go.mod
new file mode 100644
index 00000000..fc55a704
--- /dev/null
+++ b/contrib/middleware/validate/go.mod
@@ -0,0 +1,24 @@
+module github.com/go-kratos/kratos/contrib/middleware/validate/v2
+
+go 1.21.1
+
+require (
+	buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.2-20241127180247-a33202765966.1
+	github.com/bufbuild/protovalidate-go v0.8.2
+	github.com/envoyproxy/protoc-gen-validate v1.1.0
+	github.com/go-kratos/kratos/v2 v2.8.3
+	google.golang.org/protobuf v1.36.2
+)
+
+require (
+	cel.dev/expr v0.18.0 // indirect
+	github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
+	github.com/google/cel-go v0.22.1 // indirect
+	github.com/stoewer/go-strcase v1.3.0 // indirect
+	golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 // indirect
+	golang.org/x/sys v0.21.0 // indirect
+	golang.org/x/text v0.16.0 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect
+	google.golang.org/grpc v1.65.0 // indirect
+)
diff --git a/contrib/middleware/validate/go.sum b/contrib/middleware/validate/go.sum
new file mode 100644
index 00000000..8616357f
--- /dev/null
+++ b/contrib/middleware/validate/go.sum
@@ -0,0 +1,51 @@
+buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.2-20241127180247-a33202765966.1 h1:BICM6du/XzvEgeorNo4xgohK3nMTmEPViGyd5t7xVqk=
+buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.2-20241127180247-a33202765966.1/go.mod h1:JnMVLi3qrNYPODVpEKG7UjHLl/d2zR221e66YCSmP2Q=
+cel.dev/expr v0.18.0 h1:CJ6drgk+Hf96lkLikr4rFf19WrU0BOWEihyZnI2TAzo=
+cel.dev/expr v0.18.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
+github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
+github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
+github.com/bufbuild/protovalidate-go v0.8.2 h1:sgzXHkHYP6HnAsL2Rd3I1JxkYUyEQUv9awU1PduMxbM=
+github.com/bufbuild/protovalidate-go v0.8.2/go.mod h1:K6w8iPNAXBoIivVueSELbUeUl+MmeTQfCDSug85pn3M=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
+github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
+github.com/go-kratos/kratos/v2 v2.8.3 h1:kkNBq0gvdX+b8cbaN+p6Sdh95DgMhx7GimefXb4o7Ss=
+github.com/go-kratos/kratos/v2 v2.8.3/go.mod h1:+Vfe3FzF0d+BfMdajA11jT0rAyJWublRE/seZQNZVxE=
+github.com/google/cel-go v0.22.1 h1:AfVXx3chM2qwoSbM7Da8g8hX8OVSkBFwX+rz2+PcK40=
+github.com/google/cel-go v0.22.1/go.mod h1:BuznPXXfQDpXKWQ9sPW3TzlAJN5zzFe+i9tIs0yC4s8=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
+github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
+golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
+golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
+golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
+google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw=
+google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=
+google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
+google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
+google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
+google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/contrib/middleware/validate/validate.go b/contrib/middleware/validate/validate.go
new file mode 100644
index 00000000..6aaf7f19
--- /dev/null
+++ b/contrib/middleware/validate/validate.go
@@ -0,0 +1,35 @@
+package validate
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/go-kratos/kratos/v2/errors"
+	"github.com/go-kratos/kratos/v2/middleware"
+
+	"github.com/bufbuild/protovalidate-go"
+	"github.com/bufbuild/protovalidate-go/legacy"
+	"google.golang.org/protobuf/proto"
+)
+
+// ProtoValidate is a middleware that validates the request message with [protovalidate](https://github.com/bufbuild/protovalidate)
+func ProtoValidate() middleware.Middleware {
+	validator, err := protovalidate.New(
+		// Some projects may still be using PGV, turn on legacy support to handle this.
+		legacy.WithLegacySupport(legacy.ModeMerge),
+	)
+	if err != nil {
+		panic(fmt.Errorf("protovalidate.New() error: %w", err))
+	}
+
+	return func(handler middleware.Handler) middleware.Handler {
+		return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
+			if msg, ok := req.(proto.Message); ok {
+				if err := validator.Validate(msg); err != nil {
+					return nil, errors.BadRequest("VALIDATOR", err.Error()).WithCause(err)
+				}
+			}
+			return handler(ctx, req)
+		}
+	}
+}
diff --git a/contrib/opensergo/go.mod b/contrib/opensergo/go.mod
index 7b1225e1..8523899c 100644
--- a/contrib/opensergo/go.mod
+++ b/contrib/opensergo/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/opensergo/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/polaris/go.mod b/contrib/polaris/go.mod
index be72efe5..b7ce5e50 100644
--- a/contrib/polaris/go.mod
+++ b/contrib/polaris/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/polaris/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/aegis v0.2.0
diff --git a/contrib/registry/consul/go.mod b/contrib/registry/consul/go.mod
index 4f7f71af..b7f53b9e 100644
--- a/contrib/registry/consul/go.mod
+++ b/contrib/registry/consul/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/consul/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/registry/discovery/go.mod b/contrib/registry/discovery/go.mod
index a6cae320..1888c199 100644
--- a/contrib/registry/discovery/go.mod
+++ b/contrib/registry/discovery/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/discovery/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/registry/etcd/go.mod b/contrib/registry/etcd/go.mod
index 68bbcf90..914974b0 100644
--- a/contrib/registry/etcd/go.mod
+++ b/contrib/registry/etcd/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/etcd/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/registry/eureka/go.mod b/contrib/registry/eureka/go.mod
index 2a47b223..cc08a5cf 100644
--- a/contrib/registry/eureka/go.mod
+++ b/contrib/registry/eureka/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/eureka/v2
 
-go 1.19
+go 1.21
 
 require github.com/go-kratos/kratos/v2 v2.8.3
 
diff --git a/contrib/registry/kubernetes/go.mod b/contrib/registry/kubernetes/go.mod
index bb8828cb..0a9c21b2 100644
--- a/contrib/registry/kubernetes/go.mod
+++ b/contrib/registry/kubernetes/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/kubernetes/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/registry/nacos/go.mod b/contrib/registry/nacos/go.mod
index 44bb2a37..4192fae8 100644
--- a/contrib/registry/nacos/go.mod
+++ b/contrib/registry/nacos/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/nacos/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/registry/polaris/go.mod b/contrib/registry/polaris/go.mod
index 49d0b70a..e88510b5 100644
--- a/contrib/registry/polaris/go.mod
+++ b/contrib/registry/polaris/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/polaris/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/contrib/registry/servicecomb/go.mod b/contrib/registry/servicecomb/go.mod
index f207fa2f..bcffdf23 100644
--- a/contrib/registry/servicecomb/go.mod
+++ b/contrib/registry/servicecomb/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/servicecomb/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-chassis/cari v0.6.0
diff --git a/contrib/registry/zookeeper/go.mod b/contrib/registry/zookeeper/go.mod
index a083feec..afe638ec 100644
--- a/contrib/registry/zookeeper/go.mod
+++ b/contrib/registry/zookeeper/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/contrib/registry/zookeeper/v2
 
-go 1.19
+go 1.21
 
 require (
 	github.com/go-kratos/kratos/v2 v2.8.3
diff --git a/go.mod b/go.mod
index cceda950..ba669874 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/go-kratos/kratos/v2
 
-go 1.20
+go 1.21
 
 require (
 	dario.cat/mergo v1.0.0
diff --git a/go.sum b/go.sum
index 6a20c5db..00afca12 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,9 @@
 dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
 github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
+github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
 github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
+github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -9,6 +11,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
 github.com/envoyproxy/go-control-plane v0.11.2-0.20230627204322-7d0032219fcb h1:kxNVXsNro/lpR5WD+P1FI/yUHn2G03Glber3k8cQL2Y=
 github.com/envoyproxy/go-control-plane v0.11.2-0.20230627204322-7d0032219fcb/go.mod h1:GxGqnjWzl1Gz8WfAfMJSfhvsi4EPZayRb25nLHDWXyA=
 github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
+github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
 github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
 github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
 github.com/go-kratos/aegis v0.2.0 h1:dObzCDWn3XVjUkgxyBp6ZeWtx/do0DPZ7LY3yNSJLUQ=
@@ -31,6 +34,7 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
 github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
diff --git a/middleware/validate/validate.go b/middleware/validate/validate.go
index f33d76e4..788a7ae4 100644
--- a/middleware/validate/validate.go
+++ b/middleware/validate/validate.go
@@ -12,6 +12,8 @@ type validator interface {
 }
 
 // Validator is a validator middleware.
+//
+// Deprecated: use github.com/go-kratos/kratos/contrib/middleware/validate/v2.ProtoValidate instead.
 func Validator() middleware.Middleware {
 	return func(handler middleware.Handler) middleware.Handler {
 		return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
diff --git a/third_party/buf/validate/README.md b/third_party/buf/validate/README.md
new file mode 100644
index 00000000..3657eba2
--- /dev/null
+++ b/third_party/buf/validate/README.md
@@ -0,0 +1,3 @@
+# protovalidate
+
+* https://github.com/bufbuild/protovalidate
\ No newline at end of file
diff --git a/third_party/buf/validate/validate.proto b/third_party/buf/validate/validate.proto
new file mode 100644
index 00000000..c6914f69
--- /dev/null
+++ b/third_party/buf/validate/validate.proto
@@ -0,0 +1,4902 @@
+// Copyright 2023 Buf Technologies, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+syntax = "proto2";
+
+package buf.validate;
+
+import "google/protobuf/descriptor.proto";
+import "google/protobuf/duration.proto";
+import "google/protobuf/timestamp.proto";
+
+option go_package = "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate";
+option java_multiple_files = true;
+option java_outer_classname = "ValidateProto";
+option java_package = "build.buf.validate";
+
+// MessageOptions is an extension to google.protobuf.MessageOptions. It allows
+// the addition of validation rules at the message level. These rules can be
+// applied to incoming messages to ensure they meet certain criteria before
+// being processed.
+extend google.protobuf.MessageOptions {
+  // Rules specify the validations to be performed on this message. By default,
+  // no validation is performed against a message.
+  optional MessageConstraints message = 1159;
+}
+
+// OneofOptions is an extension to google.protobuf.OneofOptions. It allows
+// the addition of validation rules on a oneof. These rules can be
+// applied to incoming messages to ensure they meet certain criteria before
+// being processed.
+extend google.protobuf.OneofOptions {
+  // Rules specify the validations to be performed on this oneof. By default,
+  // no validation is performed against a oneof.
+  optional OneofConstraints oneof = 1159;
+}
+
+// FieldOptions is an extension to google.protobuf.FieldOptions. It allows
+// the addition of validation rules at the field level. These rules can be
+// applied to incoming messages to ensure they meet certain criteria before
+// being processed.
+extend google.protobuf.FieldOptions {
+  // Rules specify the validations to be performed on this field. By default,
+  // no validation is performed against a field.
+  optional FieldConstraints field = 1159;
+
+  // Specifies predefined rules. When extending a standard constraint message,
+  // this adds additional CEL expressions that apply when the extension is used.
+  //
+  // ```proto
+  // extend buf.validate.Int32Rules {
+  //   bool is_zero [(buf.validate.predefined).cel = {
+  //     id: "int32.is_zero",
+  //     message: "value must be zero",
+  //     expression: "!rule || this == 0",
+  //   }];
+  // }
+  //
+  // message Foo {
+  //   int32 reserved = 1 [(buf.validate.field).int32.(is_zero) = true];
+  // }
+  // ```
+  optional PredefinedConstraints predefined = 1160;
+}
+
+// `Constraint` represents a validation rule written in the Common Expression
+// Language (CEL) syntax. Each Constraint includes a unique identifier, an
+// optional error message, and the CEL expression to evaluate. For more
+// information on CEL, [see our documentation](https://github.com/bufbuild/protovalidate/blob/main/docs/cel.md).
+//
+// ```proto
+// message Foo {
+//   option (buf.validate.message).cel = {
+//     id: "foo.bar"
+//     message: "bar must be greater than 0"
+//     expression: "this.bar > 0"
+//   };
+//   int32 bar = 1;
+// }
+// ```
+message Constraint {
+  // `id` is a string that serves as a machine-readable name for this Constraint.
+  // It should be unique within its scope, which could be either a message or a field.
+  optional string id = 1;
+
+  // `message` is an optional field that provides a human-readable error message
+  // for this Constraint when the CEL expression evaluates to false. If a
+  // non-empty message is provided, any strings resulting from the CEL
+  // expression evaluation are ignored.
+  optional string message = 2;
+
+  // `expression` is the actual CEL expression that will be evaluated for
+  // validation. This string must resolve to either a boolean or a string
+  // value. If the expression evaluates to false or a non-empty string, the
+  // validation is considered failed, and the message is rejected.
+  optional string expression = 3;
+}
+
+// MessageConstraints represents validation rules that are applied to the entire message.
+// It includes disabling options and a list of Constraint messages representing Common Expression Language (CEL) validation rules.
+message MessageConstraints {
+  // `disabled` is a boolean flag that, when set to true, nullifies any validation rules for this message.
+  // This includes any fields within the message that would otherwise support validation.
+  //
+  // ```proto
+  // message MyMessage {
+  //   // validation will be bypassed for this message
+  //   option (buf.validate.message).disabled = true;
+  // }
+  // ```
+  optional bool disabled = 1;
+
+  // `cel` is a repeated field of type Constraint. Each Constraint specifies a validation rule to be applied to this message.
+  // These constraints are written in Common Expression Language (CEL) syntax. For more information on
+  // CEL, [see our documentation](https://github.com/bufbuild/protovalidate/blob/main/docs/cel.md).
+  //
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field `foo` must be greater than 42.
+  //   option (buf.validate.message).cel = {
+  //     id: "my_message.value",
+  //     message: "value must be greater than 42",
+  //     expression: "this.foo > 42",
+  //   };
+  //   optional int32 foo = 1;
+  // }
+  // ```
+  repeated Constraint cel = 3;
+}
+
+// The `OneofConstraints` message type enables you to manage constraints for
+// oneof fields in your protobuf messages.
+message OneofConstraints {
+  // If `required` is true, exactly one field of the oneof must be present. A
+  // validation error is returned if no fields in the oneof are present. The
+  // field itself may still be a default value; further constraints
+  // should be placed on the fields themselves to ensure they are valid values,
+  // such as `min_len` or `gt`.
+  //
+  // ```proto
+  // message MyMessage {
+  //   oneof value {
+  //     // Either `a` or `b` must be set. If `a` is set, it must also be
+  //     // non-empty; whereas if `b` is set, it can still be an empty string.
+  //     option (buf.validate.oneof).required = true;
+  //     string a = 1 [(buf.validate.field).string.min_len = 1];
+  //     string b = 2;
+  //   }
+  // }
+  // ```
+  optional bool required = 1;
+}
+
+// FieldConstraints encapsulates the rules for each type of field. Depending on
+// the field, the correct set should be used to ensure proper validations.
+message FieldConstraints {
+  // `cel` is a repeated field used to represent a textual expression
+  // in the Common Expression Language (CEL) syntax. For more information on
+  // CEL, [see our documentation](https://github.com/bufbuild/protovalidate/blob/main/docs/cel.md).
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field `value` must be greater than 42.
+  //   optional int32 value = 1 [(buf.validate.field).cel = {
+  //     id: "my_message.value",
+  //     message: "value must be greater than 42",
+  //     expression: "this > 42",
+  //   }];
+  // }
+  // ```
+  repeated Constraint cel = 23;
+  // If `required` is true, the field must be populated. A populated field can be
+  // described as "serialized in the wire format," which includes:
+  //
+  // - the following "nullable" fields must be explicitly set to be considered populated:
+  //   - singular message fields (whose fields may be unpopulated/default values)
+  //   - member fields of a oneof (may be their default value)
+  //   - proto3 optional fields (may be their default value)
+  //   - proto2 scalar fields (both optional and required)
+  // - proto3 scalar fields must be non-zero to be considered populated
+  // - repeated and map fields must be non-empty to be considered populated
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field `value` must be set to a non-null value.
+  //   optional MyOtherMessage value = 1 [(buf.validate.field).required = true];
+  // }
+  // ```
+  optional bool required = 25;
+  // Skip validation on the field if its value matches the specified criteria.
+  // See Ignore enum for details.
+  //
+  // ```proto
+  // message UpdateRequest {
+  //   // The uri rule only applies if the field is populated and not an empty
+  //   // string.
+  //   optional string url = 1 [
+  //     (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE,
+  //     (buf.validate.field).string.uri = true,
+  //   ];
+  // }
+  // ```
+  optional Ignore ignore = 27;
+
+  oneof type {
+    // Scalar Field Types
+    FloatRules float = 1;
+    DoubleRules double = 2;
+    Int32Rules int32 = 3;
+    Int64Rules int64 = 4;
+    UInt32Rules uint32 = 5;
+    UInt64Rules uint64 = 6;
+    SInt32Rules sint32 = 7;
+    SInt64Rules sint64 = 8;
+    Fixed32Rules fixed32 = 9;
+    Fixed64Rules fixed64 = 10;
+    SFixed32Rules sfixed32 = 11;
+    SFixed64Rules sfixed64 = 12;
+    BoolRules bool = 13;
+    StringRules string = 14;
+    BytesRules bytes = 15;
+
+    // Complex Field Types
+    EnumRules enum = 16;
+    RepeatedRules repeated = 18;
+    MapRules map = 19;
+
+    // Well-Known Field Types
+    AnyRules any = 20;
+    DurationRules duration = 21;
+    TimestampRules timestamp = 22;
+  }
+
+  // DEPRECATED: use ignore=IGNORE_ALWAYS instead. TODO: remove this field pre-v1.
+  optional bool skipped = 24 [deprecated = true];
+  // DEPRECATED: use ignore=IGNORE_IF_UNPOPULATED instead. TODO: remove this field pre-v1.
+  optional bool ignore_empty = 26 [deprecated = true];
+}
+
+// PredefinedConstraints are custom constraints that can be re-used with
+// multiple fields.
+message PredefinedConstraints {
+  // `cel` is a repeated field used to represent a textual expression
+  // in the Common Expression Language (CEL) syntax. For more information on
+  // CEL, [see our documentation](https://github.com/bufbuild/protovalidate/blob/main/docs/cel.md).
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field `value` must be greater than 42.
+  //   optional int32 value = 1 [(buf.validate.predefined).cel = {
+  //     id: "my_message.value",
+  //     message: "value must be greater than 42",
+  //     expression: "this > 42",
+  //   }];
+  // }
+  // ```
+  repeated Constraint cel = 1;
+}
+
+// Specifies how FieldConstraints.ignore behaves. See the documentation for
+// FieldConstraints.required for definitions of "populated" and "nullable".
+enum Ignore {
+  // buf:lint:ignore ENUM_NO_ALLOW_ALIAS // allowance for deprecations. TODO: remove pre-v1.
+  option allow_alias = true;
+  // Validation is only skipped if it's an unpopulated nullable fields.
+  //
+  // ```proto
+  // syntax="proto3";
+  //
+  // message Request {
+  //   // The uri rule applies to any value, including the empty string.
+  //   string foo = 1 [
+  //     (buf.validate.field).string.uri = true
+  //   ];
+  //
+  //   // The uri rule only applies if the field is set, including if it's
+  //   // set to the empty string.
+  //   optional string bar = 2 [
+  //     (buf.validate.field).string.uri = true
+  //   ];
+  //
+  //   // The min_items rule always applies, even if the list is empty.
+  //   repeated string baz = 3 [
+  //     (buf.validate.field).repeated.min_items = 3
+  //   ];
+  //
+  //   // The custom CEL rule applies only if the field is set, including if
+  //   // it's the "zero" value of that message.
+  //   SomeMessage quux = 4 [
+  //     (buf.validate.field).cel = {/* ... */}
+  //   ];
+  // }
+  // ```
+  IGNORE_UNSPECIFIED = 0;
+
+  // Validation is skipped if the field is unpopulated. This rule is redundant
+  // if the field is already nullable. This value is equivalent behavior to the
+  // deprecated ignore_empty rule.
+  //
+  // ```proto
+  // syntax="proto3
+  //
+  // message Request {
+  //   // The uri rule applies only if the value is not the empty string.
+  //   string foo = 1 [
+  //     (buf.validate.field).string.uri = true,
+  //     (buf.validate.field).ignore = IGNORE_IF_UNPOPULATED
+  //   ];
+  //
+  //   // IGNORE_IF_UNPOPULATED is equivalent to IGNORE_UNSPECIFIED in this
+  //   // case: the uri rule only applies if the field is set, including if
+  //   // it's set to the empty string.
+  //   optional string bar = 2 [
+  //     (buf.validate.field).string.uri = true,
+  //     (buf.validate.field).ignore = IGNORE_IF_UNPOPULATED
+  //   ];
+  //
+  //   // The min_items rule only applies if the list has at least one item.
+  //   repeated string baz = 3 [
+  //     (buf.validate.field).repeated.min_items = 3,
+  //     (buf.validate.field).ignore = IGNORE_IF_UNPOPULATED
+  //   ];
+  //
+  //   // IGNORE_IF_UNPOPULATED is equivalent to IGNORE_UNSPECIFIED in this
+  //   // case: the custom CEL rule applies only if the field is set, including
+  //   // if it's the "zero" value of that message.
+  //   SomeMessage quux = 4 [
+  //     (buf.validate.field).cel = {/* ... */},
+  //     (buf.validate.field).ignore = IGNORE_IF_UNPOPULATED
+  //   ];
+  // }
+  // ```
+  IGNORE_IF_UNPOPULATED = 1;
+
+  // Validation is skipped if the field is unpopulated or if it is a nullable
+  // field populated with its default value. This is typically the zero or
+  // empty value, but proto2 scalars support custom defaults. For messages, the
+  // default is a non-null message with all its fields unpopulated.
+  //
+  // ```proto
+  // syntax="proto3
+  //
+  // message Request {
+  //   // IGNORE_IF_DEFAULT_VALUE is equivalent to IGNORE_IF_UNPOPULATED in
+  //   // this case; the uri rule applies only if the value is not the empty
+  //   // string.
+  //   string foo = 1 [
+  //     (buf.validate.field).string.uri = true,
+  //     (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE
+  //   ];
+  //
+  //   // The uri rule only applies if the field is set to a value other than
+  //   // the empty string.
+  //   optional string bar = 2 [
+  //     (buf.validate.field).string.uri = true,
+  //     (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE
+  //   ];
+  //
+  //   // IGNORE_IF_DEFAULT_VALUE is equivalent to IGNORE_IF_UNPOPULATED in
+  //   // this case; the min_items rule only applies if the list has at least
+  //   // one item.
+  //   repeated string baz = 3 [
+  //     (buf.validate.field).repeated.min_items = 3,
+  //     (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE
+  //   ];
+  //
+  //   // The custom CEL rule only applies if the field is set to a value other
+  //   // than an empty message (i.e., fields are unpopulated).
+  //   SomeMessage quux = 4 [
+  //     (buf.validate.field).cel = {/* ... */},
+  //     (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE
+  //   ];
+  // }
+  // ```
+  //
+  // This rule is affected by proto2 custom default values:
+  //
+  // ```proto
+  // syntax="proto2";
+  //
+  // message Request {
+  //   // The gt rule only applies if the field is set and it's value is not
+  //   the default (i.e., not -42). The rule even applies if the field is set
+  //   to zero since the default value differs.
+  //   optional int32 value = 1 [
+  //     default = -42,
+  //     (buf.validate.field).int32.gt = 0,
+  //     (buf.validate.field).ignore = IGNORE_IF_DEFAULT_VALUE
+  //   ];
+  // }
+  IGNORE_IF_DEFAULT_VALUE = 2;
+
+  // The validation rules of this field will be skipped and not evaluated. This
+  // is useful for situations that necessitate turning off the rules of a field
+  // containing a message that may not make sense in the current context, or to
+  // temporarily disable constraints during development.
+  //
+  // ```proto
+  // message MyMessage {
+  //   // The field's rules will always be ignored, including any validation's
+  //   // on value's fields.
+  //   MyOtherMessage value = 1 [
+  //     (buf.validate.field).ignore = IGNORE_ALWAYS];
+  // }
+  // ```
+  IGNORE_ALWAYS = 3;
+
+  // Deprecated: Use IGNORE_IF_UNPOPULATED instead. TODO: Remove this value pre-v1.
+  IGNORE_EMPTY = 1 [deprecated = true];
+  // Deprecated: Use IGNORE_IF_DEFAULT_VALUE. TODO: Remove this value pre-v1.
+  IGNORE_DEFAULT = 2 [deprecated = true];
+}
+
+// FloatRules describes the constraints applied to `float` values. These
+// rules may also be applied to the `google.protobuf.FloatValue` Well-Known-Type.
+message FloatRules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyFloat {
+  //   // value must equal 42.0
+  //   float value = 1 [(buf.validate.field).float.const = 42.0];
+  // }
+  // ```
+  optional float const = 1 [(predefined).cel = {
+    id: "float.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFloat {
+    //   // value must be less than 10.0
+    //   float value = 1 [(buf.validate.field).float.lt = 10.0];
+    // }
+    // ```
+    float lt = 2 [(predefined).cel = {
+      id: "float.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && (this.isNan() || this >= rules.lt)"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyFloat {
+    //   // value must be less than or equal to 10.0
+    //   float value = 1 [(buf.validate.field).float.lte = 10.0];
+    // }
+    // ```
+    float lte = 3 [(predefined).cel = {
+      id: "float.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && (this.isNan() || this > rules.lte)"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFloat {
+    //   // value must be greater than 5.0 [float.gt]
+    //   float value = 1 [(buf.validate.field).float.gt = 5.0];
+    //
+    //   // value must be greater than 5 and less than 10.0 [float.gt_lt]
+    //   float other_value = 2 [(buf.validate.field).float = { gt: 5.0, lt: 10.0 }];
+    //
+    //   // value must be greater than 10 or less than 5.0 [float.gt_lt_exclusive]
+    //   float another_value = 3 [(buf.validate.field).float = { gt: 10.0, lt: 5.0 }];
+    // }
+    // ```
+    float gt = 4 [
+      (predefined).cel = {
+        id: "float.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && (this.isNan() || this <= rules.gt)"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this.isNan() || this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (this.isNan() || (rules.lt <= this && this <= rules.gt))"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this.isNan() || this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (this.isNan() || (rules.lte < this && this <= rules.gt))"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFloat {
+    //   // value must be greater than or equal to 5.0 [float.gte]
+    //   float value = 1 [(buf.validate.field).float.gte = 5.0];
+    //
+    //   // value must be greater than or equal to 5.0 and less than 10.0 [float.gte_lt]
+    //   float other_value = 2 [(buf.validate.field).float = { gte: 5.0, lt: 10.0 }];
+    //
+    //   // value must be greater than or equal to 10.0 or less than 5.0 [float.gte_lt_exclusive]
+    //   float another_value = 3 [(buf.validate.field).float = { gte: 10.0, lt: 5.0 }];
+    // }
+    // ```
+    float gte = 5 [
+      (predefined).cel = {
+        id: "float.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && (this.isNan() || this < rules.gte)"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this.isNan() || this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (this.isNan() || (rules.lt <= this && this < rules.gte))"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this.isNan() || this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "float.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (this.isNan() || (rules.lte < this && this < rules.gte))"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message
+  // is generated.
+  //
+  // ```proto
+  // message MyFloat {
+  //   // value must be in list [1.0, 2.0, 3.0]
+  //   repeated float value = 1 (buf.validate.field).float = { in: [1.0, 2.0, 3.0] };
+  // }
+  // ```
+  repeated float in = 6 [(predefined).cel = {
+    id: "float.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyFloat {
+  //   // value must not be in list [1.0, 2.0, 3.0]
+  //   repeated float value = 1 (buf.validate.field).float = { not_in: [1.0, 2.0, 3.0] };
+  // }
+  // ```
+  repeated float not_in = 7 [(predefined).cel = {
+    id: "float.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `finite` requires the field value to be finite. If the field value is
+  // infinite or NaN, an error message is generated.
+  optional bool finite = 8 [(predefined).cel = {
+    id: "float.finite"
+    expression: "rules.finite ? (this.isNan() || this.isInf() ? 'value must be finite' : '') : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyFloat {
+  //   float value = 1 [
+  //     (buf.validate.field).float.example = 1.0,
+  //     (buf.validate.field).float.example = "Infinity"
+  //   ];
+  // }
+  // ```
+  repeated float example = 9 [(predefined).cel = {
+    id: "float.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// DoubleRules describes the constraints applied to `double` values. These
+// rules may also be applied to the `google.protobuf.DoubleValue` Well-Known-Type.
+message DoubleRules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyDouble {
+  //   // value must equal 42.0
+  //   double value = 1 [(buf.validate.field).double.const = 42.0];
+  // }
+  // ```
+  optional double const = 1 [(predefined).cel = {
+    id: "double.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyDouble {
+    //   // value must be less than 10.0
+    //   double value = 1 [(buf.validate.field).double.lt = 10.0];
+    // }
+    // ```
+    double lt = 2 [(predefined).cel = {
+      id: "double.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && (this.isNan() || this >= rules.lt)"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified value
+    // (field <= value). If the field value is greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyDouble {
+    //   // value must be less than or equal to 10.0
+    //   double value = 1 [(buf.validate.field).double.lte = 10.0];
+    // }
+    // ```
+    double lte = 3 [(predefined).cel = {
+      id: "double.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && (this.isNan() || this > rules.lte)"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or `lte`,
+    // the range is reversed, and the field value must be outside the specified
+    // range. If the field value doesn't meet the required conditions, an error
+    // message is generated.
+    //
+    // ```proto
+    // message MyDouble {
+    //   // value must be greater than 5.0 [double.gt]
+    //   double value = 1 [(buf.validate.field).double.gt = 5.0];
+    //
+    //   // value must be greater than 5 and less than 10.0 [double.gt_lt]
+    //   double other_value = 2 [(buf.validate.field).double = { gt: 5.0, lt: 10.0 }];
+    //
+    //   // value must be greater than 10 or less than 5.0 [double.gt_lt_exclusive]
+    //   double another_value = 3 [(buf.validate.field).double = { gt: 10.0, lt: 5.0 }];
+    // }
+    // ```
+    double gt = 4 [
+      (predefined).cel = {
+        id: "double.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && (this.isNan() || this <= rules.gt)"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this.isNan() || this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (this.isNan() || (rules.lt <= this && this <= rules.gt))"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this.isNan() || this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (this.isNan() || (rules.lte < this && this <= rules.gt))"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyDouble {
+    //   // value must be greater than or equal to 5.0 [double.gte]
+    //   double value = 1 [(buf.validate.field).double.gte = 5.0];
+    //
+    //   // value must be greater than or equal to 5.0 and less than 10.0 [double.gte_lt]
+    //   double other_value = 2 [(buf.validate.field).double = { gte: 5.0, lt: 10.0 }];
+    //
+    //   // value must be greater than or equal to 10.0 or less than 5.0 [double.gte_lt_exclusive]
+    //   double another_value = 3 [(buf.validate.field).double = { gte: 10.0, lt: 5.0 }];
+    // }
+    // ```
+    double gte = 5 [
+      (predefined).cel = {
+        id: "double.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && (this.isNan() || this < rules.gte)"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this.isNan() || this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (this.isNan() || (rules.lt <= this && this < rules.gte))"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this.isNan() || this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "double.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (this.isNan() || (rules.lte < this && this < rules.gte))"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyDouble {
+  //   // value must be in list [1.0, 2.0, 3.0]
+  //   repeated double value = 1 (buf.validate.field).double = { in: [1.0, 2.0, 3.0] };
+  // }
+  // ```
+  repeated double in = 6 [(predefined).cel = {
+    id: "double.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyDouble {
+  //   // value must not be in list [1.0, 2.0, 3.0]
+  //   repeated double value = 1 (buf.validate.field).double = { not_in: [1.0, 2.0, 3.0] };
+  // }
+  // ```
+  repeated double not_in = 7 [(predefined).cel = {
+    id: "double.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `finite` requires the field value to be finite. If the field value is
+  // infinite or NaN, an error message is generated.
+  optional bool finite = 8 [(predefined).cel = {
+    id: "double.finite"
+    expression: "rules.finite ? (this.isNan() || this.isInf() ? 'value must be finite' : '') : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyDouble {
+  //   double value = 1 [
+  //     (buf.validate.field).double.example = 1.0,
+  //     (buf.validate.field).double.example = "Infinity"
+  //   ];
+  // }
+  // ```
+  repeated double example = 9 [(predefined).cel = {
+    id: "double.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// Int32Rules describes the constraints applied to `int32` values. These
+// rules may also be applied to the `google.protobuf.Int32Value` Well-Known-Type.
+message Int32Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyInt32 {
+  //   // value must equal 42
+  //   int32 value = 1 [(buf.validate.field).int32.const = 42];
+  // }
+  // ```
+  optional int32 const = 1 [(predefined).cel = {
+    id: "int32.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field
+    // < value). If the field value is equal to or greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyInt32 {
+    //   // value must be less than 10
+    //   int32 value = 1 [(buf.validate.field).int32.lt = 10];
+    // }
+    // ```
+    int32 lt = 2 [(predefined).cel = {
+      id: "int32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyInt32 {
+    //   // value must be less than or equal to 10
+    //   int32 value = 1 [(buf.validate.field).int32.lte = 10];
+    // }
+    // ```
+    int32 lte = 3 [(predefined).cel = {
+      id: "int32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt32 {
+    //   // value must be greater than 5 [int32.gt]
+    //   int32 value = 1 [(buf.validate.field).int32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [int32.gt_lt]
+    //   int32 other_value = 2 [(buf.validate.field).int32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [int32.gt_lt_exclusive]
+    //   int32 another_value = 3 [(buf.validate.field).int32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    int32 gt = 4 [
+      (predefined).cel = {
+        id: "int32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified value
+    // (exclusive). If the value of `gte` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt32 {
+    //   // value must be greater than or equal to 5 [int32.gte]
+    //   int32 value = 1 [(buf.validate.field).int32.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [int32.gte_lt]
+    //   int32 other_value = 2 [(buf.validate.field).int32 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [int32.gte_lt_exclusive]
+    //   int32 another_value = 3 [(buf.validate.field).int32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    int32 gte = 5 [
+      (predefined).cel = {
+        id: "int32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyInt32 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated int32 value = 1 (buf.validate.field).int32 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated int32 in = 6 [(predefined).cel = {
+    id: "int32.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error message
+  // is generated.
+  //
+  // ```proto
+  // message MyInt32 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated int32 value = 1 (buf.validate.field).int32 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated int32 not_in = 7 [(predefined).cel = {
+    id: "int32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyInt32 {
+  //   int32 value = 1 [
+  //     (buf.validate.field).int32.example = 1,
+  //     (buf.validate.field).int32.example = -10
+  //   ];
+  // }
+  // ```
+  repeated int32 example = 8 [(predefined).cel = {
+    id: "int32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// Int64Rules describes the constraints applied to `int64` values. These
+// rules may also be applied to the `google.protobuf.Int64Value` Well-Known-Type.
+message Int64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyInt64 {
+  //   // value must equal 42
+  //   int64 value = 1 [(buf.validate.field).int64.const = 42];
+  // }
+  // ```
+  optional int64 const = 1 [(predefined).cel = {
+    id: "int64.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt64 {
+    //   // value must be less than 10
+    //   int64 value = 1 [(buf.validate.field).int64.lt = 10];
+    // }
+    // ```
+    int64 lt = 2 [(predefined).cel = {
+      id: "int64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyInt64 {
+    //   // value must be less than or equal to 10
+    //   int64 value = 1 [(buf.validate.field).int64.lte = 10];
+    // }
+    // ```
+    int64 lte = 3 [(predefined).cel = {
+      id: "int64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt64 {
+    //   // value must be greater than 5 [int64.gt]
+    //   int64 value = 1 [(buf.validate.field).int64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [int64.gt_lt]
+    //   int64 other_value = 2 [(buf.validate.field).int64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [int64.gt_lt_exclusive]
+    //   int64 another_value = 3 [(buf.validate.field).int64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    int64 gt = 4 [
+      (predefined).cel = {
+        id: "int64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyInt64 {
+    //   // value must be greater than or equal to 5 [int64.gte]
+    //   int64 value = 1 [(buf.validate.field).int64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [int64.gte_lt]
+    //   int64 other_value = 2 [(buf.validate.field).int64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [int64.gte_lt_exclusive]
+    //   int64 another_value = 3 [(buf.validate.field).int64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    int64 gte = 5 [
+      (predefined).cel = {
+        id: "int64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "int64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyInt64 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated int64 value = 1 (buf.validate.field).int64 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated int64 in = 6 [(predefined).cel = {
+    id: "int64.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyInt64 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated int64 value = 1 (buf.validate.field).int64 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated int64 not_in = 7 [(predefined).cel = {
+    id: "int64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyInt64 {
+  //   int64 value = 1 [
+  //     (buf.validate.field).int64.example = 1,
+  //     (buf.validate.field).int64.example = -10
+  //   ];
+  // }
+  // ```
+  repeated int64 example = 9 [(predefined).cel = {
+    id: "int64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// UInt32Rules describes the constraints applied to `uint32` values. These
+// rules may also be applied to the `google.protobuf.UInt32Value` Well-Known-Type.
+message UInt32Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyUInt32 {
+  //   // value must equal 42
+  //   uint32 value = 1 [(buf.validate.field).uint32.const = 42];
+  // }
+  // ```
+  optional uint32 const = 1 [(predefined).cel = {
+    id: "uint32.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt32 {
+    //   // value must be less than 10
+    //   uint32 value = 1 [(buf.validate.field).uint32.lt = 10];
+    // }
+    // ```
+    uint32 lt = 2 [(predefined).cel = {
+      id: "uint32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyUInt32 {
+    //   // value must be less than or equal to 10
+    //   uint32 value = 1 [(buf.validate.field).uint32.lte = 10];
+    // }
+    // ```
+    uint32 lte = 3 [(predefined).cel = {
+      id: "uint32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt32 {
+    //   // value must be greater than 5 [uint32.gt]
+    //   uint32 value = 1 [(buf.validate.field).uint32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [uint32.gt_lt]
+    //   uint32 other_value = 2 [(buf.validate.field).uint32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [uint32.gt_lt_exclusive]
+    //   uint32 another_value = 3 [(buf.validate.field).uint32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    uint32 gt = 4 [
+      (predefined).cel = {
+        id: "uint32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt32 {
+    //   // value must be greater than or equal to 5 [uint32.gte]
+    //   uint32 value = 1 [(buf.validate.field).uint32.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [uint32.gte_lt]
+    //   uint32 other_value = 2 [(buf.validate.field).uint32 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [uint32.gte_lt_exclusive]
+    //   uint32 another_value = 3 [(buf.validate.field).uint32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    uint32 gte = 5 [
+      (predefined).cel = {
+        id: "uint32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyUInt32 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated uint32 value = 1 (buf.validate.field).uint32 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated uint32 in = 6 [(predefined).cel = {
+    id: "uint32.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyUInt32 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated uint32 value = 1 (buf.validate.field).uint32 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated uint32 not_in = 7 [(predefined).cel = {
+    id: "uint32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyUInt32 {
+  //   uint32 value = 1 [
+  //     (buf.validate.field).uint32.example = 1,
+  //     (buf.validate.field).uint32.example = 10
+  //   ];
+  // }
+  // ```
+  repeated uint32 example = 8 [(predefined).cel = {
+    id: "uint32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// UInt64Rules describes the constraints applied to `uint64` values. These
+// rules may also be applied to the `google.protobuf.UInt64Value` Well-Known-Type.
+message UInt64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyUInt64 {
+  //   // value must equal 42
+  //   uint64 value = 1 [(buf.validate.field).uint64.const = 42];
+  // }
+  // ```
+  optional uint64 const = 1 [(predefined).cel = {
+    id: "uint64.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt64 {
+    //   // value must be less than 10
+    //   uint64 value = 1 [(buf.validate.field).uint64.lt = 10];
+    // }
+    // ```
+    uint64 lt = 2 [(predefined).cel = {
+      id: "uint64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyUInt64 {
+    //   // value must be less than or equal to 10
+    //   uint64 value = 1 [(buf.validate.field).uint64.lte = 10];
+    // }
+    // ```
+    uint64 lte = 3 [(predefined).cel = {
+      id: "uint64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt64 {
+    //   // value must be greater than 5 [uint64.gt]
+    //   uint64 value = 1 [(buf.validate.field).uint64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [uint64.gt_lt]
+    //   uint64 other_value = 2 [(buf.validate.field).uint64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [uint64.gt_lt_exclusive]
+    //   uint64 another_value = 3 [(buf.validate.field).uint64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    uint64 gt = 4 [
+      (predefined).cel = {
+        id: "uint64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyUInt64 {
+    //   // value must be greater than or equal to 5 [uint64.gte]
+    //   uint64 value = 1 [(buf.validate.field).uint64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [uint64.gte_lt]
+    //   uint64 other_value = 2 [(buf.validate.field).uint64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [uint64.gte_lt_exclusive]
+    //   uint64 another_value = 3 [(buf.validate.field).uint64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    uint64 gte = 5 [
+      (predefined).cel = {
+        id: "uint64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "uint64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyUInt64 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated uint64 value = 1 (buf.validate.field).uint64 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated uint64 in = 6 [(predefined).cel = {
+    id: "uint64.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyUInt64 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated uint64 value = 1 (buf.validate.field).uint64 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated uint64 not_in = 7 [(predefined).cel = {
+    id: "uint64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyUInt64 {
+  //   uint64 value = 1 [
+  //     (buf.validate.field).uint64.example = 1,
+  //     (buf.validate.field).uint64.example = -10
+  //   ];
+  // }
+  // ```
+  repeated uint64 example = 8 [(predefined).cel = {
+    id: "uint64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// SInt32Rules describes the constraints applied to `sint32` values.
+message SInt32Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MySInt32 {
+  //   // value must equal 42
+  //   sint32 value = 1 [(buf.validate.field).sint32.const = 42];
+  // }
+  // ```
+  optional sint32 const = 1 [(predefined).cel = {
+    id: "sint32.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field
+    // < value). If the field value is equal to or greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySInt32 {
+    //   // value must be less than 10
+    //   sint32 value = 1 [(buf.validate.field).sint32.lt = 10];
+    // }
+    // ```
+    sint32 lt = 2 [(predefined).cel = {
+      id: "sint32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySInt32 {
+    //   // value must be less than or equal to 10
+    //   sint32 value = 1 [(buf.validate.field).sint32.lte = 10];
+    // }
+    // ```
+    sint32 lte = 3 [(predefined).cel = {
+      id: "sint32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySInt32 {
+    //   // value must be greater than 5 [sint32.gt]
+    //   sint32 value = 1 [(buf.validate.field).sint32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [sint32.gt_lt]
+    //   sint32 other_value = 2 [(buf.validate.field).sint32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [sint32.gt_lt_exclusive]
+    //   sint32 another_value = 3 [(buf.validate.field).sint32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    sint32 gt = 4 [
+      (predefined).cel = {
+        id: "sint32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySInt32 {
+    //  // value must be greater than or equal to 5 [sint32.gte]
+    //  sint32 value = 1 [(buf.validate.field).sint32.gte = 5];
+    //
+    //  // value must be greater than or equal to 5 and less than 10 [sint32.gte_lt]
+    //  sint32 other_value = 2 [(buf.validate.field).sint32 = { gte: 5, lt: 10 }];
+    //
+    //  // value must be greater than or equal to 10 or less than 5 [sint32.gte_lt_exclusive]
+    //  sint32 another_value = 3 [(buf.validate.field).sint32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    sint32 gte = 5 [
+      (predefined).cel = {
+        id: "sint32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MySInt32 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated sint32 value = 1 (buf.validate.field).sint32 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated sint32 in = 6 [(predefined).cel = {
+    id: "sint32.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MySInt32 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated sint32 value = 1 (buf.validate.field).sint32 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated sint32 not_in = 7 [(predefined).cel = {
+    id: "sint32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MySInt32 {
+  //   sint32 value = 1 [
+  //     (buf.validate.field).sint32.example = 1,
+  //     (buf.validate.field).sint32.example = -10
+  //   ];
+  // }
+  // ```
+  repeated sint32 example = 8 [(predefined).cel = {
+    id: "sint32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// SInt64Rules describes the constraints applied to `sint64` values.
+message SInt64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MySInt64 {
+  //   // value must equal 42
+  //   sint64 value = 1 [(buf.validate.field).sint64.const = 42];
+  // }
+  // ```
+  optional sint64 const = 1 [(predefined).cel = {
+    id: "sint64.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field
+    // < value). If the field value is equal to or greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySInt64 {
+    //   // value must be less than 10
+    //   sint64 value = 1 [(buf.validate.field).sint64.lt = 10];
+    // }
+    // ```
+    sint64 lt = 2 [(predefined).cel = {
+      id: "sint64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySInt64 {
+    //   // value must be less than or equal to 10
+    //   sint64 value = 1 [(buf.validate.field).sint64.lte = 10];
+    // }
+    // ```
+    sint64 lte = 3 [(predefined).cel = {
+      id: "sint64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySInt64 {
+    //   // value must be greater than 5 [sint64.gt]
+    //   sint64 value = 1 [(buf.validate.field).sint64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [sint64.gt_lt]
+    //   sint64 other_value = 2 [(buf.validate.field).sint64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [sint64.gt_lt_exclusive]
+    //   sint64 another_value = 3 [(buf.validate.field).sint64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    sint64 gt = 4 [
+      (predefined).cel = {
+        id: "sint64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySInt64 {
+    //   // value must be greater than or equal to 5 [sint64.gte]
+    //   sint64 value = 1 [(buf.validate.field).sint64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [sint64.gte_lt]
+    //   sint64 other_value = 2 [(buf.validate.field).sint64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [sint64.gte_lt_exclusive]
+    //   sint64 another_value = 3 [(buf.validate.field).sint64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    sint64 gte = 5 [
+      (predefined).cel = {
+        id: "sint64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sint64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message
+  // is generated.
+  //
+  // ```proto
+  // message MySInt64 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated sint64 value = 1 (buf.validate.field).sint64 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated sint64 in = 6 [(predefined).cel = {
+    id: "sint64.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MySInt64 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated sint64 value = 1 (buf.validate.field).sint64 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated sint64 not_in = 7 [(predefined).cel = {
+    id: "sint64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MySInt64 {
+  //   sint64 value = 1 [
+  //     (buf.validate.field).sint64.example = 1,
+  //     (buf.validate.field).sint64.example = -10
+  //   ];
+  // }
+  // ```
+  repeated sint64 example = 8 [(predefined).cel = {
+    id: "sint64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// Fixed32Rules describes the constraints applied to `fixed32` values.
+message Fixed32Rules {
+  // `const` requires the field value to exactly match the specified value.
+  // If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyFixed32 {
+  //   // value must equal 42
+  //   fixed32 value = 1 [(buf.validate.field).fixed32.const = 42];
+  // }
+  // ```
+  optional fixed32 const = 1 [(predefined).cel = {
+    id: "fixed32.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed32 {
+    //   // value must be less than 10
+    //   fixed32 value = 1 [(buf.validate.field).fixed32.lt = 10];
+    // }
+    // ```
+    fixed32 lt = 2 [(predefined).cel = {
+      id: "fixed32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyFixed32 {
+    //   // value must be less than or equal to 10
+    //   fixed32 value = 1 [(buf.validate.field).fixed32.lte = 10];
+    // }
+    // ```
+    fixed32 lte = 3 [(predefined).cel = {
+      id: "fixed32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed32 {
+    //   // value must be greater than 5 [fixed32.gt]
+    //   fixed32 value = 1 [(buf.validate.field).fixed32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [fixed32.gt_lt]
+    //   fixed32 other_value = 2 [(buf.validate.field).fixed32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [fixed32.gt_lt_exclusive]
+    //   fixed32 another_value = 3 [(buf.validate.field).fixed32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    fixed32 gt = 4 [
+      (predefined).cel = {
+        id: "fixed32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed32 {
+    //   // value must be greater than or equal to 5 [fixed32.gte]
+    //   fixed32 value = 1 [(buf.validate.field).fixed32.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [fixed32.gte_lt]
+    //   fixed32 other_value = 2 [(buf.validate.field).fixed32 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [fixed32.gte_lt_exclusive]
+    //   fixed32 another_value = 3 [(buf.validate.field).fixed32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    fixed32 gte = 5 [
+      (predefined).cel = {
+        id: "fixed32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message
+  // is generated.
+  //
+  // ```proto
+  // message MyFixed32 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated fixed32 value = 1 (buf.validate.field).fixed32 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated fixed32 in = 6 [(predefined).cel = {
+    id: "fixed32.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyFixed32 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated fixed32 value = 1 (buf.validate.field).fixed32 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated fixed32 not_in = 7 [(predefined).cel = {
+    id: "fixed32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyFixed32 {
+  //   fixed32 value = 1 [
+  //     (buf.validate.field).fixed32.example = 1,
+  //     (buf.validate.field).fixed32.example = 2
+  //   ];
+  // }
+  // ```
+  repeated fixed32 example = 8 [(predefined).cel = {
+    id: "fixed32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// Fixed64Rules describes the constraints applied to `fixed64` values.
+message Fixed64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyFixed64 {
+  //   // value must equal 42
+  //   fixed64 value = 1 [(buf.validate.field).fixed64.const = 42];
+  // }
+  // ```
+  optional fixed64 const = 1 [(predefined).cel = {
+    id: "fixed64.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed64 {
+    //   // value must be less than 10
+    //   fixed64 value = 1 [(buf.validate.field).fixed64.lt = 10];
+    // }
+    // ```
+    fixed64 lt = 2 [(predefined).cel = {
+      id: "fixed64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MyFixed64 {
+    //   // value must be less than or equal to 10
+    //   fixed64 value = 1 [(buf.validate.field).fixed64.lte = 10];
+    // }
+    // ```
+    fixed64 lte = 3 [(predefined).cel = {
+      id: "fixed64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed64 {
+    //   // value must be greater than 5 [fixed64.gt]
+    //   fixed64 value = 1 [(buf.validate.field).fixed64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [fixed64.gt_lt]
+    //   fixed64 other_value = 2 [(buf.validate.field).fixed64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [fixed64.gt_lt_exclusive]
+    //   fixed64 another_value = 3 [(buf.validate.field).fixed64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    fixed64 gt = 4 [
+      (predefined).cel = {
+        id: "fixed64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyFixed64 {
+    //   // value must be greater than or equal to 5 [fixed64.gte]
+    //   fixed64 value = 1 [(buf.validate.field).fixed64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [fixed64.gte_lt]
+    //   fixed64 other_value = 2 [(buf.validate.field).fixed64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [fixed64.gte_lt_exclusive]
+    //   fixed64 another_value = 3 [(buf.validate.field).fixed64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    fixed64 gte = 5 [
+      (predefined).cel = {
+        id: "fixed64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "fixed64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyFixed64 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated fixed64 value = 1 (buf.validate.field).fixed64 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated fixed64 in = 6 [(predefined).cel = {
+    id: "fixed64.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyFixed64 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated fixed64 value = 1 (buf.validate.field).fixed64 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated fixed64 not_in = 7 [(predefined).cel = {
+    id: "fixed64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyFixed64 {
+  //   fixed64 value = 1 [
+  //     (buf.validate.field).fixed64.example = 1,
+  //     (buf.validate.field).fixed64.example = 2
+  //   ];
+  // }
+  // ```
+  repeated fixed64 example = 8 [(predefined).cel = {
+    id: "fixed64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// SFixed32Rules describes the constraints applied to `fixed32` values.
+message SFixed32Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MySFixed32 {
+  //   // value must equal 42
+  //   sfixed32 value = 1 [(buf.validate.field).sfixed32.const = 42];
+  // }
+  // ```
+  optional sfixed32 const = 1 [(predefined).cel = {
+    id: "sfixed32.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed32 {
+    //   // value must be less than 10
+    //   sfixed32 value = 1 [(buf.validate.field).sfixed32.lt = 10];
+    // }
+    // ```
+    sfixed32 lt = 2 [(predefined).cel = {
+      id: "sfixed32.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySFixed32 {
+    //   // value must be less than or equal to 10
+    //   sfixed32 value = 1 [(buf.validate.field).sfixed32.lte = 10];
+    // }
+    // ```
+    sfixed32 lte = 3 [(predefined).cel = {
+      id: "sfixed32.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed32 {
+    //   // value must be greater than 5 [sfixed32.gt]
+    //   sfixed32 value = 1 [(buf.validate.field).sfixed32.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [sfixed32.gt_lt]
+    //   sfixed32 other_value = 2 [(buf.validate.field).sfixed32 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [sfixed32.gt_lt_exclusive]
+    //   sfixed32 another_value = 3 [(buf.validate.field).sfixed32 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    sfixed32 gt = 4 [
+      (predefined).cel = {
+        id: "sfixed32.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed32 {
+    //   // value must be greater than or equal to 5 [sfixed32.gte]
+    //   sfixed32 value = 1 [(buf.validate.field).sfixed32.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [sfixed32.gte_lt]
+    //   sfixed32 other_value = 2 [(buf.validate.field).sfixed32 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [sfixed32.gte_lt_exclusive]
+    //   sfixed32 another_value = 3 [(buf.validate.field).sfixed32 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    sfixed32 gte = 5 [
+      (predefined).cel = {
+        id: "sfixed32.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed32.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MySFixed32 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated sfixed32 value = 1 (buf.validate.field).sfixed32 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated sfixed32 in = 6 [(predefined).cel = {
+    id: "sfixed32.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MySFixed32 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated sfixed32 value = 1 (buf.validate.field).sfixed32 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated sfixed32 not_in = 7 [(predefined).cel = {
+    id: "sfixed32.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MySFixed32 {
+  //   sfixed32 value = 1 [
+  //     (buf.validate.field).sfixed32.example = 1,
+  //     (buf.validate.field).sfixed32.example = 2
+  //   ];
+  // }
+  // ```
+  repeated sfixed32 example = 8 [(predefined).cel = {
+    id: "sfixed32.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// SFixed64Rules describes the constraints applied to `fixed64` values.
+message SFixed64Rules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MySFixed64 {
+  //   // value must equal 42
+  //   sfixed64 value = 1 [(buf.validate.field).sfixed64.const = 42];
+  // }
+  // ```
+  optional sfixed64 const = 1 [(predefined).cel = {
+    id: "sfixed64.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` requires the field value to be less than the specified value (field <
+    // value). If the field value is equal to or greater than the specified value,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed64 {
+    //   // value must be less than 10
+    //   sfixed64 value = 1 [(buf.validate.field).sfixed64.lt = 10];
+    // }
+    // ```
+    sfixed64 lt = 2 [(predefined).cel = {
+      id: "sfixed64.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` requires the field value to be less than or equal to the specified
+    // value (field <= value). If the field value is greater than the specified
+    // value, an error message is generated.
+    //
+    // ```proto
+    // message MySFixed64 {
+    //   // value must be less than or equal to 10
+    //   sfixed64 value = 1 [(buf.validate.field).sfixed64.lte = 10];
+    // }
+    // ```
+    sfixed64 lte = 3 [(predefined).cel = {
+      id: "sfixed64.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the field value to be greater than the specified value
+    // (exclusive). If the value of `gt` is larger than a specified `lt` or
+    // `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed64 {
+    //   // value must be greater than 5 [sfixed64.gt]
+    //   sfixed64 value = 1 [(buf.validate.field).sfixed64.gt = 5];
+    //
+    //   // value must be greater than 5 and less than 10 [sfixed64.gt_lt]
+    //   sfixed64 other_value = 2 [(buf.validate.field).sfixed64 = { gt: 5, lt: 10 }];
+    //
+    //   // value must be greater than 10 or less than 5 [sfixed64.gt_lt_exclusive]
+    //   sfixed64 another_value = 3 [(buf.validate.field).sfixed64 = { gt: 10, lt: 5 }];
+    // }
+    // ```
+    sfixed64 gt = 4 [
+      (predefined).cel = {
+        id: "sfixed64.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the field value to be greater than or equal to the specified
+    // value (exclusive). If the value of `gte` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MySFixed64 {
+    //   // value must be greater than or equal to 5 [sfixed64.gte]
+    //   sfixed64 value = 1 [(buf.validate.field).sfixed64.gte = 5];
+    //
+    //   // value must be greater than or equal to 5 and less than 10 [sfixed64.gte_lt]
+    //   sfixed64 other_value = 2 [(buf.validate.field).sfixed64 = { gte: 5, lt: 10 }];
+    //
+    //   // value must be greater than or equal to 10 or less than 5 [sfixed64.gte_lt_exclusive]
+    //   sfixed64 another_value = 3 [(buf.validate.field).sfixed64 = { gte: 10, lt: 5 }];
+    // }
+    // ```
+    sfixed64 gte = 5 [
+      (predefined).cel = {
+        id: "sfixed64.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "sfixed64.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` requires the field value to be equal to one of the specified values.
+  // If the field value isn't one of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MySFixed64 {
+  //   // value must be in list [1, 2, 3]
+  //   repeated sfixed64 value = 1 (buf.validate.field).sfixed64 = { in: [1, 2, 3] };
+  // }
+  // ```
+  repeated sfixed64 in = 6 [(predefined).cel = {
+    id: "sfixed64.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to not be equal to any of the specified
+  // values. If the field value is one of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MySFixed64 {
+  //   // value must not be in list [1, 2, 3]
+  //   repeated sfixed64 value = 1 (buf.validate.field).sfixed64 = { not_in: [1, 2, 3] };
+  // }
+  // ```
+  repeated sfixed64 not_in = 7 [(predefined).cel = {
+    id: "sfixed64.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MySFixed64 {
+  //   sfixed64 value = 1 [
+  //     (buf.validate.field).sfixed64.example = 1,
+  //     (buf.validate.field).sfixed64.example = 2
+  //   ];
+  // }
+  // ```
+  repeated sfixed64 example = 8 [(predefined).cel = {
+    id: "sfixed64.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// BoolRules describes the constraints applied to `bool` values. These rules
+// may also be applied to the `google.protobuf.BoolValue` Well-Known-Type.
+message BoolRules {
+  // `const` requires the field value to exactly match the specified boolean value.
+  // If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyBool {
+  //   // value must equal true
+  //   bool value = 1 [(buf.validate.field).bool.const = true];
+  // }
+  // ```
+  optional bool const = 1 [(predefined).cel = {
+    id: "bool.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyBool {
+  //   bool value = 1 [
+  //     (buf.validate.field).bool.example = 1,
+  //     (buf.validate.field).bool.example = 2
+  //   ];
+  // }
+  // ```
+  repeated bool example = 2 [(predefined).cel = {
+    id: "bool.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// StringRules describes the constraints applied to `string` values These
+// rules may also be applied to the `google.protobuf.StringValue` Well-Known-Type.
+message StringRules {
+  // `const` requires the field value to exactly match the specified value. If
+  // the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value must equal `hello`
+  //   string value = 1 [(buf.validate.field).string.const = "hello"];
+  // }
+  // ```
+  optional string const = 1 [(predefined).cel = {
+    id: "string.const"
+    expression: "this != rules.const ? 'value must equal `%s`'.format([rules.const]) : ''"
+  }];
+
+  // `len` dictates that the field value must have the specified
+  // number of characters (Unicode code points), which may differ from the number
+  // of bytes in the string. If the field value does not meet the specified
+  // length, an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be 5 characters
+  //   string value = 1 [(buf.validate.field).string.len = 5];
+  // }
+  // ```
+  optional uint64 len = 19 [(predefined).cel = {
+    id: "string.len"
+    expression: "uint(this.size()) != rules.len ? 'value length must be %s characters'.format([rules.len]) : ''"
+  }];
+
+  // `min_len` specifies that the field value must have at least the specified
+  // number of characters (Unicode code points), which may differ from the number
+  // of bytes in the string. If the field value contains fewer characters, an error
+  // message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be at least 3 characters
+  //   string value = 1 [(buf.validate.field).string.min_len = 3];
+  // }
+  // ```
+  optional uint64 min_len = 2 [(predefined).cel = {
+    id: "string.min_len"
+    expression: "uint(this.size()) < rules.min_len ? 'value length must be at least %s characters'.format([rules.min_len]) : ''"
+  }];
+
+  // `max_len` specifies that the field value must have no more than the specified
+  // number of characters (Unicode code points), which may differ from the
+  // number of bytes in the string. If the field value contains more characters,
+  // an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be at most 10 characters
+  //   string value = 1 [(buf.validate.field).string.max_len = 10];
+  // }
+  // ```
+  optional uint64 max_len = 3 [(predefined).cel = {
+    id: "string.max_len"
+    expression: "uint(this.size()) > rules.max_len ? 'value length must be at most %s characters'.format([rules.max_len]) : ''"
+  }];
+
+  // `len_bytes` dictates that the field value must have the specified number of
+  // bytes. If the field value does not match the specified length in bytes,
+  // an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be 6 bytes
+  //   string value = 1 [(buf.validate.field).string.len_bytes = 6];
+  // }
+  // ```
+  optional uint64 len_bytes = 20 [(predefined).cel = {
+    id: "string.len_bytes"
+    expression: "uint(bytes(this).size()) != rules.len_bytes ? 'value length must be %s bytes'.format([rules.len_bytes]) : ''"
+  }];
+
+  // `min_bytes` specifies that the field value must have at least the specified
+  // number of bytes. If the field value contains fewer bytes, an error message
+  // will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be at least 4 bytes
+  //   string value = 1 [(buf.validate.field).string.min_bytes = 4];
+  // }
+  //
+  // ```
+  optional uint64 min_bytes = 4 [(predefined).cel = {
+    id: "string.min_bytes"
+    expression: "uint(bytes(this).size()) < rules.min_bytes ? 'value length must be at least %s bytes'.format([rules.min_bytes]) : ''"
+  }];
+
+  // `max_bytes` specifies that the field value must have no more than the
+  //specified number of bytes. If the field value contains more bytes, an
+  // error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value length must be at most 8 bytes
+  //   string value = 1 [(buf.validate.field).string.max_bytes = 8];
+  // }
+  // ```
+  optional uint64 max_bytes = 5 [(predefined).cel = {
+    id: "string.max_bytes"
+    expression: "uint(bytes(this).size()) > rules.max_bytes ? 'value length must be at most %s bytes'.format([rules.max_bytes]) : ''"
+  }];
+
+  // `pattern` specifies that the field value must match the specified
+  // regular expression (RE2 syntax), with the expression provided without any
+  // delimiters. If the field value doesn't match the regular expression, an
+  // error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value does not match regex pattern `^[a-zA-Z]//$`
+  //   string value = 1 [(buf.validate.field).string.pattern = "^[a-zA-Z]//$"];
+  // }
+  // ```
+  optional string pattern = 6 [(predefined).cel = {
+    id: "string.pattern"
+    expression: "!this.matches(rules.pattern) ? 'value does not match regex pattern `%s`'.format([rules.pattern]) : ''"
+  }];
+
+  // `prefix` specifies that the field value must have the
+  //specified substring at the beginning of the string. If the field value
+  // doesn't start with the specified prefix, an error message will be
+  // generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value does not have prefix `pre`
+  //   string value = 1 [(buf.validate.field).string.prefix = "pre"];
+  // }
+  // ```
+  optional string prefix = 7 [(predefined).cel = {
+    id: "string.prefix"
+    expression: "!this.startsWith(rules.prefix) ? 'value does not have prefix `%s`'.format([rules.prefix]) : ''"
+  }];
+
+  // `suffix` specifies that the field value must have the
+  //specified substring at the end of the string. If the field value doesn't
+  // end with the specified suffix, an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value does not have suffix `post`
+  //   string value = 1 [(buf.validate.field).string.suffix = "post"];
+  // }
+  // ```
+  optional string suffix = 8 [(predefined).cel = {
+    id: "string.suffix"
+    expression: "!this.endsWith(rules.suffix) ? 'value does not have suffix `%s`'.format([rules.suffix]) : ''"
+  }];
+
+  // `contains` specifies that the field value must have the
+  //specified substring anywhere in the string. If the field value doesn't
+  // contain the specified substring, an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value does not contain substring `inside`.
+  //   string value = 1 [(buf.validate.field).string.contains = "inside"];
+  // }
+  // ```
+  optional string contains = 9 [(predefined).cel = {
+    id: "string.contains"
+    expression: "!this.contains(rules.contains) ? 'value does not contain substring `%s`'.format([rules.contains]) : ''"
+  }];
+
+  // `not_contains` specifies that the field value must not have the
+  //specified substring anywhere in the string. If the field value contains
+  // the specified substring, an error message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value contains substring `inside`.
+  //   string value = 1 [(buf.validate.field).string.not_contains = "inside"];
+  // }
+  // ```
+  optional string not_contains = 23 [(predefined).cel = {
+    id: "string.not_contains"
+    expression: "this.contains(rules.not_contains) ? 'value contains substring `%s`'.format([rules.not_contains]) : ''"
+  }];
+
+  // `in` specifies that the field value must be equal to one of the specified
+  // values. If the field value isn't one of the specified values, an error
+  // message will be generated.
+  //
+  // ```proto
+  // message MyString {
+  //   // value must be in list ["apple", "banana"]
+  //   repeated string value = 1 [(buf.validate.field).string.in = "apple", (buf.validate.field).string.in = "banana"];
+  // }
+  // ```
+  repeated string in = 10 [(predefined).cel = {
+    id: "string.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` specifies that the field value cannot be equal to any
+  // of the specified values. If the field value is one of the specified values,
+  // an error message will be generated.
+  // ```proto
+  // message MyString {
+  //   // value must not be in list ["orange", "grape"]
+  //   repeated string value = 1 [(buf.validate.field).string.not_in = "orange", (buf.validate.field).string.not_in = "grape"];
+  // }
+  // ```
+  repeated string not_in = 11 [(predefined).cel = {
+    id: "string.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `WellKnown` rules provide advanced constraints against common string
+  // patterns
+  oneof well_known {
+    // `email` specifies that the field value must be a valid email address
+    // (addr-spec only) as defined by [RFC 5322](https://tools.ietf.org/html/rfc5322#section-3.4.1).
+    // If the field value isn't a valid email address, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid email address
+    //   string value = 1 [(buf.validate.field).string.email = true];
+    // }
+    // ```
+    bool email = 12 [
+      (predefined).cel = {
+        id: "string.email"
+        message: "value must be a valid email address"
+        expression: "!rules.email || this == '' || this.isEmail()"
+      },
+      (predefined).cel = {
+        id: "string.email_empty"
+        message: "value is empty, which is not a valid email address"
+        expression: "!rules.email || this != ''"
+      }
+    ];
+
+    // `hostname` specifies that the field value must be a valid
+    // hostname as defined by [RFC 1034](https://tools.ietf.org/html/rfc1034#section-3.5). This constraint doesn't support
+    // internationalized domain names (IDNs). If the field value isn't a
+    // valid hostname, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid hostname
+    //   string value = 1 [(buf.validate.field).string.hostname = true];
+    // }
+    // ```
+    bool hostname = 13 [
+      (predefined).cel = {
+        id: "string.hostname"
+        message: "value must be a valid hostname"
+        expression: "!rules.hostname || this == '' || this.isHostname()"
+      },
+      (predefined).cel = {
+        id: "string.hostname_empty"
+        message: "value is empty, which is not a valid hostname"
+        expression: "!rules.hostname || this != ''"
+      }
+    ];
+
+    // `ip` specifies that the field value must be a valid IP
+    // (v4 or v6) address, without surrounding square brackets for IPv6 addresses.
+    // If the field value isn't a valid IP address, an error message will be
+    // generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IP address
+    //   string value = 1 [(buf.validate.field).string.ip = true];
+    // }
+    // ```
+    bool ip = 14 [
+      (predefined).cel = {
+        id: "string.ip"
+        message: "value must be a valid IP address"
+        expression: "!rules.ip || this == '' || this.isIp()"
+      },
+      (predefined).cel = {
+        id: "string.ip_empty"
+        message: "value is empty, which is not a valid IP address"
+        expression: "!rules.ip || this != ''"
+      }
+    ];
+
+    // `ipv4` specifies that the field value must be a valid IPv4
+    // address. If the field value isn't a valid IPv4 address, an error message
+    // will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv4 address
+    //   string value = 1 [(buf.validate.field).string.ipv4 = true];
+    // }
+    // ```
+    bool ipv4 = 15 [
+      (predefined).cel = {
+        id: "string.ipv4"
+        message: "value must be a valid IPv4 address"
+        expression: "!rules.ipv4 || this == '' || this.isIp(4)"
+      },
+      (predefined).cel = {
+        id: "string.ipv4_empty"
+        message: "value is empty, which is not a valid IPv4 address"
+        expression: "!rules.ipv4 || this != ''"
+      }
+    ];
+
+    // `ipv6` specifies that the field value must be a valid
+    // IPv6 address, without surrounding square brackets. If the field value is
+    // not a valid IPv6 address, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv6 address
+    //   string value = 1 [(buf.validate.field).string.ipv6 = true];
+    // }
+    // ```
+    bool ipv6 = 16 [
+      (predefined).cel = {
+        id: "string.ipv6"
+        message: "value must be a valid IPv6 address"
+        expression: "!rules.ipv6 || this == '' || this.isIp(6)"
+      },
+      (predefined).cel = {
+        id: "string.ipv6_empty"
+        message: "value is empty, which is not a valid IPv6 address"
+        expression: "!rules.ipv6 || this != ''"
+      }
+    ];
+
+    // `uri` specifies that the field value must be a valid,
+    // absolute URI as defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3). If the field value isn't a valid,
+    // absolute URI, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid URI
+    //   string value = 1 [(buf.validate.field).string.uri = true];
+    // }
+    // ```
+    bool uri = 17 [
+      (predefined).cel = {
+        id: "string.uri"
+        message: "value must be a valid URI"
+        expression: "!rules.uri || this == '' || this.isUri()"
+      },
+      (predefined).cel = {
+        id: "string.uri_empty"
+        message: "value is empty, which is not a valid URI"
+        expression: "!rules.uri || this != ''"
+      }
+    ];
+
+    // `uri_ref` specifies that the field value must be a valid URI
+    // as defined by [RFC 3986](https://tools.ietf.org/html/rfc3986#section-3) and may be either relative or absolute. If the
+    // field value isn't a valid URI, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid URI
+    //   string value = 1 [(buf.validate.field).string.uri_ref = true];
+    // }
+    // ```
+    bool uri_ref = 18 [(predefined).cel = {
+      id: "string.uri_ref"
+      message: "value must be a valid URI"
+      expression: "!rules.uri_ref || this.isUriRef()"
+    }];
+
+    // `address` specifies that the field value must be either a valid hostname
+    // as defined by [RFC 1034](https://tools.ietf.org/html/rfc1034#section-3.5)
+    // (which doesn't support internationalized domain names or IDNs) or a valid
+    // IP (v4 or v6). If the field value isn't a valid hostname or IP, an error
+    // message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid hostname, or ip address
+    //   string value = 1 [(buf.validate.field).string.address = true];
+    // }
+    // ```
+    bool address = 21 [
+      (predefined).cel = {
+        id: "string.address"
+        message: "value must be a valid hostname, or ip address"
+        expression: "!rules.address || this == '' || this.isHostname() || this.isIp()"
+      },
+      (predefined).cel = {
+        id: "string.address_empty"
+        message: "value is empty, which is not a valid hostname, or ip address"
+        expression: "!rules.address || this != ''"
+      }
+    ];
+
+    // `uuid` specifies that the field value must be a valid UUID as defined by
+    // [RFC 4122](https://tools.ietf.org/html/rfc4122#section-4.1.2). If the
+    // field value isn't a valid UUID, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid UUID
+    //   string value = 1 [(buf.validate.field).string.uuid = true];
+    // }
+    // ```
+    bool uuid = 22 [
+      (predefined).cel = {
+        id: "string.uuid"
+        message: "value must be a valid UUID"
+        expression: "!rules.uuid || this == '' || this.matches('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')"
+      },
+      (predefined).cel = {
+        id: "string.uuid_empty"
+        message: "value is empty, which is not a valid UUID"
+        expression: "!rules.uuid || this != ''"
+      }
+    ];
+
+    // `tuuid` (trimmed UUID) specifies that the field value must be a valid UUID as
+    // defined by [RFC 4122](https://tools.ietf.org/html/rfc4122#section-4.1.2) with all dashes
+    // omitted. If the field value isn't a valid UUID without dashes, an error message
+    // will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid trimmed UUID
+    //   string value = 1 [(buf.validate.field).string.tuuid = true];
+    // }
+    // ```
+    bool tuuid = 33 [
+      (predefined).cel = {
+        id: "string.tuuid"
+        message: "value must be a valid trimmed UUID"
+        expression: "!rules.tuuid || this == '' || this.matches('^[0-9a-fA-F]{32}$')"
+      },
+      (predefined).cel = {
+        id: "string.tuuid_empty"
+        message: "value is empty, which is not a valid trimmed UUID"
+        expression: "!rules.tuuid || this != ''"
+      }
+    ];
+
+    // `ip_with_prefixlen` specifies that the field value must be a valid IP (v4 or v6)
+    // address with prefix length. If the field value isn't a valid IP with prefix
+    // length, an error message will be generated.
+    //
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IP with prefix length
+    //    string value = 1 [(buf.validate.field).string.ip_with_prefixlen = true];
+    // }
+    // ```
+    bool ip_with_prefixlen = 26 [
+      (predefined).cel = {
+        id: "string.ip_with_prefixlen"
+        message: "value must be a valid IP prefix"
+        expression: "!rules.ip_with_prefixlen || this == '' || this.isIpPrefix()"
+      },
+      (predefined).cel = {
+        id: "string.ip_with_prefixlen_empty"
+        message: "value is empty, which is not a valid IP prefix"
+        expression: "!rules.ip_with_prefixlen || this != ''"
+      }
+    ];
+
+    // `ipv4_with_prefixlen` specifies that the field value must be a valid
+    // IPv4 address with prefix.
+    // If the field value isn't a valid IPv4 address with prefix length,
+    // an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv4 address with prefix length
+    //    string value = 1 [(buf.validate.field).string.ipv4_with_prefixlen = true];
+    // }
+    // ```
+    bool ipv4_with_prefixlen = 27 [
+      (predefined).cel = {
+        id: "string.ipv4_with_prefixlen"
+        message: "value must be a valid IPv4 address with prefix length"
+        expression: "!rules.ipv4_with_prefixlen || this == '' || this.isIpPrefix(4)"
+      },
+      (predefined).cel = {
+        id: "string.ipv4_with_prefixlen_empty"
+        message: "value is empty, which is not a valid IPv4 address with prefix length"
+        expression: "!rules.ipv4_with_prefixlen || this != ''"
+      }
+    ];
+
+    // `ipv6_with_prefixlen` specifies that the field value must be a valid
+    // IPv6 address with prefix length.
+    // If the field value is not a valid IPv6 address with prefix length,
+    // an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv6 address prefix length
+    //    string value = 1 [(buf.validate.field).string.ipv6_with_prefixlen = true];
+    // }
+    // ```
+    bool ipv6_with_prefixlen = 28 [
+      (predefined).cel = {
+        id: "string.ipv6_with_prefixlen"
+        message: "value must be a valid IPv6 address with prefix length"
+        expression: "!rules.ipv6_with_prefixlen || this == '' || this.isIpPrefix(6)"
+      },
+      (predefined).cel = {
+        id: "string.ipv6_with_prefixlen_empty"
+        message: "value is empty, which is not a valid IPv6 address with prefix length"
+        expression: "!rules.ipv6_with_prefixlen || this != ''"
+      }
+    ];
+
+    // `ip_prefix` specifies that the field value must be a valid IP (v4 or v6) prefix.
+    // If the field value isn't a valid IP prefix, an error message will be
+    // generated. The prefix must have all zeros for the masked bits of the prefix (e.g.,
+    // `127.0.0.0/16`, not `127.0.0.1/16`).
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IP prefix
+    //    string value = 1 [(buf.validate.field).string.ip_prefix = true];
+    // }
+    // ```
+    bool ip_prefix = 29 [
+      (predefined).cel = {
+        id: "string.ip_prefix"
+        message: "value must be a valid IP prefix"
+        expression: "!rules.ip_prefix || this == '' || this.isIpPrefix(true)"
+      },
+      (predefined).cel = {
+        id: "string.ip_prefix_empty"
+        message: "value is empty, which is not a valid IP prefix"
+        expression: "!rules.ip_prefix || this != ''"
+      }
+    ];
+
+    // `ipv4_prefix` specifies that the field value must be a valid IPv4
+    // prefix. If the field value isn't a valid IPv4 prefix, an error message
+    // will be generated. The prefix must have all zeros for the masked bits of
+    // the prefix (e.g., `127.0.0.0/16`, not `127.0.0.1/16`).
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv4 prefix
+    //    string value = 1 [(buf.validate.field).string.ipv4_prefix = true];
+    // }
+    // ```
+    bool ipv4_prefix = 30 [
+      (predefined).cel = {
+        id: "string.ipv4_prefix"
+        message: "value must be a valid IPv4 prefix"
+        expression: "!rules.ipv4_prefix || this == '' || this.isIpPrefix(4, true)"
+      },
+      (predefined).cel = {
+        id: "string.ipv4_prefix_empty"
+        message: "value is empty, which is not a valid IPv4 prefix"
+        expression: "!rules.ipv4_prefix || this != ''"
+      }
+    ];
+
+    // `ipv6_prefix` specifies that the field value must be a valid IPv6 prefix.
+    // If the field value is not a valid IPv6 prefix, an error message will be
+    // generated. The prefix must have all zeros for the masked bits of the prefix
+    // (e.g., `2001:db8::/48`, not `2001:db8::1/48`).
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid IPv6 prefix
+    //    string value = 1 [(buf.validate.field).string.ipv6_prefix = true];
+    // }
+    // ```
+    bool ipv6_prefix = 31 [
+      (predefined).cel = {
+        id: "string.ipv6_prefix"
+        message: "value must be a valid IPv6 prefix"
+        expression: "!rules.ipv6_prefix || this == '' || this.isIpPrefix(6, true)"
+      },
+      (predefined).cel = {
+        id: "string.ipv6_prefix_empty"
+        message: "value is empty, which is not a valid IPv6 prefix"
+        expression: "!rules.ipv6_prefix || this != ''"
+      }
+    ];
+
+    // `host_and_port` specifies the field value must be a valid host and port
+    // pair. The host must be a valid hostname or IP address while the port
+    // must be in the range of 0-65535, inclusive. IPv6 addresses must be delimited
+    // with square brackets (e.g., `[::1]:1234`).
+    bool host_and_port = 32 [
+      (predefined).cel = {
+        id: "string.host_and_port"
+        message: "value must be a valid host (hostname or IP address) and port pair"
+        expression: "!rules.host_and_port || this == '' || this.isHostAndPort(true)"
+      },
+      (predefined).cel = {
+        id: "string.host_and_port_empty"
+        message: "value is empty, which is not a valid host and port pair"
+        expression: "!rules.host_and_port || this != ''"
+      }
+    ];
+
+    // `well_known_regex` specifies a common well-known pattern
+    // defined as a regex. If the field value doesn't match the well-known
+    // regex, an error message will be generated.
+    //
+    // ```proto
+    // message MyString {
+    //   // value must be a valid HTTP header value
+    //   string value = 1 [(buf.validate.field).string.well_known_regex = KNOWN_REGEX_HTTP_HEADER_VALUE];
+    // }
+    // ```
+    //
+    // #### KnownRegex
+    //
+    // `well_known_regex` contains some well-known patterns.
+    //
+    // | Name                          | Number | Description                               |
+    // |-------------------------------|--------|-------------------------------------------|
+    // | KNOWN_REGEX_UNSPECIFIED       | 0      |                                           |
+    // | KNOWN_REGEX_HTTP_HEADER_NAME  | 1      | HTTP header name as defined by [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2)  |
+    // | KNOWN_REGEX_HTTP_HEADER_VALUE | 2      | HTTP header value as defined by [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2.4) |
+    KnownRegex well_known_regex = 24 [
+      (predefined).cel = {
+        id: "string.well_known_regex.header_name"
+        message: "value must be a valid HTTP header name"
+        expression:
+            "rules.well_known_regex != 1 || this == '' || this.matches(!has(rules.strict) || rules.strict ?"
+                "'^:?[0-9a-zA-Z!#$%&\\'*+-.^_|~\\x60]+$' :"
+                "'^[^\\u0000\\u000A\\u000D]+$')"
+      },
+      (predefined).cel = {
+        id: "string.well_known_regex.header_name_empty"
+        message: "value is empty, which is not a valid HTTP header name"
+        expression: "rules.well_known_regex != 1 || this != ''"
+      },
+      (predefined).cel = {
+        id: "string.well_known_regex.header_value"
+        message: "value must be a valid HTTP header value"
+        expression:
+            "rules.well_known_regex != 2 || this.matches(!has(rules.strict) || rules.strict ?"
+                "'^[^\\u0000-\\u0008\\u000A-\\u001F\\u007F]*$' :"
+                "'^[^\\u0000\\u000A\\u000D]*$')"
+      }
+    ];
+  }
+
+  // This applies to regexes `HTTP_HEADER_NAME` and `HTTP_HEADER_VALUE` to
+  // enable strict header validation. By default, this is true, and HTTP header
+  // validations are [RFC-compliant](https://tools.ietf.org/html/rfc7230#section-3). Setting to false will enable looser
+  // validations that only disallow `\r\n\0` characters, which can be used to
+  // bypass header matching rules.
+  //
+  // ```proto
+  // message MyString {
+  //   // The field `value` must have be a valid HTTP headers, but not enforced with strict rules.
+  //   string value = 1 [(buf.validate.field).string.strict = false];
+  // }
+  // ```
+  optional bool strict = 25;
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyString {
+  //   string value = 1 [
+  //     (buf.validate.field).string.example = "hello",
+  //     (buf.validate.field).string.example = "world"
+  //   ];
+  // }
+  // ```
+  repeated string example = 34 [(predefined).cel = {
+    id: "string.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// WellKnownRegex contain some well-known patterns.
+enum KnownRegex {
+  KNOWN_REGEX_UNSPECIFIED = 0;
+
+  // HTTP header name as defined by [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2).
+  KNOWN_REGEX_HTTP_HEADER_NAME = 1;
+
+  // HTTP header value as defined by [RFC 7230](https://tools.ietf.org/html/rfc7230#section-3.2.4).
+  KNOWN_REGEX_HTTP_HEADER_VALUE = 2;
+}
+
+// BytesRules describe the constraints applied to `bytes` values. These rules
+// may also be applied to the `google.protobuf.BytesValue` Well-Known-Type.
+message BytesRules {
+  // `const` requires the field value to exactly match the specified bytes
+  // value. If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value must be "\x01\x02\x03\x04"
+  //   bytes value = 1 [(buf.validate.field).bytes.const = "\x01\x02\x03\x04"];
+  // }
+  // ```
+  optional bytes const = 1 [(predefined).cel = {
+    id: "bytes.const"
+    expression: "this != rules.const ? 'value must be %x'.format([rules.const]) : ''"
+  }];
+
+  // `len` requires the field value to have the specified length in bytes.
+  // If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value length must be 4 bytes.
+  //   optional bytes value = 1 [(buf.validate.field).bytes.len = 4];
+  // }
+  // ```
+  optional uint64 len = 13 [(predefined).cel = {
+    id: "bytes.len"
+    expression: "uint(this.size()) != rules.len ? 'value length must be %s bytes'.format([rules.len]) : ''"
+  }];
+
+  // `min_len` requires the field value to have at least the specified minimum
+  // length in bytes.
+  // If the field value doesn't meet the requirement, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value length must be at least 2 bytes.
+  //   optional bytes value = 1 [(buf.validate.field).bytes.min_len = 2];
+  // }
+  // ```
+  optional uint64 min_len = 2 [(predefined).cel = {
+    id: "bytes.min_len"
+    expression: "uint(this.size()) < rules.min_len ? 'value length must be at least %s bytes'.format([rules.min_len]) : ''"
+  }];
+
+  // `max_len` requires the field value to have at most the specified maximum
+  // length in bytes.
+  // If the field value exceeds the requirement, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value must be at most 6 bytes.
+  //   optional bytes value = 1 [(buf.validate.field).bytes.max_len = 6];
+  // }
+  // ```
+  optional uint64 max_len = 3 [(predefined).cel = {
+    id: "bytes.max_len"
+    expression: "uint(this.size()) > rules.max_len ? 'value must be at most %s bytes'.format([rules.max_len]) : ''"
+  }];
+
+  // `pattern` requires the field value to match the specified regular
+  // expression ([RE2 syntax](https://github.com/google/re2/wiki/Syntax)).
+  // The value of the field must be valid UTF-8 or validation will fail with a
+  // runtime error.
+  // If the field value doesn't match the pattern, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value must match regex pattern "^[a-zA-Z0-9]+$".
+  //   optional bytes value = 1 [(buf.validate.field).bytes.pattern = "^[a-zA-Z0-9]+$"];
+  // }
+  // ```
+  optional string pattern = 4 [(predefined).cel = {
+    id: "bytes.pattern"
+    expression: "!string(this).matches(rules.pattern) ? 'value must match regex pattern `%s`'.format([rules.pattern]) : ''"
+  }];
+
+  // `prefix` requires the field value to have the specified bytes at the
+  // beginning of the string.
+  // If the field value doesn't meet the requirement, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value does not have prefix \x01\x02
+  //   optional bytes value = 1 [(buf.validate.field).bytes.prefix = "\x01\x02"];
+  // }
+  // ```
+  optional bytes prefix = 5 [(predefined).cel = {
+    id: "bytes.prefix"
+    expression: "!this.startsWith(rules.prefix) ? 'value does not have prefix %x'.format([rules.prefix]) : ''"
+  }];
+
+  // `suffix` requires the field value to have the specified bytes at the end
+  // of the string.
+  // If the field value doesn't meet the requirement, an error message is generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value does not have suffix \x03\x04
+  //   optional bytes value = 1 [(buf.validate.field).bytes.suffix = "\x03\x04"];
+  // }
+  // ```
+  optional bytes suffix = 6 [(predefined).cel = {
+    id: "bytes.suffix"
+    expression: "!this.endsWith(rules.suffix) ? 'value does not have suffix %x'.format([rules.suffix]) : ''"
+  }];
+
+  // `contains` requires the field value to have the specified bytes anywhere in
+  // the string.
+  // If the field value doesn't meet the requirement, an error message is generated.
+  //
+  // ```protobuf
+  // message MyBytes {
+  //   // value does not contain \x02\x03
+  //   optional bytes value = 1 [(buf.validate.field).bytes.contains = "\x02\x03"];
+  // }
+  // ```
+  optional bytes contains = 7 [(predefined).cel = {
+    id: "bytes.contains"
+    expression: "!this.contains(rules.contains) ? 'value does not contain %x'.format([rules.contains]) : ''"
+  }];
+
+  // `in` requires the field value to be equal to one of the specified
+  // values. If the field value doesn't match any of the specified values, an
+  // error message is generated.
+  //
+  // ```protobuf
+  // message MyBytes {
+  //   // value must in ["\x01\x02", "\x02\x03", "\x03\x04"]
+  //   optional bytes value = 1 [(buf.validate.field).bytes.in = {"\x01\x02", "\x02\x03", "\x03\x04"}];
+  // }
+  // ```
+  repeated bytes in = 8 [(predefined).cel = {
+    id: "bytes.in"
+    expression: "dyn(rules)['in'].size() > 0 && !(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to be not equal to any of the specified
+  // values.
+  // If the field value matches any of the specified values, an error message is
+  // generated.
+  //
+  // ```proto
+  // message MyBytes {
+  //   // value must not in ["\x01\x02", "\x02\x03", "\x03\x04"]
+  //   optional bytes value = 1 [(buf.validate.field).bytes.not_in = {"\x01\x02", "\x02\x03", "\x03\x04"}];
+  // }
+  // ```
+  repeated bytes not_in = 9 [(predefined).cel = {
+    id: "bytes.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // WellKnown rules provide advanced constraints against common byte
+  // patterns
+  oneof well_known {
+    // `ip` ensures that the field `value` is a valid IP address (v4 or v6) in byte format.
+    // If the field value doesn't meet this constraint, an error message is generated.
+    //
+    // ```proto
+    // message MyBytes {
+    //   // value must be a valid IP address
+    //   optional bytes value = 1 [(buf.validate.field).bytes.ip = true];
+    // }
+    // ```
+    bool ip = 10 [
+      (predefined).cel = {
+        id: "bytes.ip"
+        message: "value must be a valid IP address"
+        expression: "!rules.ip || this.size() == 0 || this.size() == 4 || this.size() == 16"
+      },
+      (predefined).cel = {
+        id: "bytes.ip_empty"
+        message: "value is empty, which is not a valid IP address"
+        expression: "!rules.ip || this.size() != 0"
+      }
+    ];
+
+    // `ipv4` ensures that the field `value` is a valid IPv4 address in byte format.
+    // If the field value doesn't meet this constraint, an error message is generated.
+    //
+    // ```proto
+    // message MyBytes {
+    //   // value must be a valid IPv4 address
+    //   optional bytes value = 1 [(buf.validate.field).bytes.ipv4 = true];
+    // }
+    // ```
+    bool ipv4 = 11 [
+      (predefined).cel = {
+        id: "bytes.ipv4"
+        message: "value must be a valid IPv4 address"
+        expression: "!rules.ipv4 || this.size() == 0 || this.size() == 4"
+      },
+      (predefined).cel = {
+        id: "bytes.ipv4_empty"
+        message: "value is empty, which is not a valid IPv4 address"
+        expression: "!rules.ipv4 || this.size() != 0"
+      }
+    ];
+
+    // `ipv6` ensures that the field `value` is a valid IPv6 address in byte format.
+    // If the field value doesn't meet this constraint, an error message is generated.
+    // ```proto
+    // message MyBytes {
+    //   // value must be a valid IPv6 address
+    //   optional bytes value = 1 [(buf.validate.field).bytes.ipv6 = true];
+    // }
+    // ```
+    bool ipv6 = 12 [
+      (predefined).cel = {
+        id: "bytes.ipv6"
+        message: "value must be a valid IPv6 address"
+        expression: "!rules.ipv6 || this.size() == 0 || this.size() == 16"
+      },
+      (predefined).cel = {
+        id: "bytes.ipv6_empty"
+        message: "value is empty, which is not a valid IPv6 address"
+        expression: "!rules.ipv6 || this.size() != 0"
+      }
+    ];
+  }
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyBytes {
+  //   bytes value = 1 [
+  //     (buf.validate.field).bytes.example = "\x01\x02",
+  //     (buf.validate.field).bytes.example = "\x02\x03"
+  //   ];
+  // }
+  // ```
+  repeated bytes example = 14 [(predefined).cel = {
+    id: "bytes.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// EnumRules describe the constraints applied to `enum` values.
+message EnumRules {
+  // `const` requires the field value to exactly match the specified enum value.
+  // If the field value doesn't match, an error message is generated.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //   // The field `value` must be exactly MY_ENUM_VALUE1.
+  //   MyEnum value = 1 [(buf.validate.field).enum.const = 1];
+  // }
+  // ```
+  optional int32 const = 1 [(predefined).cel = {
+    id: "enum.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+
+  // `defined_only` requires the field value to be one of the defined values for
+  // this enum, failing on any undefined value.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //   // The field `value` must be a defined value of MyEnum.
+  //   MyEnum value = 1 [(buf.validate.field).enum.defined_only = true];
+  // }
+  // ```
+  optional bool defined_only = 2;
+
+  // `in` requires the field value to be equal to one of the
+  //specified enum values. If the field value doesn't match any of the
+  //specified values, an error message is generated.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //   // The field `value` must be equal to one of the specified values.
+  //   MyEnum value = 1 [(buf.validate.field).enum = { in: [1, 2]}];
+  // }
+  // ```
+  repeated int32 in = 3 [(predefined).cel = {
+    id: "enum.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` requires the field value to be not equal to any of the
+  //specified enum values. If the field value matches one of the specified
+  // values, an error message is generated.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //   // The field `value` must not be equal to any of the specified values.
+  //   MyEnum value = 1 [(buf.validate.field).enum = { not_in: [1, 2]}];
+  // }
+  // ```
+  repeated int32 not_in = 4 [(predefined).cel = {
+    id: "enum.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // enum MyEnum {
+  //   MY_ENUM_UNSPECIFIED = 0;
+  //   MY_ENUM_VALUE1 = 1;
+  //   MY_ENUM_VALUE2 = 2;
+  // }
+  //
+  // message MyMessage {
+  //     (buf.validate.field).enum.example = 1,
+  //     (buf.validate.field).enum.example = 2
+  // }
+  // ```
+  repeated int32 example = 5 [(predefined).cel = {
+    id: "enum.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// RepeatedRules describe the constraints applied to `repeated` values.
+message RepeatedRules {
+  // `min_items` requires that this field must contain at least the specified
+  // minimum number of items.
+  //
+  // Note that `min_items = 1` is equivalent to setting a field as `required`.
+  //
+  // ```proto
+  // message MyRepeated {
+  //   // value must contain at least  2 items
+  //   repeated string value = 1 [(buf.validate.field).repeated.min_items = 2];
+  // }
+  // ```
+  optional uint64 min_items = 1 [(predefined).cel = {
+    id: "repeated.min_items"
+    expression: "uint(this.size()) < rules.min_items ? 'value must contain at least %d item(s)'.format([rules.min_items]) : ''"
+  }];
+
+  // `max_items` denotes that this field must not exceed a
+  // certain number of items as the upper limit. If the field contains more
+  // items than specified, an error message will be generated, requiring the
+  // field to maintain no more than the specified number of items.
+  //
+  // ```proto
+  // message MyRepeated {
+  //   // value must contain no more than 3 item(s)
+  //   repeated string value = 1 [(buf.validate.field).repeated.max_items = 3];
+  // }
+  // ```
+  optional uint64 max_items = 2 [(predefined).cel = {
+    id: "repeated.max_items"
+    expression: "uint(this.size()) > rules.max_items ? 'value must contain no more than %s item(s)'.format([rules.max_items]) : ''"
+  }];
+
+  // `unique` indicates that all elements in this field must
+  // be unique. This constraint is strictly applicable to scalar and enum
+  // types, with message types not being supported.
+  //
+  // ```proto
+  // message MyRepeated {
+  //   // repeated value must contain unique items
+  //   repeated string value = 1 [(buf.validate.field).repeated.unique = true];
+  // }
+  // ```
+  optional bool unique = 3 [(predefined).cel = {
+    id: "repeated.unique"
+    message: "repeated value must contain unique items"
+    expression: "!rules.unique || this.unique()"
+  }];
+
+  // `items` details the constraints to be applied to each item
+  // in the field. Even for repeated message fields, validation is executed
+  // against each item unless skip is explicitly specified.
+  //
+  // ```proto
+  // message MyRepeated {
+  //   // The items in the field `value` must follow the specified constraints.
+  //   repeated string value = 1 [(buf.validate.field).repeated.items = {
+  //     string: {
+  //       min_len: 3
+  //       max_len: 10
+  //     }
+  //   }];
+  // }
+  // ```
+  optional FieldConstraints items = 4;
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// MapRules describe the constraints applied to `map` values.
+message MapRules {
+  //Specifies the minimum number of key-value pairs allowed. If the field has
+  // fewer key-value pairs than specified, an error message is generated.
+  //
+  // ```proto
+  // message MyMap {
+  //   // The field `value` must have at least 2 key-value pairs.
+  //   map<string, string> value = 1 [(buf.validate.field).map.min_pairs = 2];
+  // }
+  // ```
+  optional uint64 min_pairs = 1 [(predefined).cel = {
+    id: "map.min_pairs"
+    expression: "uint(this.size()) < rules.min_pairs ? 'map must be at least %d entries'.format([rules.min_pairs]) : ''"
+  }];
+
+  //Specifies the maximum number of key-value pairs allowed. If the field has
+  // more key-value pairs than specified, an error message is generated.
+  //
+  // ```proto
+  // message MyMap {
+  //   // The field `value` must have at most 3 key-value pairs.
+  //   map<string, string> value = 1 [(buf.validate.field).map.max_pairs = 3];
+  // }
+  // ```
+  optional uint64 max_pairs = 2 [(predefined).cel = {
+    id: "map.max_pairs"
+    expression: "uint(this.size()) > rules.max_pairs ? 'map must be at most %d entries'.format([rules.max_pairs]) : ''"
+  }];
+
+  //Specifies the constraints to be applied to each key in the field.
+  //
+  // ```proto
+  // message MyMap {
+  //   // The keys in the field `value` must follow the specified constraints.
+  //   map<string, string> value = 1 [(buf.validate.field).map.keys = {
+  //     string: {
+  //       min_len: 3
+  //       max_len: 10
+  //     }
+  //   }];
+  // }
+  // ```
+  optional FieldConstraints keys = 4;
+
+  //Specifies the constraints to be applied to the value of each key in the
+  // field. Message values will still have their validations evaluated unless
+  //skip is specified here.
+  //
+  // ```proto
+  // message MyMap {
+  //   // The values in the field `value` must follow the specified constraints.
+  //   map<string, string> value = 1 [(buf.validate.field).map.values = {
+  //     string: {
+  //       min_len: 5
+  //       max_len: 20
+  //     }
+  //   }];
+  // }
+  // ```
+  optional FieldConstraints values = 5;
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// AnyRules describe constraints applied exclusively to the `google.protobuf.Any` well-known type.
+message AnyRules {
+  // `in` requires the field's `type_url` to be equal to one of the
+  //specified values. If it doesn't match any of the specified values, an error
+  // message is generated.
+  //
+  // ```proto
+  // message MyAny {
+  //   //  The `value` field must have a `type_url` equal to one of the specified values.
+  //   google.protobuf.Any value = 1 [(buf.validate.field).any.in = ["type.googleapis.com/MyType1", "type.googleapis.com/MyType2"]];
+  // }
+  // ```
+  repeated string in = 2;
+
+  // requires the field's type_url to be not equal to any of the specified values. If it matches any of the specified values, an error message is generated.
+  //
+  // ```proto
+  // message MyAny {
+  //   // The field `value` must not have a `type_url` equal to any of the specified values.
+  //   google.protobuf.Any value = 1 [(buf.validate.field).any.not_in = ["type.googleapis.com/ForbiddenType1", "type.googleapis.com/ForbiddenType2"]];
+  // }
+  // ```
+  repeated string not_in = 3;
+}
+
+// DurationRules describe the constraints applied exclusively to the `google.protobuf.Duration` well-known type.
+message DurationRules {
+  // `const` dictates that the field must match the specified value of the `google.protobuf.Duration` type exactly.
+  // If the field's value deviates from the specified value, an error message
+  // will be generated.
+  //
+  // ```proto
+  // message MyDuration {
+  //   // value must equal 5s
+  //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.const = "5s"];
+  // }
+  // ```
+  optional google.protobuf.Duration const = 2 [(predefined).cel = {
+    id: "duration.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // `lt` stipulates that the field must be less than the specified value of the `google.protobuf.Duration` type,
+    // exclusive. If the field's value is greater than or equal to the specified
+    // value, an error message will be generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //   // value must be less than 5s
+    //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.lt = "5s"];
+    // }
+    // ```
+    google.protobuf.Duration lt = 3 [(predefined).cel = {
+      id: "duration.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // `lte` indicates that the field must be less than or equal to the specified
+    // value of the `google.protobuf.Duration` type, inclusive. If the field's value is greater than the specified value,
+    // an error message will be generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //   // value must be less than or equal to 10s
+    //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.lte = "10s"];
+    // }
+    // ```
+    google.protobuf.Duration lte = 4 [(predefined).cel = {
+      id: "duration.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the duration field value to be greater than the specified
+    // value (exclusive). If the value of `gt` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //   // duration must be greater than 5s [duration.gt]
+    //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.gt = { seconds: 5 }];
+    //
+    //   // duration must be greater than 5s and less than 10s [duration.gt_lt]
+    //   google.protobuf.Duration another_value = 2 [(buf.validate.field).duration = { gt: { seconds: 5 }, lt: { seconds: 10 } }];
+    //
+    //   // duration must be greater than 10s or less than 5s [duration.gt_lt_exclusive]
+    //   google.protobuf.Duration other_value = 3 [(buf.validate.field).duration = { gt: { seconds: 10 }, lt: { seconds: 5 } }];
+    // }
+    // ```
+    google.protobuf.Duration gt = 5 [
+      (predefined).cel = {
+        id: "duration.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the duration field value to be greater than or equal to the
+    // specified value (exclusive). If the value of `gte` is larger than a
+    // specified `lt` or `lte`, the range is reversed, and the field value must
+    // be outside the specified range. If the field value doesn't meet the
+    // required conditions, an error message is generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //  // duration must be greater than or equal to 5s [duration.gte]
+    //  google.protobuf.Duration value = 1 [(buf.validate.field).duration.gte = { seconds: 5 }];
+    //
+    //  // duration must be greater than or equal to 5s and less than 10s [duration.gte_lt]
+    //  google.protobuf.Duration another_value = 2 [(buf.validate.field).duration = { gte: { seconds: 5 }, lt: { seconds: 10 } }];
+    //
+    //  // duration must be greater than or equal to 10s or less than 5s [duration.gte_lt_exclusive]
+    //  google.protobuf.Duration other_value = 3 [(buf.validate.field).duration = { gte: { seconds: 10 }, lt: { seconds: 5 } }];
+    // }
+    // ```
+    google.protobuf.Duration gte = 6 [
+      (predefined).cel = {
+        id: "duration.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "duration.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+  }
+
+  // `in` asserts that the field must be equal to one of the specified values of the `google.protobuf.Duration` type.
+  // If the field's value doesn't correspond to any of the specified values,
+  // an error message will be generated.
+  //
+  // ```proto
+  // message MyDuration {
+  //   // value must be in list [1s, 2s, 3s]
+  //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.in = ["1s", "2s", "3s"]];
+  // }
+  // ```
+  repeated google.protobuf.Duration in = 7 [(predefined).cel = {
+    id: "duration.in"
+    expression: "!(this in dyn(rules)['in']) ? 'value must be in list %s'.format([dyn(rules)['in']]) : ''"
+  }];
+
+  // `not_in` denotes that the field must not be equal to
+  // any of the specified values of the `google.protobuf.Duration` type.
+  // If the field's value matches any of these values, an error message will be
+  // generated.
+  //
+  // ```proto
+  // message MyDuration {
+  //   // value must not be in list [1s, 2s, 3s]
+  //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.not_in = ["1s", "2s", "3s"]];
+  // }
+  // ```
+  repeated google.protobuf.Duration not_in = 8 [(predefined).cel = {
+    id: "duration.not_in"
+    expression: "this in rules.not_in ? 'value must not be in list %s'.format([rules.not_in]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyDuration {
+  //   google.protobuf.Duration value = 1 [
+  //     (buf.validate.field).duration.example = { seconds: 1 },
+  //     (buf.validate.field).duration.example = { seconds: 2 },
+  //   ];
+  // }
+  // ```
+  repeated google.protobuf.Duration example = 9 [(predefined).cel = {
+    id: "duration.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// TimestampRules describe the constraints applied exclusively to the `google.protobuf.Timestamp` well-known type.
+message TimestampRules {
+  // `const` dictates that this field, of the `google.protobuf.Timestamp` type, must exactly match the specified value. If the field value doesn't correspond to the specified timestamp, an error message will be generated.
+  //
+  // ```proto
+  // message MyTimestamp {
+  //   // value must equal 2023-05-03T10:00:00Z
+  //   google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.const = {seconds: 1727998800}];
+  // }
+  // ```
+  optional google.protobuf.Timestamp const = 2 [(predefined).cel = {
+    id: "timestamp.const"
+    expression: "this != rules.const ? 'value must equal %s'.format([rules.const]) : ''"
+  }];
+  oneof less_than {
+    // requires the duration field value to be less than the specified value (field < value). If the field value doesn't meet the required conditions, an error message is generated.
+    //
+    // ```proto
+    // message MyDuration {
+    //   // duration must be less than 'P3D' [duration.lt]
+    //   google.protobuf.Duration value = 1 [(buf.validate.field).duration.lt = { seconds: 259200 }];
+    // }
+    // ```
+    google.protobuf.Timestamp lt = 3 [(predefined).cel = {
+      id: "timestamp.lt"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this >= rules.lt"
+              "? 'value must be less than %s'.format([rules.lt]) : ''"
+    }];
+
+    // requires the timestamp field value to be less than or equal to the specified value (field <= value). If the field value doesn't meet the required conditions, an error message is generated.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //   // timestamp must be less than or equal to '2023-05-14T00:00:00Z' [timestamp.lte]
+    //   google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.lte = { seconds: 1678867200 }];
+    // }
+    // ```
+    google.protobuf.Timestamp lte = 4 [(predefined).cel = {
+      id: "timestamp.lte"
+      expression:
+          "!has(rules.gte) && !has(rules.gt) && this > rules.lte"
+              "? 'value must be less than or equal to %s'.format([rules.lte]) : ''"
+    }];
+
+    // `lt_now` specifies that this field, of the `google.protobuf.Timestamp` type, must be less than the current time. `lt_now` can only be used with the `within` rule.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //  // value must be less than now
+    //   google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.lt_now = true];
+    // }
+    // ```
+    bool lt_now = 7 [(predefined).cel = {
+      id: "timestamp.lt_now"
+      expression: "(rules.lt_now && this > now) ? 'value must be less than now' : ''"
+    }];
+  }
+  oneof greater_than {
+    // `gt` requires the timestamp field value to be greater than the specified
+    // value (exclusive). If the value of `gt` is larger than a specified `lt`
+    // or `lte`, the range is reversed, and the field value must be outside the
+    // specified range. If the field value doesn't meet the required conditions,
+    // an error message is generated.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //   // timestamp must be greater than '2023-01-01T00:00:00Z' [timestamp.gt]
+    //   google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.gt = { seconds: 1672444800 }];
+    //
+    //   // timestamp must be greater than '2023-01-01T00:00:00Z' and less than '2023-01-02T00:00:00Z' [timestamp.gt_lt]
+    //   google.protobuf.Timestamp another_value = 2 [(buf.validate.field).timestamp = { gt: { seconds: 1672444800 }, lt: { seconds: 1672531200 } }];
+    //
+    //   // timestamp must be greater than '2023-01-02T00:00:00Z' or less than '2023-01-01T00:00:00Z' [timestamp.gt_lt_exclusive]
+    //   google.protobuf.Timestamp other_value = 3 [(buf.validate.field).timestamp = { gt: { seconds: 1672531200 }, lt: { seconds: 1672444800 } }];
+    // }
+    // ```
+    google.protobuf.Timestamp gt = 5 [
+      (predefined).cel = {
+        id: "timestamp.gt"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this <= rules.gt"
+                "? 'value must be greater than %s'.format([rules.gt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gt_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gt && (this >= rules.lt || this <= rules.gt)"
+                "? 'value must be greater than %s and less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gt_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gt && (rules.lt <= this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than %s'.format([rules.gt, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gt_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gt && (this > rules.lte || this <= rules.gt)"
+                "? 'value must be greater than %s and less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gt_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gt && (rules.lte < this && this <= rules.gt)"
+                "? 'value must be greater than %s or less than or equal to %s'.format([rules.gt, rules.lte]) : ''"
+      }
+    ];
+
+    // `gte` requires the timestamp field value to be greater than or equal to the
+    // specified value (exclusive). If the value of `gte` is larger than a
+    // specified `lt` or `lte`, the range is reversed, and the field value
+    // must be outside the specified range. If the field value doesn't meet
+    // the required conditions, an error message is generated.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //   // timestamp must be greater than or equal to '2023-01-01T00:00:00Z' [timestamp.gte]
+    //   google.protobuf.Timestamp value = 1 [(buf.validate.field).timestamp.gte = { seconds: 1672444800 }];
+    //
+    //   // timestamp must be greater than or equal to '2023-01-01T00:00:00Z' and less than '2023-01-02T00:00:00Z' [timestamp.gte_lt]
+    //   google.protobuf.Timestamp another_value = 2 [(buf.validate.field).timestamp = { gte: { seconds: 1672444800 }, lt: { seconds: 1672531200 } }];
+    //
+    //   // timestamp must be greater than or equal to '2023-01-02T00:00:00Z' or less than '2023-01-01T00:00:00Z' [timestamp.gte_lt_exclusive]
+    //   google.protobuf.Timestamp other_value = 3 [(buf.validate.field).timestamp = { gte: { seconds: 1672531200 }, lt: { seconds: 1672444800 } }];
+    // }
+    // ```
+    google.protobuf.Timestamp gte = 6 [
+      (predefined).cel = {
+        id: "timestamp.gte"
+        expression:
+            "!has(rules.lt) && !has(rules.lte) && this < rules.gte"
+                "? 'value must be greater than or equal to %s'.format([rules.gte]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gte_lt"
+        expression:
+            "has(rules.lt) && rules.lt >= rules.gte && (this >= rules.lt || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gte_lt_exclusive"
+        expression:
+            "has(rules.lt) && rules.lt < rules.gte && (rules.lt <= this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than %s'.format([rules.gte, rules.lt]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gte_lte"
+        expression:
+            "has(rules.lte) && rules.lte >= rules.gte && (this > rules.lte || this < rules.gte)"
+                "? 'value must be greater than or equal to %s and less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      },
+      (predefined).cel = {
+        id: "timestamp.gte_lte_exclusive"
+        expression:
+            "has(rules.lte) && rules.lte < rules.gte && (rules.lte < this && this < rules.gte)"
+                "? 'value must be greater than or equal to %s or less than or equal to %s'.format([rules.gte, rules.lte]) : ''"
+      }
+    ];
+
+    // `gt_now` specifies that this field, of the `google.protobuf.Timestamp` type, must be greater than the current time. `gt_now` can only be used with the `within` rule.
+    //
+    // ```proto
+    // message MyTimestamp {
+    //   // value must be greater than now
+    //   google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.gt_now = true];
+    // }
+    // ```
+    bool gt_now = 8 [(predefined).cel = {
+      id: "timestamp.gt_now"
+      expression: "(rules.gt_now && this < now) ? 'value must be greater than now' : ''"
+    }];
+  }
+
+  // `within` specifies that this field, of the `google.protobuf.Timestamp` type, must be within the specified duration of the current time. If the field value isn't within the duration, an error message is generated.
+  //
+  // ```proto
+  // message MyTimestamp {
+  //   // value must be within 1 hour of now
+  //   google.protobuf.Timestamp created_at = 1 [(buf.validate.field).timestamp.within = {seconds: 3600}];
+  // }
+  // ```
+  optional google.protobuf.Duration within = 9 [(predefined).cel = {
+    id: "timestamp.within"
+    expression: "this < now-rules.within || this > now+rules.within ? 'value must be within %s of now'.format([rules.within]) : ''"
+  }];
+
+  // `example` specifies values that the field may have. These values SHOULD
+  // conform to other constraints. `example` values will not impact validation
+  // but may be used as helpful guidance on how to populate the given field.
+  //
+  // ```proto
+  // message MyTimestamp {
+  //   google.protobuf.Timestamp value = 1 [
+  //     (buf.validate.field).timestamp.example = { seconds: 1672444800 },
+  //     (buf.validate.field).timestamp.example = { seconds: 1672531200 },
+  //   ];
+  // }
+  // ```
+
+  repeated google.protobuf.Timestamp example = 10 [(predefined).cel = {
+    id: "timestamp.example"
+    expression: "true"
+  }];
+
+  // Extension fields in this range that have the (buf.validate.predefined)
+  // option set will be treated as predefined field constraints that can then be
+  // set on the field options of other fields to apply field constraints.
+  // Extension numbers 1000 to 99999 are reserved for extension numbers that are
+  // defined in the [Protobuf Global Extension Registry][1]. Extension numbers
+  // above this range are reserved for extension numbers that are not explicitly
+  // assigned. For rules defined in publicly-consumed schemas, use of extensions
+  // above 99999 is discouraged due to the risk of conflicts.
+  //
+  // [1]: https://github.com/protocolbuffers/protobuf/blob/main/docs/options.md
+  extensions 1000 to max;
+}
+
+// `Violations` is a collection of `Violation` messages. This message type is returned by
+// protovalidate when a proto message fails to meet the requirements set by the `Constraint` validation rules.
+// Each individual violation is represented by a `Violation` message.
+message Violations {
+  // `violations` is a repeated field that contains all the `Violation` messages corresponding to the violations detected.
+  repeated Violation violations = 1;
+}
+
+// `Violation` represents a single instance where a validation rule, expressed
+// as a `Constraint`, was not met. It provides information about the field that
+// caused the violation, the specific constraint that wasn't fulfilled, and a
+// human-readable error message.
+//
+// ```json
+// {
+//   "fieldPath": "bar",
+//   "constraintId": "foo.bar",
+//   "message": "bar must be greater than 0"
+// }
+// ```
+message Violation {
+  // `field` is a machine-readable path to the field that failed validation.
+  // This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+  //
+  // For example, consider the following message:
+  //
+  // ```proto
+  // message Message {
+  //   bool a = 1 [(buf.validate.field).required = true];
+  // }
+  // ```
+  //
+  // It could produce the following violation:
+  //
+  // ```textproto
+  // violation {
+  //   field { element { field_number: 1, field_name: "a", field_type: 8 } }
+  //   ...
+  // }
+  // ```
+  optional FieldPath field = 5;
+
+  // `rule` is a machine-readable path that points to the specific constraint rule that failed validation.
+  // This will be a nested field starting from the FieldConstraints of the field that failed validation.
+  // For custom constraints, this will provide the path of the constraint, e.g. `cel[0]`.
+  //
+  // For example, consider the following message:
+  //
+  // ```proto
+  // message Message {
+  //   bool a = 1 [(buf.validate.field).required = true];
+  //   bool b = 2 [(buf.validate.field).cel = {
+  //     id: "custom_constraint",
+  //     expression: "!this ? 'b must be true': ''"
+  //   }]
+  // }
+  // ```
+  //
+  // It could produce the following violations:
+  //
+  // ```textproto
+  // violation {
+  //   rule { element { field_number: 25, field_name: "required", field_type: 8 } }
+  //   ...
+  // }
+  // violation {
+  //   rule { element { field_number: 23, field_name: "cel", field_type: 11, index: 0 } }
+  //   ...
+  // }
+  // ```
+  optional FieldPath rule = 6;
+
+  // `field_path` is a human-readable identifier that points to the specific field that failed the validation.
+  // This could be a nested field, in which case the path will include all the parent fields leading to the actual field that caused the violation.
+  //
+  // Deprecated: use the `field` instead.
+  optional string field_path = 1 [deprecated = true];
+
+  // `constraint_id` is the unique identifier of the `Constraint` that was not fulfilled.
+  // This is the same `id` that was specified in the `Constraint` message, allowing easy tracing of which rule was violated.
+  optional string constraint_id = 2;
+
+  // `message` is a human-readable error message that describes the nature of the violation.
+  // This can be the default error message from the violated `Constraint`, or it can be a custom message that gives more context about the violation.
+  optional string message = 3;
+
+  // `for_key` indicates whether the violation was caused by a map key, rather than a value.
+  optional bool for_key = 4;
+}
+
+// `FieldPath` provides a path to a nested protobuf field.
+//
+// This message provides enough information to render a dotted field path even without protobuf descriptors.
+// It also provides enough information to resolve a nested field through unknown wire data.
+message FieldPath {
+  // `elements` contains each element of the path, starting from the root and recursing downward.
+  repeated FieldPathElement elements = 1;
+}
+
+// `FieldPathElement` provides enough information to nest through a single protobuf field.
+//
+// If the selected field is a map or repeated field, the `subscript` value selects a specific element from it.
+// A path that refers to a value nested under a map key or repeated field index will have a `subscript` value.
+// The `field_type` field allows unambiguous resolution of a field even if descriptors are not available.
+message FieldPathElement {
+  // `field_number` is the field number this path element refers to.
+  optional int32 field_number = 1;
+
+  // `field_name` contains the field name this path element refers to.
+  // This can be used to display a human-readable path even if the field number is unknown.
+  optional string field_name = 2;
+
+  // `field_type` specifies the type of this field. When using reflection, this value is not needed.
+  //
+  // This value is provided to make it possible to traverse unknown fields through wire data.
+  // When traversing wire data, be mindful of both packed[1] and delimited[2] encoding schemes.
+  //
+  // [1]: https://protobuf.dev/programming-guides/encoding/#packed
+  // [2]: https://protobuf.dev/programming-guides/encoding/#groups
+  //
+  // N.B.: Although groups are deprecated, the corresponding delimited encoding scheme is not, and
+  // can be explicitly used in Protocol Buffers 2023 Edition.
+  optional google.protobuf.FieldDescriptorProto.Type field_type = 3;
+
+  // `key_type` specifies the map key type of this field. This value is useful when traversing
+  // unknown fields through wire data: specifically, it allows handling the differences between
+  // different integer encodings.
+  optional google.protobuf.FieldDescriptorProto.Type key_type = 4;
+
+  // `value_type` specifies map value type of this field. This is useful if you want to display a
+  // value inside unknown fields through wire data.
+  optional google.protobuf.FieldDescriptorProto.Type value_type = 5;
+
+  // `subscript` contains a repeated index or map key, if this path element nests into a repeated or map field.
+  oneof subscript {
+    // `index` specifies a 0-based index into a repeated field.
+    uint64 index = 6;
+
+    // `bool_key` specifies a map key of type bool.
+    bool bool_key = 7;
+
+    // `int_key` specifies a map key of type int32, int64, sint32, sint64, sfixed32 or sfixed64.
+    int64 int_key = 8;
+
+    // `uint_key` specifies a map key of type uint32, uint64, fixed32 or fixed64.
+    uint64 uint_key = 9;
+
+    // `string_key` specifies a map key of type string.
+    string string_key = 10;
+  }
+}
\ No newline at end of file
diff --git a/transport/grpc/server.go b/transport/grpc/server.go
index 2b260bf1..fb1fa807 100644
--- a/transport/grpc/server.go
+++ b/transport/grpc/server.go
@@ -223,13 +223,25 @@ func (s *Server) Start(ctx context.Context) error {
 }
 
 // Stop stop the gRPC server.
-func (s *Server) Stop(_ context.Context) error {
+func (s *Server) Stop(ctx context.Context) error {
 	if s.adminClean != nil {
 		s.adminClean()
 	}
 	s.health.Shutdown()
-	s.GracefulStop()
-	log.Info("[gRPC] server stopping")
+
+	done := make(chan struct{})
+	go func() {
+		defer close(done)
+		log.Info("[gRPC] server stopping")
+		s.Server.GracefulStop()
+	}()
+
+	select {
+	case <-done:
+	case <-ctx.Done():
+		log.Warn("[gRPC] server couldn't stop gracefully in time, doing force stop")
+		s.Server.Stop()
+	}
 	return nil
 }
 
diff --git a/transport/http/server.go b/transport/http/server.go
index 457fe724..dc92e789 100644
--- a/transport/http/server.go
+++ b/transport/http/server.go
@@ -343,7 +343,14 @@ func (s *Server) Start(ctx context.Context) error {
 // Stop stop the HTTP server.
 func (s *Server) Stop(ctx context.Context) error {
 	log.Info("[HTTP] server stopping")
-	return s.Shutdown(ctx)
+	err := s.Shutdown(ctx)
+	if err != nil {
+		if ctx.Err() != nil {
+			log.Warn("[HTTP] server couldn't stop gracefully in time, doing force stop")
+			err = s.Server.Close()
+		}
+	}
+	return err
 }
 
 func (s *Server) listenAndEndpoint() error {


Test patch:
diff --git a/cmd/kratos/internal/base/mod_test.go b/cmd/kratos/internal/base/mod_test.go
index da12fd56..2b2c0743 100644
--- a/cmd/kratos/internal/base/mod_test.go
+++ b/cmd/kratos/internal/base/mod_test.go
@@ -25,7 +25,7 @@ func TestModulePath(t *testing.T) {
 
 	mod := `module github.com/go-kratos/kratos/v2
 
-go 1.19`
+go 1.21`
 	_, err = f.WriteString(mod)
 	if err != nil {
 		t.Fatal(err)
diff --git a/contrib/middleware/validate/internal/testdata/generate.go b/contrib/middleware/validate/internal/testdata/generate.go
new file mode 100644
index 00000000..03809572
--- /dev/null
+++ b/contrib/middleware/validate/internal/testdata/generate.go
@@ -0,0 +1,3 @@
+package testdata
+
+//go:generate protoc -I . -I ../../../../../third_party --go_out=paths=source_relative:. ./test.proto
diff --git a/contrib/middleware/validate/internal/testdata/test.pb.go b/contrib/middleware/validate/internal/testdata/test.pb.go
new file mode 100644
index 00000000..c72c371d
--- /dev/null
+++ b/contrib/middleware/validate/internal/testdata/test.pb.go
@@ -0,0 +1,258 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.36.0
+// 	protoc        v5.28.3
+// source: test.proto
+
+package testdata
+
+import (
+	_ "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate"
+	_ "github.com/envoyproxy/protoc-gen-validate/validate"
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Legacy struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Name          string                 `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Age           int32                  `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Legacy) Reset() {
+	*x = Legacy{}
+	mi := &file_test_proto_msgTypes[0]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Legacy) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Legacy) ProtoMessage() {}
+
+func (x *Legacy) ProtoReflect() protoreflect.Message {
+	mi := &file_test_proto_msgTypes[0]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Legacy.ProtoReflect.Descriptor instead.
+func (*Legacy) Descriptor() ([]byte, []int) {
+	return file_test_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Legacy) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Legacy) GetAge() int32 {
+	if x != nil {
+		return x.Age
+	}
+	return 0
+}
+
+type Mixed struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Name          string                 `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Age           int32                  `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Mixed) Reset() {
+	*x = Mixed{}
+	mi := &file_test_proto_msgTypes[1]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Mixed) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Mixed) ProtoMessage() {}
+
+func (x *Mixed) ProtoReflect() protoreflect.Message {
+	mi := &file_test_proto_msgTypes[1]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Mixed.ProtoReflect.Descriptor instead.
+func (*Mixed) Descriptor() ([]byte, []int) {
+	return file_test_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *Mixed) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Mixed) GetAge() int32 {
+	if x != nil {
+		return x.Age
+	}
+	return 0
+}
+
+type Modern struct {
+	state         protoimpl.MessageState `protogen:"open.v1"`
+	Name          string                 `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+	Age           int32                  `protobuf:"varint,2,opt,name=age,proto3" json:"age,omitempty"`
+	unknownFields protoimpl.UnknownFields
+	sizeCache     protoimpl.SizeCache
+}
+
+func (x *Modern) Reset() {
+	*x = Modern{}
+	mi := &file_test_proto_msgTypes[2]
+	ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+	ms.StoreMessageInfo(mi)
+}
+
+func (x *Modern) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Modern) ProtoMessage() {}
+
+func (x *Modern) ProtoReflect() protoreflect.Message {
+	mi := &file_test_proto_msgTypes[2]
+	if x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Modern.ProtoReflect.Descriptor instead.
+func (*Modern) Descriptor() ([]byte, []int) {
+	return file_test_proto_rawDescGZIP(), []int{2}
+}
+
+func (x *Modern) GetName() string {
+	if x != nil {
+		return x.Name
+	}
+	return ""
+}
+
+func (x *Modern) GetAge() int32 {
+	if x != nil {
+		return x.Age
+	}
+	return 0
+}
+
+var File_test_proto protoreflect.FileDescriptor
+
+var file_test_proto_rawDesc = []byte{
+	0x0a, 0x0a, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x08, 0x74, 0x65,
+	0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69,
+	0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72,
+	0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61,
+	0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x40, 0x0a, 0x06,
+	0x4c, 0x65, 0x67, 0x61, 0x63, 0x79, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x05, 0x52, 0x04, 0x6e,
+	0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05,
+	0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x20, 0x12, 0x52, 0x03, 0x61, 0x67, 0x65, 0x22, 0x3f,
+	0x0a, 0x05, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x05, 0x52, 0x04,
+	0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x05, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x20, 0x12, 0x52, 0x03, 0x61, 0x67, 0x65, 0x22,
+	0x40, 0x0a, 0x06, 0x4d, 0x6f, 0x64, 0x65, 0x72, 0x6e, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xba, 0x48, 0x04, 0x72, 0x02, 0x10, 0x05,
+	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x03, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x05, 0x42, 0x07, 0xba, 0x48, 0x04, 0x1a, 0x02, 0x20, 0x12, 0x52, 0x03, 0x61, 0x67,
+	0x65, 0x42, 0x4b, 0x5a, 0x49, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
+	0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73,
+	0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x2f, 0x6d, 0x69, 0x64, 0x64, 0x6c, 0x65, 0x77,
+	0x61, 0x72, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x69, 0x6e, 0x74,
+	0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x64, 0x61, 0x74, 0x61, 0x62, 0x06,
+	0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_test_proto_rawDescOnce sync.Once
+	file_test_proto_rawDescData = file_test_proto_rawDesc
+)
+
+func file_test_proto_rawDescGZIP() []byte {
+	file_test_proto_rawDescOnce.Do(func() {
+		file_test_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_proto_rawDescData)
+	})
+	return file_test_proto_rawDescData
+}
+
+var file_test_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
+var file_test_proto_goTypes = []any{
+	(*Legacy)(nil), // 0: testdata.Legacy
+	(*Mixed)(nil),  // 1: testdata.Mixed
+	(*Modern)(nil), // 2: testdata.Modern
+}
+var file_test_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_test_proto_init() }
+func file_test_proto_init() {
+	if File_test_proto != nil {
+		return
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_test_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   3,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_test_proto_goTypes,
+		DependencyIndexes: file_test_proto_depIdxs,
+		MessageInfos:      file_test_proto_msgTypes,
+	}.Build()
+	File_test_proto = out.File
+	file_test_proto_rawDesc = nil
+	file_test_proto_goTypes = nil
+	file_test_proto_depIdxs = nil
+}
diff --git a/contrib/middleware/validate/internal/testdata/test.proto b/contrib/middleware/validate/internal/testdata/test.proto
new file mode 100644
index 00000000..8e4b82ba
--- /dev/null
+++ b/contrib/middleware/validate/internal/testdata/test.proto
@@ -0,0 +1,23 @@
+syntax = "proto3";
+
+package testdata;
+
+import "buf/validate/validate.proto";
+import "validate/validate.proto";
+
+option go_package = "github.com/go-kratos/kratos/contrib/middleware/validate/internal/testdata";
+
+message Legacy {
+  string name = 1 [(validate.rules).string.min_len = 5];
+  int32 age = 2 [(validate.rules).int32.gt = 18];
+}
+
+message Mixed {
+  string name = 1 [(buf.validate.field).string.min_len = 5];
+  int32 age = 2 [(validate.rules).int32.gt = 18];
+}
+
+message Modern {
+  string name = 1 [(buf.validate.field).string.min_len = 5];
+  int32 age = 2 [(buf.validate.field).int32.gt = 18];
+}
diff --git a/contrib/middleware/validate/validate_test.go b/contrib/middleware/validate/validate_test.go
new file mode 100644
index 00000000..86001820
--- /dev/null
+++ b/contrib/middleware/validate/validate_test.go
@@ -0,0 +1,82 @@
+package validate
+
+import (
+	"context"
+	"testing"
+
+	"google.golang.org/protobuf/proto"
+
+	"github.com/go-kratos/kratos/contrib/middleware/validate/v2/internal/testdata"
+	kerrors "github.com/go-kratos/kratos/v2/errors"
+	"github.com/go-kratos/kratos/v2/middleware"
+)
+
+type testcase struct {
+	name string
+	req  proto.Message
+	err  bool
+}
+
+func TestTable(t *testing.T) {
+	var mock middleware.Handler = func(context.Context, interface{}) (interface{}, error) { return nil, nil }
+
+	tests := []testcase{
+		{
+			name: "valid_legacy",
+			req:  &testdata.Legacy{Name: "testcase", Age: 19},
+			err:  false,
+		},
+		{
+			name: "invalid_legacy1",
+			req:  &testdata.Legacy{Name: "testcase", Age: 10},
+			err:  true,
+		},
+		{
+			name: "invalid_legacy2",
+			req:  &testdata.Legacy{Name: "test", Age: 100},
+			err:  true,
+		},
+		{
+			name: "valid_mixed",
+			req:  &testdata.Mixed{Name: "testcase", Age: 19},
+			err:  false,
+		},
+		{
+			name: "invalid_mixed1",
+			req:  &testdata.Mixed{Name: "testcase", Age: 10},
+			err:  true,
+		},
+		{
+			name: "invalid_mixed2",
+			req:  &testdata.Mixed{Name: "test", Age: 100},
+			err:  true,
+		},
+		{
+			name: "valid_modern",
+			req:  &testdata.Modern{Name: "testcase", Age: 19},
+			err:  false,
+		},
+		{
+			name: "invalid_modern1",
+			req:  &testdata.Modern{Name: "testcase", Age: 10},
+			err:  true,
+		},
+		{
+			name: "invalid_modern2",
+			req:  &testdata.Modern{Name: "test", Age: 100},
+			err:  true,
+		},
+	}
+
+	for _, test := range tests {
+		t.Run(test.name, func(t *testing.T) {
+			handle := ProtoValidate()(mock)
+			_, err := handle(context.Background(), test.req)
+			expect := test.err
+			actual := kerrors.IsBadRequest(err)
+			if expect != actual {
+				t.Errorf("case %s expect %v, actual %v, err %v", test.name, expect, actual, err)
+			}
+		})
+	}
+}
diff --git a/transport/grpc/server_test.go b/transport/grpc/server_test.go
index 0117db9a..38270922 100644
--- a/transport/grpc/server_test.go
+++ b/transport/grpc/server_test.go
@@ -1,6 +1,7 @@
 package grpc
 
 import (
+	"bytes"
 	"context"
 	"crypto/tls"
 	"fmt"
@@ -8,6 +9,7 @@ import (
 	"net/url"
 	"reflect"
 	"strings"
+	"sync"
 	"testing"
 	"time"
 
@@ -17,6 +19,7 @@ import (
 	"github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/internal/matcher"
 	pb "github.com/go-kratos/kratos/v2/internal/testdata/helloworld"
+	"github.com/go-kratos/kratos/v2/log"
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/transport"
 )
@@ -371,3 +374,127 @@ func TestListener(t *testing.T) {
 		t.Errorf("expect not empty")
 	}
 }
+
+func TestStop(t *testing.T) {
+	timeoutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
+	defer cancel()
+
+	tests := []struct {
+		name          string
+		ctx           context.Context
+		cancel        context.CancelFunc
+		wantForceStop bool
+	}{
+		{
+			name:          "normal",
+			ctx:           context.Background(),
+			cancel:        func() {},
+			wantForceStop: false,
+		},
+		{
+			name:          "timeout",
+			ctx:           timeoutCtx,
+			cancel:        cancel,
+			wantForceStop: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			l, err := net.Listen("tcp", ":0")
+			if err != nil {
+				t.Fatal(err)
+			}
+			defer l.Close()
+
+			old := log.GetLogger()
+			defer log.SetLogger(old)
+
+			// Create a logger to capture logs
+			var logs safeBytesBuffer
+			log.SetLogger(log.NewStdLogger(&logs))
+
+			s := NewServer(Listener(l))
+			pb.RegisterGreeterServer(s, &server{})
+
+			go func() {
+				err := s.Start(context.Background()) //nolint
+				if err != nil {
+					log.Fatal(err)
+				}
+			}()
+
+			time.Sleep(100 * time.Millisecond)
+
+			conn, err := DialInsecure(
+				context.Background(),
+				WithEndpoint(l.Addr().String()),
+				WithOptions(grpc.WithBlock()),
+			)
+			if err != nil {
+				t.Fatal(err)
+			}
+			defer conn.Close()
+
+			go func() {
+				client := pb.NewGreeterClient(conn)
+				if tt.wantForceStop {
+					// Simulate a long-running request
+					s, err := client.SayHelloStream(context.Background()) //nolint
+					if err != nil {
+						log.Fatal(err)
+					}
+					// Keep the stream open
+					for {
+						// Intentionally do not send messages, only receive messages
+						_, err := s.Recv()
+						if err != nil {
+							break
+						}
+					}
+				} else {
+					_, err := client.SayHello(context.Background(), &pb.HelloRequest{Name: "test"}) //nolint
+					if err != nil {
+						log.Error(err)
+					}
+				}
+			}()
+
+			time.Sleep(100 * time.Millisecond)
+
+			err = s.Stop(tt.ctx)
+			if err != nil {
+				t.Errorf("Expected no error, got %v", err)
+				return
+			}
+
+			// Check if the stop was forced or graceful
+			if tt.wantForceStop {
+				if !strings.Contains(logs.String(), "force stop") {
+					t.Errorf("Expected force stop\n%s", logs.String())
+				}
+			} else {
+				if strings.Contains(logs.String(), "force stop") {
+					t.Errorf("Expected graceful stop\n%s", logs.String())
+				}
+			}
+		})
+	}
+}
+
+type safeBytesBuffer struct {
+	mu  sync.Mutex
+	buf bytes.Buffer
+}
+
+func (b *safeBytesBuffer) Write(p []byte) (n int, err error) {
+	b.mu.Lock()
+	defer b.mu.Unlock()
+	return b.buf.Write(p)
+}
+
+func (b *safeBytesBuffer) String() string {
+	b.mu.Lock()
+	defer b.mu.Unlock()
+	return b.buf.String()
+}
diff --git a/transport/http/resolver_test.go b/transport/http/resolver_test.go
index e1cfd103..60b17221 100644
--- a/transport/http/resolver_test.go
+++ b/transport/http/resolver_test.go
@@ -6,6 +6,7 @@ import (
 	"fmt"
 	"reflect"
 	"strconv"
+	"sync"
 	"testing"
 	"time"
 
@@ -86,6 +87,8 @@ type mockWatch struct {
 
 	nextErr bool
 	stopErr bool
+
+	lock sync.Mutex
 }
 
 func (m *mockWatch) Next() ([]*registry.ServiceInstance, error) {
@@ -94,6 +97,8 @@ func (m *mockWatch) Next() ([]*registry.ServiceInstance, error) {
 		return nil, m.ctx.Err()
 	default:
 	}
+	m.lock.Lock()
+	defer m.lock.Unlock()
 	if m.nextErr {
 		return nil, errors.New("mock test error")
 	}
@@ -115,6 +120,8 @@ func (m *mockWatch) Next() ([]*registry.ServiceInstance, error) {
 }
 
 func (m *mockWatch) Stop() error {
+	m.lock.Lock()
+	defer m.lock.Unlock()
 	if m.stopErr {
 		return errors.New("mock test error")
 	}
@@ -130,46 +137,67 @@ func TestResolver(t *testing.T) {
 		return
 	}
 
+	cancelCtx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
 	// 异步 无需报错
-	_, err = newResolver(context.Background(), &mockDiscoveries{true, false, false}, ta, &mockRebalancer{}, false, false, 25)
+	r, err := newResolver(cancelCtx, &mockDiscoveries{true, false, false}, ta, &mockRebalancer{}, false, false, 25)
 	if err != nil {
 		t.Errorf("expect %v, got %v", nil, err)
 	}
+	if r != nil {
+		_ = r.Close()
+	}
 
 	// 同步 一切正常运行
-	_, err = newResolver(context.Background(), &mockDiscoveries{false, false, false}, ta, &mockRebalancer{}, true, true, 25)
+	r, err = newResolver(cancelCtx, &mockDiscoveries{false, false, false}, ta, &mockRebalancer{}, true, true, 25)
 	if err != nil {
 		t.Errorf("expect %v, got %v", nil, err)
 	}
+	if r != nil {
+		_ = r.Close()
+	}
 
 	// 同步 但是 next 出错 以及 stop 出错
-	_, err = newResolver(context.Background(), &mockDiscoveries{false, true, true}, ta, &mockRebalancer{}, true, true, 25)
+	r, err = newResolver(cancelCtx, &mockDiscoveries{false, true, true}, ta, &mockRebalancer{}, true, true, 25)
 	if err == nil {
 		t.Errorf("expect err, got nil")
 	}
+	if r != nil {
+		_ = r.Close()
+	}
 
 	// 同步 service name watch 失败
-	_, err = newResolver(context.Background(), &mockDiscoveries{false, true, true}, &Target{
+	r, err = newResolver(cancelCtx, &mockDiscoveries{false, true, true}, &Target{
 		Scheme:   "discovery",
 		Endpoint: errServiceName,
 	}, &mockRebalancer{}, true, true, 25)
 	if err == nil {
 		t.Errorf("expect err, got nil")
 	}
+	if r != nil {
+		_ = r.Close()
+	}
 
-	cancelCtx, cancel := context.WithCancel(context.Background())
 	cancel()
 
 	// 此处应该打印出来 context.Canceled
-	r, err := newResolver(cancelCtx, &mockDiscoveries{false, false, false}, ta, &mockRebalancer{}, false, false, 25)
+	r, err = newResolver(cancelCtx, &mockDiscoveries{false, false, false}, ta, &mockRebalancer{}, false, false, 25)
 	if err != nil {
 		t.Errorf("expect %v, got %v", nil, err)
 	}
-	_ = r.Close()
+	if r != nil {
+		_ = r.Close()
+	}
 
 	// 同步 但是服务取消，此时需要报错
-	_, err = newResolver(cancelCtx, &mockDiscoveries{false, false, true}, ta, &mockRebalancer{}, true, true, 25)
+	r, err = newResolver(cancelCtx, &mockDiscoveries{false, false, true}, ta, &mockRebalancer{}, true, true, 25)
 	if err == nil {
 		t.Errorf("expect ctx cancel err, got nil")
 	}
+	if r != nil {
+		_ = r.Close()
+	}
+
+	time.Sleep(100 * time.Millisecond)
 }
diff --git a/transport/http/server_test.go b/transport/http/server_test.go
index c692a4ff..665ac022 100644
--- a/transport/http/server_test.go
+++ b/transport/http/server_test.go
@@ -1,6 +1,7 @@
 package http
 
 import (
+	"bytes"
 	"context"
 	"crypto/tls"
 	"encoding/json"
@@ -9,13 +10,16 @@ import (
 	"io"
 	"net"
 	"net/http"
+	"net/http/httptest"
 	"reflect"
 	"strings"
+	"sync"
 	"testing"
 	"time"
 
 	kratoserrors "github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/internal/host"
+	"github.com/go-kratos/kratos/v2/log"
 )
 
 var h = func(w http.ResponseWriter, r *http.Request) {
@@ -382,3 +386,102 @@ func TestMethodNotAllowedHandler(t *testing.T) {
 		t.Errorf("expected %v got %v", mux, srv.router.MethodNotAllowedHandler)
 	}
 }
+
+func TestStop(t *testing.T) {
+	timeoutCtx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
+	defer cancel()
+
+	tests := []struct {
+		name          string
+		sleep         time.Duration
+		ctx           context.Context
+		cancel        context.CancelFunc
+		wantForceStop bool
+	}{
+		{
+			name:          "normal",
+			sleep:         0,
+			ctx:           context.Background(),
+			cancel:        func() {},
+			wantForceStop: false,
+		},
+		{
+			name:          "timeout",
+			sleep:         2 * time.Second,
+			ctx:           timeoutCtx,
+			cancel:        cancel,
+			wantForceStop: true,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			old := log.GetLogger()
+			defer log.SetLogger(old)
+
+			// Create a logger to capture logs
+			var logs safeBytesBuffer
+			log.SetLogger(log.NewStdLogger(&logs))
+
+			testServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+				t := time.NewTimer(tt.sleep)
+				defer t.Stop()
+				select {
+				case <-t.C:
+				case <-r.Context().Done():
+				}
+				w.WriteHeader(http.StatusOK)
+			}))
+			defer testServer.Close()
+
+			go func() {
+				resp, err := http.Get(testServer.URL)
+				if err != nil {
+					return
+				}
+				_ = resp.Body.Close()
+			}()
+
+			time.Sleep(100 * time.Millisecond)
+
+			s := &Server{
+				Server: testServer.Config,
+			}
+
+			tt.cancel()
+			err := s.Stop(tt.ctx)
+			if err != nil {
+				t.Errorf("Expected no error, got %v", err)
+				return
+			}
+
+			// Check if the stop was forced or graceful
+			if tt.wantForceStop {
+				if !strings.Contains(logs.String(), "force stop") {
+					t.Errorf("Expected force stop\n%s", logs.String())
+				}
+			} else {
+				if strings.Contains(logs.String(), "force stop") {
+					t.Errorf("Expected graceful stop\n%s", logs.String())
+				}
+			}
+		})
+	}
+}
+
+type safeBytesBuffer struct {
+	mu  sync.Mutex
+	buf bytes.Buffer
+}
+
+func (b *safeBytesBuffer) Write(p []byte) (n int, err error) {
+	b.mu.Lock()
+	defer b.mu.Unlock()
+	return b.buf.Write(p)
+}
+
+func (b *safeBytesBuffer) String() string {
+	b.mu.Lock()
+	defer b.mu.Unlock()
+	return b.buf.String()
+}