Repository: envoyproxy/gateway
Pull request #6016 (2025-05-12 13:21:35)

build(deps): bump the gomod group across 6 directories with 8 updates
Bumps the gomod group with 3 updates in the / directory: [github.com/miekg/dns](https://github.com/miekg/dns), [go.opentelemetry.io/proto/otlp](https://github.com/open-telemetry/opentelemetry-proto-go) and [golang.org/x/net](https://github.com/golang/net).
Bumps the gomod group with 1 update in the /examples/envoy-ext-auth directory: [golang.org/x/net](https://github.com/golang/net).
Bumps the gomod group with 1 update in the /examples/extension-server directory: [golang.org/x/net](https://github.com/golang/net).
Bumps the gomod group with 1 update in the /examples/grpc-ext-proc directory: [golang.org/x/net](https://github.com/golang/net).
Bumps the gomod group with 1 update in the /examples/preserve-case-backend directory: [github.com/valyala/fasthttp](https://github.com/valyala/fasthttp).
Bumps the gomod group with 3 updates in the /examples/simple-extension-server directory: [golang.org/x/net](https://github.com/golang/net), google.golang.org/protobuf and [github.com/envoyproxy/gateway](https://github.com/envoyproxy/gateway).

Updates `github.com/miekg/dns` from 1.1.65 to 1.1.66
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/miekg/dns/commit/10d76bc36d3ac95c7eaffd675456d52c7556ebe6"><code>10d76bc</code></a> Release 1.1.66</li>
<li><a href="https://github.com/miekg/dns/commit/ed312a384c7e26da583c0152c10d3b9e5e0ad549"><code>ed312a3</code></a> Fix logic in xfr ReadMsg + add test (<a href="https://redirect.github.com/miekg/dns/issues/1649">#1649</a>)</li>
<li><a href="https://github.com/miekg/dns/commit/27318b9ae1ae63856925c49aeebb267844c42dac"><code>27318b9</code></a> RFC 8490: Implement DSO type registry</li>
<li><a href="https://github.com/miekg/dns/commit/01abd80e27d6d8509cfece0ef510fbfd390971ea"><code>01abd80</code></a> DSO: Use Stateful as the suffix</li>
<li><a href="https://github.com/miekg/dns/commit/64211b39d1bc2a10df0e8beab070f4b72f8d62eb"><code>64211b3</code></a> Add the rcode DSO-TYPE Not Implemented / RFC8490 (<a href="https://redirect.github.com/miekg/dns/issues/1648">#1648</a>)</li>
<li><a href="https://github.com/miekg/dns/commit/8ec9f6746945869157671f11b1c1c26a8066d9b2"><code>8ec9f67</code></a> Upgrade all deps (<a href="https://redirect.github.com/miekg/dns/issues/1647">#1647</a>)</li>
<li><a href="https://github.com/miekg/dns/commit/8a570c6b43b605ad587996e11ca6dac9c9f1cbab"><code>8a570c6</code></a> A comment concerning newline while scanning (<a href="https://redirect.github.com/miekg/dns/issues/1645">#1645</a>)</li>
<li><a href="https://github.com/miekg/dns/commit/739cf212474e8ad0fd3edb4e585ac3922dbb6f3f"><code>739cf21</code></a> Return error for empty target (<a href="https://redirect.github.com/miekg/dns/issues/1627">#1627</a>)</li>
<li>See full diff in <a href="https://github.com/miekg/dns/compare/v1.1.65...v1.1.66">compare view</a></li>
</ul>
</details>
<br />

Updates `go.opentelemetry.io/proto/otlp` from 1.5.0 to 1.6.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/open-telemetry/opentelemetry-proto-go/releases">go.opentelemetry.io/proto/otlp's releases</a>.</em></p>
<blockquote>
<h2>v1.6.0</h2>
<h2>Overview</h2>
<p>Generated Go code for the <a href="https://github.com/open-telemetry/opentelemetry-proto/releases/tag/v1.6.0">v1.6.0</a> version of the OTLP</p>
<h3>OTLP Changelog</h3>
<blockquote>
<h3>Added</h3>
<ul>
<li>resource: Add EntityRef. <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto/pull/635">#635</a></li>
<li>general: add specs for empty telemetry envelopes. <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto/pull/622">#622</a></li>
</ul>
<h3>Changed</h3>
<ul>
<li>logs: Stabilize <code>event_name</code> field in <code>LogRecord</code> message. <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto/pull/643">#643</a></li>
<li>profiles: Move the lookup tables to ProfilesData. <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto/pull/644">#644</a></li>
<li>profiles: Move default sample_type from the string table to sample_type. <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto/pull/620">#620</a></li>
<li>general: remove comment on each service about keeping the RPC alive <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto/pull/637">#637</a></li>
<li>metrics: clarify when bucket_counts array may be empty <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto/pull/619">#619</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/open-telemetry/opentelemetry-proto/compare/v1.5.0...v1.6.0">https://github.com/open-telemetry/opentelemetry-proto/compare/v1.5.0...v1.6.0</a></p>
</blockquote>
<h2>What's Changed</h2>
<ul>
<li>chore(deps): update google.golang.org/genproto/googleapis/api digest to 5f5ef82 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/239">open-telemetry/opentelemetry-proto-go#239</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/rpc digest to 5f5ef82 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/240">open-telemetry/opentelemetry-proto-go#240</a></li>
<li>chore(deps): update module golang.org/x/net to v0.34.0 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/241">open-telemetry/opentelemetry-proto-go#241</a></li>
<li>fix(deps): update module google.golang.org/protobuf to v1.36.2 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/242">open-telemetry/opentelemetry-proto-go#242</a></li>
<li>fix(deps): update module go.opentelemetry.io/build-tools/multimod to v0.16.0 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/243">open-telemetry/opentelemetry-proto-go#243</a></li>
<li>fix(deps): update module google.golang.org/grpc to v1.69.4 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/244">open-telemetry/opentelemetry-proto-go#244</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/api digest to 1a7da9e by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/245">open-telemetry/opentelemetry-proto-go#245</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/rpc digest to 1a7da9e by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/246">open-telemetry/opentelemetry-proto-go#246</a></li>
<li>fix(deps): update module google.golang.org/protobuf to v1.36.3 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/247">open-telemetry/opentelemetry-proto-go#247</a></li>
<li>fix(deps): update module github.com/grpc-ecosystem/grpc-gateway/v2 to v2.26.0 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/249">open-telemetry/opentelemetry-proto-go#249</a></li>
<li>fix(deps): update module go.opentelemetry.io/build-tools/multimod to v0.17.0 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/253">open-telemetry/opentelemetry-proto-go#253</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/api digest to 138b5a5 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/251">open-telemetry/opentelemetry-proto-go#251</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/rpc digest to 138b5a5 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/252">open-telemetry/opentelemetry-proto-go#252</a></li>
<li>fix(deps): update module google.golang.org/grpc to v1.70.0 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/254">open-telemetry/opentelemetry-proto-go#254</a></li>
<li>fix(deps): update module google.golang.org/protobuf to v1.36.4 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/255">open-telemetry/opentelemetry-proto-go#255</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/api digest to 65684f5 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/256">open-telemetry/opentelemetry-proto-go#256</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/rpc digest to 65684f5 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/257">open-telemetry/opentelemetry-proto-go#257</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/rpc digest to 29210b9 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/259">open-telemetry/opentelemetry-proto-go#259</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/api digest to 29210b9 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/258">open-telemetry/opentelemetry-proto-go#258</a></li>
<li>chore(deps): update module golang.org/x/sys to v0.30.0 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/260">open-telemetry/opentelemetry-proto-go#260</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/api digest to 7023788 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/261">open-telemetry/opentelemetry-proto-go#261</a></li>
<li>chore(deps): update google.golang.org/genproto/googleapis/rpc digest to 7023788 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/262">open-telemetry/opentelemetry-proto-go#262</a></li>
<li>chore(deps): update module golang.org/x/text to v0.22.0 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/263">open-telemetry/opentelemetry-proto-go#263</a></li>
<li>fix(deps): update module go.opentelemetry.io/build-tools/multimod to v0.18.0 by <a href="https://github.com/renovate"><code>@​renovate</code></a> in <a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/pull/264">open-telemetry/opentelemetry-proto-go#264</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/ed3d8b947fc13152a45970f8397bbaded5b611e5"><code>ed3d8b9</code></a> Release v1.6.0 (<a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/issues/304">#304</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/54306df1fe704ab06f4c60a562d92082f23c638c"><code>54306df</code></a> fix(deps): update module go.opentelemetry.io/build-tools/multimod to v0.23.1 ...</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/757fdc74491e3ba5aeb59dcd54a117e8d5ee938d"><code>757fdc7</code></a> chore(deps): update otel/build-protobuf docker tag to v0.25.0 (<a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/issues/308">#308</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/d2c0ede96bdcdf49b5b8c1a124bca31022557a46"><code>d2c0ede</code></a> Use renovate-friendly def of Docker image (<a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/issues/305">#305</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/7c5443585a03b734b50de29a9da0b209fc121c38"><code>7c54435</code></a> fix(deps): update module go.opentelemetry.io/build-tools/multimod to v0.23.0 ...</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/225af11c623b784101e11e7899d741b1439582c0"><code>225af11</code></a> chore(deps): update google.golang.org/genproto/googleapis/rpc digest to 10db9...</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/0a64f5450e92e70ac78d285e3114f6c3e3bd0b6f"><code>0a64f54</code></a> chore(deps): update google.golang.org/genproto/googleapis/api digest to 10db9...</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/293531b5fec9f9dfcc5d2559dc3843141f2e2440"><code>293531b</code></a> chore(deps): update github/codeql-action action to v3.28.16 (<a href="https://redirect.github.com/open-telemetry/opentelemetry-proto-go/issues/298">#298</a>)</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/3ed1d3dcbc4742614ff4e4b36902a6baa51e1251"><code>3ed1d3d</code></a> chore(deps): update google.golang.org/genproto/googleapis/rpc digest to 7b384...</li>
<li><a href="https://github.com/open-telemetry/opentelemetry-proto-go/commit/9dd37fe2c2edc46fdc62372ecba49d6611cf4e18"><code>9dd37fe</code></a> chore(deps): update google.golang.org/genproto/googleapis/api digest to 7b384...</li>
<li>Additional commits viewable in <a href="https://github.com/open-telemetry/opentelemetry-proto-go/compare/v1.5.0...v1.6.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/net` from 0.39.0 to 0.40.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/net/commit/7d6e62ace5ed100018bd82d1967d2d98cff6fbae"><code>7d6e62a</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/net/commit/ea0c1d94f5e0c4b4c18b927e26e188ad8fadb38e"><code>ea0c1d9</code></a> internal/timeseries: use built-in max/min to simplify the code</li>
<li><a href="https://github.com/golang/net/commit/3e7a445bf42b2e561241ba03bf98fc320ea58814"><code>3e7a445</code></a> quic: skip packet numbers for optimistic ack defense</li>
<li><a href="https://github.com/golang/net/commit/3f563d3b0dee482b8cc70bae68346d9a6d4609a6"><code>3f563d3</code></a> quic: use an enum for sentPacket state</li>
<li><a href="https://github.com/golang/net/commit/a3b6e772dc0acbd9c55a9e62524a4c389bed0d69"><code>a3b6e77</code></a> quic: don't re-lose packets when discarding keys</li>
<li><a href="https://github.com/golang/net/commit/22500a668c8e49a00a2a8ef32accbaaa25f72565"><code>22500a6</code></a> quic: decode packet numbers &gt;255 in tests</li>
<li><a href="https://github.com/golang/net/commit/dd0b200aed506ae7891bd38fb47bacfd57b5a6e0"><code>dd0b200</code></a> quic: remove go1.21 build constraint</li>
<li>See full diff in <a href="https://github.com/golang/net/compare/v0.39.0...v0.40.0">compare view</a></li>
</ul>
</details>
<br />

Updates `google.golang.org/genproto/googleapis/api` from 0.0.0-20250218202821-56aae31c358a to 0.0.0-20250428153025-10db94c68c34
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/googleapis/go-genproto/commits">compare view</a></li>
</ul>
</details>
<br />

Updates `google.golang.org/genproto/googleapis/rpc` from 0.0.0-20250219182151-9fdb1cabc7b2 to 0.0.0-20250428153025-10db94c68c34
<details>
<summary>Commits</summary>
<ul>
<li>See full diff in <a href="https://github.com/googleapis/go-genproto/commits">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/net` from 0.39.0 to 0.40.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/net/commit/7d6e62ace5ed100018bd82d1967d2d98cff6fbae"><code>7d6e62a</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/net/commit/ea0c1d94f5e0c4b4c18b927e26e188ad8fadb38e"><code>ea0c1d9</code></a> internal/timeseries: use built-in max/min to simplify the code</li>
<li><a href="https://github.com/golang/net/commit/3e7a445bf42b2e561241ba03bf98fc320ea58814"><code>3e7a445</code></a> quic: skip packet numbers for optimistic ack defense</li>
<li><a href="https://github.com/golang/net/commit/3f563d3b0dee482b8cc70bae68346d9a6d4609a6"><code>3f563d3</code></a> quic: use an enum for sentPacket state</li>
<li><a href="https://github.com/golang/net/commit/a3b6e772dc0acbd9c55a9e62524a4c389bed0d69"><code>a3b6e77</code></a> quic: don't re-lose packets when discarding keys</li>
<li><a href="https://github.com/golang/net/commit/22500a668c8e49a00a2a8ef32accbaaa25f72565"><code>22500a6</code></a> quic: decode packet numbers &gt;255 in tests</li>
<li><a href="https://github.com/golang/net/commit/dd0b200aed506ae7891bd38fb47bacfd57b5a6e0"><code>dd0b200</code></a> quic: remove go1.21 build constraint</li>
<li>See full diff in <a href="https://github.com/golang/net/compare/v0.39.0...v0.40.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/net` from 0.39.0 to 0.40.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/net/commit/7d6e62ace5ed100018bd82d1967d2d98cff6fbae"><code>7d6e62a</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/net/commit/ea0c1d94f5e0c4b4c18b927e26e188ad8fadb38e"><code>ea0c1d9</code></a> internal/timeseries: use built-in max/min to simplify the code</li>
<li><a href="https://github.com/golang/net/commit/3e7a445bf42b2e561241ba03bf98fc320ea58814"><code>3e7a445</code></a> quic: skip packet numbers for optimistic ack defense</li>
<li><a href="https://github.com/golang/net/commit/3f563d3b0dee482b8cc70bae68346d9a6d4609a6"><code>3f563d3</code></a> quic: use an enum for sentPacket state</li>
<li><a href="https://github.com/golang/net/commit/a3b6e772dc0acbd9c55a9e62524a4c389bed0d69"><code>a3b6e77</code></a> quic: don't re-lose packets when discarding keys</li>
<li><a href="https://github.com/golang/net/commit/22500a668c8e49a00a2a8ef32accbaaa25f72565"><code>22500a6</code></a> quic: decode packet numbers &gt;255 in tests</li>
<li><a href="https://github.com/golang/net/commit/dd0b200aed506ae7891bd38fb47bacfd57b5a6e0"><code>dd0b200</code></a> quic: remove go1.21 build constraint</li>
<li>See full diff in <a href="https://github.com/golang/net/compare/v0.39.0...v0.40.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/net` from 0.39.0 to 0.40.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/net/commit/7d6e62ace5ed100018bd82d1967d2d98cff6fbae"><code>7d6e62a</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/net/commit/ea0c1d94f5e0c4b4c18b927e26e188ad8fadb38e"><code>ea0c1d9</code></a> internal/timeseries: use built-in max/min to simplify the code</li>
<li><a href="https://github.com/golang/net/commit/3e7a445bf42b2e561241ba03bf98fc320ea58814"><code>3e7a445</code></a> quic: skip packet numbers for optimistic ack defense</li>
<li><a href="https://github.com/golang/net/commit/3f563d3b0dee482b8cc70bae68346d9a6d4609a6"><code>3f563d3</code></a> quic: use an enum for sentPacket state</li>
<li><a href="https://github.com/golang/net/commit/a3b6e772dc0acbd9c55a9e62524a4c389bed0d69"><code>a3b6e77</code></a> quic: don't re-lose packets when discarding keys</li>
<li><a href="https://github.com/golang/net/commit/22500a668c8e49a00a2a8ef32accbaaa25f72565"><code>22500a6</code></a> quic: decode packet numbers &gt;255 in tests</li>
<li><a href="https://github.com/golang/net/commit/dd0b200aed506ae7891bd38fb47bacfd57b5a6e0"><code>dd0b200</code></a> quic: remove go1.21 build constraint</li>
<li>See full diff in <a href="https://github.com/golang/net/compare/v0.39.0...v0.40.0">compare view</a></li>
</ul>
</details>
<br />

Updates `github.com/valyala/fasthttp` from 1.61.0 to 1.62.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/valyala/fasthttp/releases">github.com/valyala/fasthttp's releases</a>.</em></p>
<blockquote>
<h2>v1.62.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Add support for streaming identity-encoded or unknown length response bodies by <a href="https://github.com/osxtest"><code>@​osxtest</code></a> in <a href="https://redirect.github.com/valyala/fasthttp/pull/2000">valyala/fasthttp#2000</a></li>
<li>feat: move user values to Request structure by <a href="https://github.com/mdenushev"><code>@​mdenushev</code></a> in <a href="https://redirect.github.com/valyala/fasthttp/pull/1999">valyala/fasthttp#1999</a></li>
<li>chore(deps): bump golangci/golangci-lint-action from 7 to 8 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/valyala/fasthttp/pull/2001">valyala/fasthttp#2001</a></li>
<li>chore(deps): bump golang.org/x/crypto from 0.37.0 to 0.38.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/valyala/fasthttp/pull/2002">valyala/fasthttp#2002</a></li>
<li>chore(deps): bump golang.org/x/net from 0.39.0 to 0.40.0 by <a href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a href="https://redirect.github.com/valyala/fasthttp/pull/2003">valyala/fasthttp#2003</a></li>
<li>modify <code>acceptConn</code> for <code>RIO</code> by <a href="https://github.com/wamshawn"><code>@​wamshawn</code></a> in <a href="https://redirect.github.com/valyala/fasthttp/pull/2005">valyala/fasthttp#2005</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/osxtest"><code>@​osxtest</code></a> made their first contribution in <a href="https://redirect.github.com/valyala/fasthttp/pull/2000">valyala/fasthttp#2000</a></li>
<li><a href="https://github.com/wamshawn"><code>@​wamshawn</code></a> made their first contribution in <a href="https://redirect.github.com/valyala/fasthttp/pull/2005">valyala/fasthttp#2005</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/valyala/fasthttp/compare/v1.61.0...v1.62.0">https://github.com/valyala/fasthttp/compare/v1.61.0...v1.62.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/valyala/fasthttp/commit/9e457ebd982fe77cce75b59667ff20d4c3af30b2"><code>9e457eb</code></a> mod acceptConn (<a href="https://redirect.github.com/valyala/fasthttp/issues/2005">#2005</a>)</li>
<li><a href="https://github.com/valyala/fasthttp/commit/69a68df4eb257570ffed33b85a8e6d523b07ed70"><code>69a68df</code></a> chore(deps): bump golang.org/x/net from 0.39.0 to 0.40.0 (<a href="https://redirect.github.com/valyala/fasthttp/issues/2003">#2003</a>)</li>
<li><a href="https://github.com/valyala/fasthttp/commit/83fbe80f9379db8388b4ee24a2eaab4674998b3f"><code>83fbe80</code></a> chore(deps): bump golang.org/x/crypto from 0.37.0 to 0.38.0 (<a href="https://redirect.github.com/valyala/fasthttp/issues/2002">#2002</a>)</li>
<li><a href="https://github.com/valyala/fasthttp/commit/51817a4eb67dabb67e0870efccb20caafe0a936d"><code>51817a4</code></a> chore(deps): bump golangci/golangci-lint-action from 7 to 8 (<a href="https://redirect.github.com/valyala/fasthttp/issues/2001">#2001</a>)</li>
<li><a href="https://github.com/valyala/fasthttp/commit/41a1449627b8ba0cbf30030ea41fc1ae4ca514f2"><code>41a1449</code></a> feat: move user values to Request structure (<a href="https://redirect.github.com/valyala/fasthttp/issues/1999">#1999</a>)</li>
<li><a href="https://github.com/valyala/fasthttp/commit/1345f42ede3f31b6fe6b42342256f338261bd9d5"><code>1345f42</code></a> Add support for streaming identity-encoded or unknown length response bodies ...</li>
<li>See full diff in <a href="https://github.com/valyala/fasthttp/compare/v1.61.0...v1.62.0">compare view</a></li>
</ul>
</details>
<br />

Updates `golang.org/x/net` from 0.39.0 to 0.40.0
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/net/commit/7d6e62ace5ed100018bd82d1967d2d98cff6fbae"><code>7d6e62a</code></a> go.mod: update golang.org/x dependencies</li>
<li><a href="https://github.com/golang/net/commit/ea0c1d94f5e0c4b4c18b927e26e188ad8fadb38e"><code>ea0c1d9</code></a> internal/timeseries: use built-in max/min to simplify the code</li>
<li><a href="https://github.com/golang/net/commit/3e7a445bf42b2e561241ba03bf98fc320ea58814"><code>3e7a445</code></a> quic: skip packet numbers for optimistic ack defense</li>
<li><a href="https://github.com/golang/net/commit/3f563d3b0dee482b8cc70bae68346d9a6d4609a6"><code>3f563d3</code></a> quic: use an enum for sentPacket state</li>
<li><a href="https://github.com/golang/net/commit/a3b6e772dc0acbd9c55a9e62524a4c389bed0d69"><code>a3b6e77</code></a> quic: don't re-lose packets when discarding keys</li>
<li><a href="https://github.com/golang/net/commit/22500a668c8e49a00a2a8ef32accbaaa25f72565"><code>22500a6</code></a> quic: decode packet numbers &gt;255 in tests</li>
<li><a href="https://github.com/golang/net/commit/dd0b200aed506ae7891bd38fb47bacfd57b5a6e0"><code>dd0b200</code></a> quic: remove go1.21 build constraint</li>
<li>See full diff in <a href="https://github.com/golang/net/compare/v0.39.0...v0.40.0">compare view</a></li>
</ul>
</details>
<br />

Updates `google.golang.org/protobuf` from 1.36.5 to 1.36.6

Updates `github.com/envoyproxy/gateway` from 1.3.2 to 1.3.3
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/envoyproxy/gateway/releases">github.com/envoyproxy/gateway's releases</a>.</em></p>
<blockquote>
<h2>v1.3.3</h2>
<h2>Release Announcement</h2>
<p>Check out the <a href="https://gateway.envoyproxy.io/news/releases/notes/v1.3.3/">v1.3.3 release announcement</a> to learn more about the release.</p>
<h2>Bug fixes</h2>
<ul>
<li>Fix issue where ReferenceGrant from SecurityPolicy to the referenced RemoteJWKS backend was not respected.</li>
<li>Fix HTTPRoute precedence by correctly considering header and query match types.</li>
<li>Fix to return an error if direct response size exceeds the limit.</li>
<li>Fix to avoid adding the TLS inspector filter to QUIC listeners.</li>
<li>Fix to continue processing remaining GatewayClasses after encountering an error.</li>
<li>Add validation for header values.</li>
</ul>
<h2>Other changes</h2>
<ul>
<li>Bumped envoy to v1.33.3.</li>
<li>Bumped ratelimit to 3e085e5b.</li>
</ul>
<h2>What's Changed</h2>
<ul>
<li>[release/v1.3] release v1.3.3 cherry-pick by <a href="https://github.com/guydc"><code>@​guydc</code></a> in <a href="https://redirect.github.com/envoyproxy/gateway/pull/5951">envoyproxy/gateway#5951</a></li>
<li>[release/v1.3] pin envoy and ratelimit by <a href="https://github.com/guydc"><code>@​guydc</code></a> in <a href="https://redirect.github.com/envoyproxy/gateway/pull/5968">envoyproxy/gateway#5968</a></li>
<li>[release/v1.3] Release version v1.3.3 by <a href="https://github.com/guydc"><code>@​guydc</code></a> in <a href="https://redirect.github.com/envoyproxy/gateway/pull/5970">envoyproxy/gateway#5970</a></li>
<li>[release/v1.3] bump cc action by <a href="https://github.com/guydc"><code>@​guydc</code></a> in <a href="https://redirect.github.com/envoyproxy/gateway/pull/5975">envoyproxy/gateway#5975</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/envoyproxy/gateway/compare/v1.3.2...v1.3.3">https://github.com/envoyproxy/gateway/compare/v1.3.2...v1.3.3</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/envoyproxy/gateway/commit/34c134d24462ebcbcc4b235539683193fd3af94d"><code>34c134d</code></a> [release/v1.3] bump cc action (<a href="https://redirect.github.com/envoyproxy/gateway/issues/5975">#5975</a>)</li>
<li><a href="https://github.com/envoyproxy/gateway/commit/4467040dc6ac7f0817d5b007cef8a9d917c3b01d"><code>4467040</code></a> [release/v1.3] Release version v1.3.3 (<a href="https://redirect.github.com/envoyproxy/gateway/issues/5970">#5970</a>)</li>
<li><a href="https://github.com/envoyproxy/gateway/commit/01e13824c5c539705729aa7c4dfeb89bc4527309"><code>01e1382</code></a> [release/v1.3] pin envoy and ratelimit (<a href="https://redirect.github.com/envoyproxy/gateway/issues/5968">#5968</a>)</li>
<li><a href="https://github.com/envoyproxy/gateway/commit/998995e03b4c30290522cff9e9045e30d4dd8d08"><code>998995e</code></a> [release/v1.3] release v1.3.3 cherry-pick (<a href="https://redirect.github.com/envoyproxy/gateway/issues/5951">#5951</a>)</li>
<li>See full diff in <a href="https://github.com/envoyproxy/gateway/compare/v1.3.2...v1.3.3">compare view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions


</details>

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/envoyproxy/gateway/pull/6016?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 70.45%. Comparing base [(`196b280`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/196b280d0753455d32f4901a041c68918b4afbed?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy) to head [(`a4bf5b0`)](https://app.codecov.io/gh/envoyproxy/gateway/commit/a4bf5b0796e82a519a4bc9cc065b2041c946eede?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main    #6016      +/-   ##
==========================================
+ Coverage   70.44%   70.45%   +0.01%     
==========================================
  Files         217      217              
  Lines       36016    36016              
==========================================
+ Hits        25370    25374       +4     
+ Misses       9140     9138       -2     
+ Partials     1506     1504       -2     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/envoyproxy/gateway/pull/6016?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=envoyproxy).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>

Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index b1b6b5e96..52af14f2b 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -41,11 +41,13 @@ updates:
           - "github.com*"
           - "go.opentelemetry.io*"
           - "golang*"
+          - "golang.org*"
           - "google*"
+          - "google.golang.org*"
           - "fortio.org*"
           - "gopkg.in*"
           - "helm.sh*"
-          - "gomodules.xyz"
+          - "gomodules.xyz*"
         exclude-patterns:
           # Exclude envoyproxy/go-control-plane, since it needs more work to update
           - "github.com/envoyproxy/go-control-plane*"
diff --git a/VERSION b/VERSION
index d5915d368..0d0c52f84 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-v1.4.0-rc.2
+v1.4.0
diff --git a/api/v1alpha1/ratelimit_types.go b/api/v1alpha1/ratelimit_types.go
index 21727bb05..d3cd36bca 100644
--- a/api/v1alpha1/ratelimit_types.go
+++ b/api/v1alpha1/ratelimit_types.go
@@ -49,19 +49,8 @@ type GlobalRateLimit struct {
 	// matches two rules, one rate limited and one not, the final decision will be
 	// to rate limit the request.
 	//
-	// +patchMergeKey:"name"
-	// +patchStrategy:"merge"
 	// +kubebuilder:validation:MaxItems=64
-	Rules []RateLimitRule `json:"rules" patchMergeKey:"name" patchStrategy:"merge"`
-
-	// Shared determines whether the rate limit rules apply across all the policy targets.
-	// If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
-	// Default: false.
-	//
-	// +optional
-	// +notImplementedHide
-	// +kubebuilder:default=false
-	Shared *bool `json:"shared,omitempty"`
+	Rules []RateLimitRule `json:"rules"`
 }
 
 // LocalRateLimit defines local rate limit configuration.
@@ -71,23 +60,15 @@ type LocalRateLimit struct {
 	// matches two rules, one with 10rps and one with 20rps, the final limit will
 	// be based on the rule with 10rps.
 	//
-	// +patchMergeKey:"name"
-	// +patchStrategy:"merge"
-	//
 	// +optional
 	// +kubebuilder:validation:MaxItems=16
 	// +kubebuilder:validation:XValidation:rule="self.all(foo, !has(foo.cost) || !has(foo.cost.response))", message="response cost is not supported for Local Rate Limits"
-	Rules []RateLimitRule `json:"rules" patchMergeKey:"name" patchStrategy:"merge"`
+	Rules []RateLimitRule `json:"rules"`
 }
 
 // RateLimitRule defines the semantics for matching attributes
 // from the incoming requests, and setting limits for them.
 type RateLimitRule struct {
-	// Name is the name of the rule. This is used to identify the rule
-	// in the Envoy configuration and as a unique identifier for merging.
-	//
-	// +optional
-	Name string `json:"name,omitempty"`
 	// ClientSelectors holds the list of select conditions to select
 	// specific clients using attributes from the traffic flow.
 	// All individual select conditions must hold True for this rule
@@ -118,6 +99,12 @@ type RateLimitRule struct {
 	//
 	// +optional
 	Cost *RateLimitCost `json:"cost,omitempty"`
+	// Shared determines whether this rate limit rule applies across all the policy targets.
+	// If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
+	// Default: false.
+	//
+	// +optional
+	Shared *bool `json:"shared,omitempty"`
 }
 
 type RateLimitCost struct {
diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go
index ed3f92b80..87c150497 100644
--- a/api/v1alpha1/zz_generated.deepcopy.go
+++ b/api/v1alpha1/zz_generated.deepcopy.go
@@ -2853,11 +2853,6 @@ func (in *GlobalRateLimit) DeepCopyInto(out *GlobalRateLimit) {
 			(*in)[i].DeepCopyInto(&(*out)[i])
 		}
 	}
-	if in.Shared != nil {
-		in, out := &in.Shared, &out.Shared
-		*out = new(bool)
-		**out = **in
-	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalRateLimit.
@@ -5306,6 +5301,11 @@ func (in *RateLimitRule) DeepCopyInto(out *RateLimitRule) {
 		*out = new(RateLimitCost)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.Shared != nil {
+		in, out := &in.Shared, &out.Shared
+		*out = new(bool)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitRule.
diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
index 66c01520e..4aeb42b0a 100644
--- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
+++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
@@ -948,23 +948,17 @@ spec:
                               - requests
                               - unit
                               type: object
-                            name:
+                            shared:
                               description: |-
-                                Name is the name of the rule. This is used to identify the rule
-                                in the Envoy configuration and as a unique identifier for merging.
-                              type: string
+                                Shared determines whether this rate limit rule applies across all the policy targets.
+                                If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
+                                Default: false.
+                              type: boolean
                           required:
                           - limit
                           type: object
                         maxItems: 64
                         type: array
-                      shared:
-                        default: false
-                        description: |-
-                          Shared determines whether the rate limit rules apply across all the policy targets.
-                          If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
-                          Default: false.
-                        type: boolean
                     required:
                     - rules
                     type: object
@@ -1203,11 +1197,12 @@ spec:
                               - requests
                               - unit
                               type: object
-                            name:
+                            shared:
                               description: |-
-                                Name is the name of the rule. This is used to identify the rule
-                                in the Envoy configuration and as a unique identifier for merging.
-                              type: string
+                                Shared determines whether this rate limit rule applies across all the policy targets.
+                                If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
+                                Default: false.
+                              type: boolean
                           required:
                           - limit
                           type: object
diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
index af436290d..2f79f196d 100644
--- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
+++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_backendtrafficpolicies.yaml
@@ -947,23 +947,17 @@ spec:
                               - requests
                               - unit
                               type: object
-                            name:
+                            shared:
                               description: |-
-                                Name is the name of the rule. This is used to identify the rule
-                                in the Envoy configuration and as a unique identifier for merging.
-                              type: string
+                                Shared determines whether this rate limit rule applies across all the policy targets.
+                                If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
+                                Default: false.
+                              type: boolean
                           required:
                           - limit
                           type: object
                         maxItems: 64
                         type: array
-                      shared:
-                        default: false
-                        description: |-
-                          Shared determines whether the rate limit rules apply across all the policy targets.
-                          If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
-                          Default: false.
-                        type: boolean
                     required:
                     - rules
                     type: object
@@ -1202,11 +1196,12 @@ spec:
                               - requests
                               - unit
                               type: object
-                            name:
+                            shared:
                               description: |-
-                                Name is the name of the rule. This is used to identify the rule
-                                in the Envoy configuration and as a unique identifier for merging.
-                              type: string
+                                Shared determines whether this rate limit rule applies across all the policy targets.
+                                If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
+                                Default: false.
+                              type: boolean
                           required:
                           - limit
                           type: object
diff --git a/examples/envoy-ext-auth/go.mod b/examples/envoy-ext-auth/go.mod
index 10d19daf3..80a169fb6 100644
--- a/examples/envoy-ext-auth/go.mod
+++ b/examples/envoy-ext-auth/go.mod
@@ -13,8 +13,8 @@ require (
 	github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
 	github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
 	github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
-	golang.org/x/net v0.39.0 // indirect
-	golang.org/x/sys v0.32.0 // indirect
-	golang.org/x/text v0.24.0 // indirect
+	golang.org/x/net v0.40.0 // indirect
+	golang.org/x/sys v0.33.0 // indirect
+	golang.org/x/text v0.25.0 // indirect
 	google.golang.org/protobuf v1.36.6 // indirect
 )
diff --git a/examples/envoy-ext-auth/go.sum b/examples/envoy-ext-auth/go.sum
index 57a3fc34b..1825a30fc 100644
--- a/examples/envoy-ext-auth/go.sum
+++ b/examples/envoy-ext-auth/go.sum
@@ -28,12 +28,12 @@ go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce
 go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
 go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
 go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
-golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
-golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
-golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
-golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
-golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
+golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
 google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
diff --git a/examples/extension-server/go.mod b/examples/extension-server/go.mod
index 8a396c325..346800b85 100644
--- a/examples/extension-server/go.mod
+++ b/examples/extension-server/go.mod
@@ -37,13 +37,13 @@ require (
 	github.com/x448/float16 v0.8.4 // indirect
 	github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
 	golang.org/x/mod v0.24.0 // indirect
-	golang.org/x/net v0.39.0 // indirect
-	golang.org/x/sync v0.13.0 // indirect
-	golang.org/x/sys v0.32.0 // indirect
-	golang.org/x/text v0.24.0 // indirect
-	golang.org/x/tools v0.31.0 // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 // indirect
+	golang.org/x/net v0.40.0 // indirect
+	golang.org/x/sync v0.14.0 // indirect
+	golang.org/x/sys v0.33.0 // indirect
+	golang.org/x/text v0.25.0 // indirect
+	golang.org/x/tools v0.32.0 // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
diff --git a/examples/extension-server/go.sum b/examples/extension-server/go.sum
index 44303e457..5e3ed754c 100644
--- a/examples/extension-server/go.sum
+++ b/examples/extension-server/go.sum
@@ -120,37 +120,37 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
-golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
-golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
+golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
-golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
-golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
+golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
-golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
+golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
+golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 h1:DMTIbak9GhdaSxEjvVzAeNZvyc03I61duqNbnm3SU0M=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
+google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 h1:0PeQib/pH3nB/5pEmFeVQJotzGohV0dq4Vcp09H5yhE=
+google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
 google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
 google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
 google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
diff --git a/examples/grpc-ext-proc/go.mod b/examples/grpc-ext-proc/go.mod
index b94b3afa9..a39b3cb3c 100644
--- a/examples/grpc-ext-proc/go.mod
+++ b/examples/grpc-ext-proc/go.mod
@@ -12,8 +12,8 @@ require (
 	github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect
 	github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
 	github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
-	golang.org/x/net v0.39.0 // indirect
-	golang.org/x/sys v0.32.0 // indirect
-	golang.org/x/text v0.24.0 // indirect
+	golang.org/x/net v0.40.0 // indirect
+	golang.org/x/sys v0.33.0 // indirect
+	golang.org/x/text v0.25.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
 )
diff --git a/examples/grpc-ext-proc/go.sum b/examples/grpc-ext-proc/go.sum
index 57a3fc34b..1825a30fc 100644
--- a/examples/grpc-ext-proc/go.sum
+++ b/examples/grpc-ext-proc/go.sum
@@ -28,12 +28,12 @@ go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce
 go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
 go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
 go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
-golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
-golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
-golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
-golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
-golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
+golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
 google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
diff --git a/examples/preserve-case-backend/go.mod b/examples/preserve-case-backend/go.mod
index d38359395..cd5f4f38f 100644
--- a/examples/preserve-case-backend/go.mod
+++ b/examples/preserve-case-backend/go.mod
@@ -2,7 +2,7 @@ module github.com/envoyproxy/gateway-preserve-case-backend
 
 go 1.24.2
 
-require github.com/valyala/fasthttp v1.61.0
+require github.com/valyala/fasthttp v1.62.0
 
 require (
 	github.com/andybalholm/brotli v1.1.1 // indirect
diff --git a/examples/preserve-case-backend/go.sum b/examples/preserve-case-backend/go.sum
index 328122500..a4f5738ca 100644
--- a/examples/preserve-case-backend/go.sum
+++ b/examples/preserve-case-backend/go.sum
@@ -4,7 +4,7 @@ github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zt
 github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.61.0 h1:VV08V0AfoRaFurP1EWKvQQdPTZHiUzaVoulX1aBDgzU=
-github.com/valyala/fasthttp v1.61.0/go.mod h1:wRIV/4cMwUPWnRcDno9hGnYZGh78QzODFfo1LTUhBog=
+github.com/valyala/fasthttp v1.62.0 h1:8dKRBX/y2rCzyc6903Zu1+3qN0H/d2MsxPPmVNamiH0=
+github.com/valyala/fasthttp v1.62.0/go.mod h1:FCINgr4GKdKqV8Q0xv8b+UxPV+H/O5nNFo3D+r54Htg=
 github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
 github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
diff --git a/examples/simple-extension-server/go.mod b/examples/simple-extension-server/go.mod
index 3939ecfae..226d0b9b4 100644
--- a/examples/simple-extension-server/go.mod
+++ b/examples/simple-extension-server/go.mod
@@ -3,7 +3,7 @@ module github.com/envoyproxy/gateway-simple-extension-server
 go 1.24.2
 
 require (
-	github.com/envoyproxy/gateway v1.3.2
+	github.com/envoyproxy/gateway v1.3.3
 	github.com/urfave/cli/v2 v2.27.6
 	google.golang.org/grpc v1.72.0
 )
@@ -17,10 +17,10 @@ require (
 	github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
 	github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
-	golang.org/x/net v0.39.0 // indirect
-	golang.org/x/sys v0.32.0 // indirect
-	golang.org/x/text v0.24.0 // indirect
+	golang.org/x/net v0.40.0 // indirect
+	golang.org/x/sys v0.33.0 // indirect
+	golang.org/x/text v0.25.0 // indirect
 	google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
-	google.golang.org/protobuf v1.36.5 // indirect
+	google.golang.org/protobuf v1.36.6 // indirect
 )
diff --git a/examples/simple-extension-server/go.sum b/examples/simple-extension-server/go.sum
index c66fc2a2b..9ce7c9c84 100644
--- a/examples/simple-extension-server/go.sum
+++ b/examples/simple-extension-server/go.sum
@@ -4,8 +4,8 @@ github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 h1:Om6kYQYDUk5wWbT0t0q
 github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
 github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
 github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
-github.com/envoyproxy/gateway v1.3.2 h1:JpCWRIQyVdLOtHEZ0AX/fB2jFL/u6zBKKXu56H16lyw=
-github.com/envoyproxy/gateway v1.3.2/go.mod h1:O8bWdOd8GNBGoxPomNnh5u19zpNYkXly3iz8KZTm0d4=
+github.com/envoyproxy/gateway v1.3.3 h1:b8LX1eH4vFpvaSEsU7uOnXGvQkMZ3ysQ3M9JNlwD6Wc=
+github.com/envoyproxy/gateway v1.3.3/go.mod h1:O8bWdOd8GNBGoxPomNnh5u19zpNYkXly3iz8KZTm0d4=
 github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
 github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
 github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
@@ -40,17 +40,17 @@ go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce
 go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
 go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k=
 go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
-golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
-golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
-golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
-golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
-golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
-golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
+golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
 google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
 google.golang.org/grpc v1.72.0 h1:S7UkcVa60b5AAQTaO6ZKamFp1zMZSU0fGDK2WZLbBnM=
 google.golang.org/grpc v1.72.0/go.mod h1:wH5Aktxcg25y1I3w7H69nHfXdOG3UiadoBtjh3izSDM=
-google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
-google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
+google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
diff --git a/go.mod b/go.mod
index b424f4806..ff07e4e3b 100644
--- a/go.mod
+++ b/go.mod
@@ -34,7 +34,7 @@ require (
 	github.com/google/cel-go v0.23.2
 	github.com/google/go-cmp v0.7.0
 	github.com/google/go-containerregistry v0.20.3
-	github.com/miekg/dns v1.1.65
+	github.com/miekg/dns v1.1.66
 	github.com/ohler55/ojg v1.26.4
 	github.com/pkg/errors v0.9.1
 	github.com/prometheus/client_golang v1.22.0
@@ -57,12 +57,12 @@ require (
 	go.opentelemetry.io/otel/metric v1.35.0
 	go.opentelemetry.io/otel/sdk v1.35.0
 	go.opentelemetry.io/otel/sdk/metric v1.35.0
-	go.opentelemetry.io/proto/otlp v1.5.0
+	go.opentelemetry.io/proto/otlp v1.6.0
 	go.uber.org/zap v1.27.0
 	golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8
-	golang.org/x/net v0.39.0
+	golang.org/x/net v0.40.0
 	gomodules.xyz/jsonpatch/v2 v2.4.0
-	google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a
+	google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34
 	google.golang.org/grpc v1.72.0
 	google.golang.org/grpc/security/advancedtls v1.0.0
 	google.golang.org/protobuf v1.36.6
@@ -276,7 +276,7 @@ require (
 	github.com/gosuri/uitable v0.0.4 // indirect
 	github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
 	github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
-	github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
+	github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/go-immutable-radix/v2 v2.1.0 // indirect
 	github.com/hashicorp/go-multierror v1.1.1 // indirect
@@ -479,19 +479,19 @@ require (
 	go.uber.org/mock v0.5.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/zap/exp v0.3.0 // indirect
-	golang.org/x/crypto v0.37.0 // indirect
+	golang.org/x/crypto v0.38.0 // indirect
 	golang.org/x/crypto/x509roots/fallback v0.0.0-20250406160420-959f8f3db0fb // indirect
 	golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect
 	golang.org/x/mod v0.24.0 // indirect
 	golang.org/x/oauth2 v0.28.0 // indirect
-	golang.org/x/sync v0.13.0 // indirect
-	golang.org/x/sys v0.32.0 // indirect
-	golang.org/x/term v0.31.1-0.20250421193057-a809085bff59 // indirect
-	golang.org/x/text v0.24.0 // indirect
+	golang.org/x/sync v0.14.0 // indirect
+	golang.org/x/sys v0.33.0 // indirect
+	golang.org/x/term v0.32.0 // indirect
+	golang.org/x/text v0.25.0 // indirect
 	golang.org/x/time v0.10.0 // indirect
-	golang.org/x/tools v0.31.0 // indirect
+	golang.org/x/tools v0.32.0 // indirect
 	golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 // indirect
 	google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 // indirect
 	gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect
 	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
diff --git a/go.sum b/go.sum
index 315d567f9..1242801d9 100644
--- a/go.sum
+++ b/go.sum
@@ -714,8 +714,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t
 github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
 github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -908,8 +908,8 @@ github.com/mgechev/revive v1.7.0 h1:JyeQ4yO5K8aZhIKf5rec56u0376h8AlKNQEmjfkjKlY=
 github.com/mgechev/revive v1.7.0/go.mod h1:qZnwcNhoguE58dfi96IJeSTPeZQejNeoMQLUZGi4SW4=
 github.com/microsoft/go-mssqldb v1.8.0 h1:7cyZ/AT7ycDsEoWPIXibd+aVKFtteUNhDGf3aobP+tw=
 github.com/microsoft/go-mssqldb v1.8.0/go.mod h1:6znkekS3T2vp0waiMhen4GPU1BiAsrP+iXHcE7a7rFo=
-github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc=
-github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck=
+github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE=
+github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE=
 github.com/mistifyio/go-zfs/v3 v3.0.1 h1:YaoXgBePoMA12+S1u/ddkv+QqxcfiZK4prI6HPnkFiU=
 github.com/mistifyio/go-zfs/v3 v3.0.1/go.mod h1:CzVgeB0RvF2EGzQnytKVvVSDwmKJXxkOTUGbNrTja/k=
 github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
@@ -1427,8 +1427,8 @@ go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5J
 go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
 go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
 go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
-go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
-go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
+go.opentelemetry.io/proto/otlp v1.6.0 h1:jQjP+AQyTf+Fe7OKj/MfkDrmK4MNVtw2NpXsf9fefDI=
+go.opentelemetry.io/proto/otlp v1.6.0/go.mod h1:cicgGehlFuNdgZkcALOCh3VE6K/u2tAjzlRhDwmVpZc=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
@@ -1458,8 +1458,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
-golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
-golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
+golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
+golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
 golang.org/x/crypto/x509roots/fallback v0.0.0-20250406160420-959f8f3db0fb h1:Iu0p/klM0SM7atONioa/bPhLS7cjhnip99x1OIGibwg=
 golang.org/x/crypto/x509roots/fallback v0.0.0-20250406160420-959f8f3db0fb/go.mod h1:lxN5T34bK4Z/i6cMaU7frUU57VkDXFD4Kamfl/cp9oU=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1520,8 +1520,8 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
-golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
-golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
+golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
+golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1540,8 +1540,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
 golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
-golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
-golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
+golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1594,8 +1594,8 @@ golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
-golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
@@ -1604,8 +1604,8 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
-golang.org/x/term v0.31.1-0.20250421193057-a809085bff59 h1:VvEs4+4zlvlqhfwqiC06eDyr3q44VP9bioP96d7Vtyo=
-golang.org/x/term v0.31.1-0.20250421193057-a809085bff59/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw=
+golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
+golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
 golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1618,8 +1618,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
-golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
+golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
+golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1657,8 +1657,8 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
 golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
 golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
-golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
-golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
+golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
+golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1679,10 +1679,10 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
 google.golang.org/genproto v0.0.0-20241118233622-e639e219e697 h1:ToEetK57OidYuqD4Q5w+vfEnPvPpuTwedCNVohYJfNk=
 google.golang.org/genproto v0.0.0-20241118233622-e639e219e697/go.mod h1:JJrvXBWRZaFMxBufik1a4RpFw4HhgVtBBWQeQgUj2cc=
-google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
-google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2 h1:DMTIbak9GhdaSxEjvVzAeNZvyc03I61duqNbnm3SU0M=
-google.golang.org/genproto/googleapis/rpc v0.0.0-20250219182151-9fdb1cabc7b2/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
+google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34 h1:0PeQib/pH3nB/5pEmFeVQJotzGohV0dq4Vcp09H5yhE=
+google.golang.org/genproto/googleapis/api v0.0.0-20250428153025-10db94c68c34/go.mod h1:0awUlEkap+Pb1UMeJwJQQAdJQrt3moU7J2moTy69irI=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34 h1:h6p3mQqrmT1XkHVTfzLdNz1u7IhINeZkz67/xTbOuWs=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20250428153025-10db94c68c34/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
diff --git a/internal/gatewayapi/backendtrafficpolicy.go b/internal/gatewayapi/backendtrafficpolicy.go
index 75fcd286a..b670a2ea2 100644
--- a/internal/gatewayapi/backendtrafficpolicy.go
+++ b/internal/gatewayapi/backendtrafficpolicy.go
@@ -429,13 +429,33 @@ func (t *Translator) translateBackendTrafficPolicyForRouteWithMerge(
 	if err != nil {
 		return fmt.Errorf("error merging policies: %w", err)
 	}
+
+	// Build traffic features from the merged policy
 	tf, errs := t.buildTrafficFeatures(mergedPolicy, resources)
 	if tf == nil {
 		// should not happen
 		return nil
 	}
 
-	// Apply IR to relevant gateway routes
+	// Since GlobalRateLimit merge relies on IR auto-generated key: (<policy-ns>/<policy-name>/rule/<rule-index>)
+	// We can't simply merge the BTP's using utils.Merge() we need to specifically merge the GlobalRateLimit.Rules using IR fields.
+	// Since ir.TrafficFeatures is not a built-in Kubernetes API object with defined merging strategies and it does not support a deep merge (for lists/maps).
+	if policy.Spec.RateLimit != nil && gwPolicy.Spec.RateLimit != nil {
+		tfGW, _ := t.buildTrafficFeatures(gwPolicy, resources)
+		tfRoute, _ := t.buildTrafficFeatures(policy, resources)
+
+		if tfGW != nil && tfRoute != nil &&
+			tfGW.RateLimit != nil && tfRoute.RateLimit != nil {
+
+			mergedRL, err := utils.MergeRL(tfGW.RateLimit, tfRoute.RateLimit, *policy.Spec.MergeType)
+			if err != nil {
+				return fmt.Errorf("error merging rate limits: %w", err)
+			}
+			// Replace the rate limit in the merged features if successful
+			tf.RateLimit = mergedRL
+		}
+	}
+
 	x, ok := xdsIR[t.IRKey(gatewayNN)]
 	if !ok {
 		// should not happen.
@@ -489,7 +509,6 @@ func applyTrafficFeatureToRoute(route RouteContext,
 				}
 
 				r.Traffic = tf.DeepCopy()
-				r.Traffic.Name = irTrafficName(policy)
 
 				if localTo, err := buildClusterSettingsTimeout(policy.Spec.ClusterSettings); err == nil {
 					r.Traffic.Timeout = localTo
@@ -695,7 +714,6 @@ func (t *Translator) translateBackendTrafficPolicyForGateway(
 			}
 
 			r.Traffic = tf.DeepCopy()
-			r.Traffic.Name = irTrafficName(policy)
 
 			// Update the Host field in HealthCheck, now that we have access to the Route Hostname.
 			r.Traffic.HealthCheck.SetHTTPHostIfAbsent(r.Hostname)
@@ -769,7 +787,7 @@ func (t *Translator) buildLocalRateLimit(policy *egv1a1.BackendTrafficPolicy) (*
 	var err error
 	var irRule *ir.RateLimitRule
 	irRules := make([]*ir.RateLimitRule, 0)
-	for _, rule := range local.Rules {
+	for i, rule := range local.Rules {
 		// We don't process the rule without clientSelectors here because it's
 		// previously used as the default route-level limit.
 		if len(rule.ClientSelectors) == 0 {
@@ -780,6 +798,8 @@ func (t *Translator) buildLocalRateLimit(policy *egv1a1.BackendTrafficPolicy) (*
 		if err != nil {
 			return nil, err
 		}
+		// Set the Name field as <policy-ns>/<policy-name>/rule/<rule-index>
+		irRule.Name = irRuleName(policy.Namespace, policy.Name, i)
 		irRules = append(irRules, irRule)
 	}
 
@@ -804,8 +824,7 @@ func (t *Translator) buildGlobalRateLimit(policy *egv1a1.BackendTrafficPolicy) (
 	global := policy.Spec.RateLimit.Global
 	rateLimit := &ir.RateLimit{
 		Global: &ir.GlobalRateLimit{
-			Rules:  make([]*ir.RateLimitRule, len(global.Rules)),
-			Shared: global.Shared,
+			Rules: make([]*ir.RateLimitRule, len(global.Rules)),
 		},
 	}
 
@@ -816,6 +835,8 @@ func (t *Translator) buildGlobalRateLimit(policy *egv1a1.BackendTrafficPolicy) (
 		if err != nil {
 			return nil, err
 		}
+		// Set the Name field as <policy-ns>/<policy-name>/rule/<rule-index>
+		irRules[i].Name = irRuleName(policy.Namespace, policy.Name, i)
 	}
 
 	return rateLimit, nil
@@ -828,6 +849,7 @@ func buildRateLimitRule(rule egv1a1.RateLimitRule) (*ir.RateLimitRule, error) {
 			Unit:     ir.RateLimitUnit(rule.Limit.Unit),
 		},
 		HeaderMatches: make([]*ir.StringMatch, 0),
+		Shared:        rule.Shared,
 	}
 
 	for _, match := range rule.ClientSelectors {
diff --git a/internal/gatewayapi/helpers.go b/internal/gatewayapi/helpers.go
index 20d9a5663..81cf59f3f 100644
--- a/internal/gatewayapi/helpers.go
+++ b/internal/gatewayapi/helpers.go
@@ -408,6 +408,10 @@ func irDestinationSettingName(destName string, backendIdx int) string {
 	return fmt.Sprintf("%s/backend/%d", destName, backendIdx)
 }
 
+func irRuleName(policyNamespace, policyName string, ruleIndex int) string {
+	return fmt.Sprintf("%s/%s/rule/%d", policyNamespace, policyName, ruleIndex)
+}
+
 // irTLSConfigs produces a defaulted IR TLSConfig
 func irTLSConfigs(tlsSecrets ...*corev1.Secret) *ir.TLSConfig {
 	if len(tlsSecrets) == 0 {
@@ -450,11 +454,6 @@ func irTLSCACertName(namespace, name string) string {
 	return fmt.Sprintf("%s/%s/%s", namespace, name, caCertKey)
 }
 
-// Helper function to format the policy name and namespace
-func irTrafficName(policy *egv1a1.BackendTrafficPolicy) string {
-	return fmt.Sprintf("%s/%s", policy.Namespace, policy.Name)
-}
-
 func IsMergeGatewaysEnabled(resources *resource.Resources) bool {
 	return resources.EnvoyProxyForGatewayClass != nil && resources.EnvoyProxyForGatewayClass.Spec.MergeGateways != nil && *resources.EnvoyProxyForGatewayClass.Spec.MergeGateways
 }
diff --git a/internal/ir/xds.go b/internal/ir/xds.go
index 777e33eb9..30bd1d1fc 100644
--- a/internal/ir/xds.go
+++ b/internal/ir/xds.go
@@ -835,8 +835,6 @@ type Compression struct {
 // TrafficFeatures holds the information associated with the Backend Traffic Policy.
 // +k8s:deepcopy-gen=true
 type TrafficFeatures struct {
-	// Name of the backend traffic policy and namespace
-	Name string `json:"name,omitempty"`
 	// RateLimit defines the more specific match conditions as well as limits for ratelimiting
 	// the requests on this route.
 	RateLimit *RateLimit `json:"rateLimit,omitempty" yaml:"rateLimit,omitempty"`
@@ -2093,16 +2091,7 @@ type GlobalRateLimit struct {
 	// TODO zhaohuabing: add default values for Global rate limiting.
 
 	// Rules for rate limiting.
-	Rules []*RateLimitRule `json:"rules,omitempty" yaml:"rules,omitempty"`
-
-	// Shared determines whether this rate limit rule applies globally across the gateway, or xRoute(s).
-	// If set to true, the rule is treated as a common bucket and is shared across all routes under the backend traffic policy.
-	// Must have targetRef set to Gateway or xRoute(s).
-	// Default: false.
-	//
-	// +optional
-	// +kubebuilder:default=false
-	Shared *bool `json:"shared,omitempty" yaml:"shared,omitempty"`
+	Rules []*RateLimitRule `json:"rules,omitempty" yaml:"rules,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
 }
 
 // LocalRateLimit holds the local rate limiting configuration.
@@ -2113,7 +2102,7 @@ type LocalRateLimit struct {
 	Default RateLimitValue `json:"default,omitempty" yaml:"default,omitempty"`
 
 	// Rules for rate limiting.
-	Rules []*RateLimitRule `json:"rules,omitempty" yaml:"rules,omitempty"`
+	Rules []*RateLimitRule `json:"rules,omitempty" yaml:"rules,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
 }
 
 // RateLimitRule holds the match and limit configuration for ratelimiting.
@@ -2129,6 +2118,15 @@ type RateLimitRule struct {
 	RequestCost *RateLimitCost `json:"requestCost,omitempty" yaml:"requestCost,omitempty"`
 	// ResponseCost specifies the cost of the response.
 	ResponseCost *RateLimitCost `json:"responseCost,omitempty" yaml:"responseCost,omitempty"`
+	// Shared determines whether this rate limit rule applies globally across the gateway, or xRoute(s).
+	// If set to true, the rule is treated as a common bucket and is shared across all routes under the backend traffic policy.
+	// Must have targetRef set to Gateway or xRoute(s).
+	// Default: false.
+	//
+	// +optional
+	Shared *bool `json:"shared,omitempty" yaml:"shared,omitempty"`
+	// Name is a unique identifier for this rule, set as <policy-ns>/<policy-name>/rule/<rule-index>.
+	Name string `json:"name,omitempty" yaml:"name,omitempty"`
 }
 
 // RateLimitCost specifies the cost of the request or response.
diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go
index 5b27f1e48..eb5f63edb 100644
--- a/internal/ir/zz_generated.deepcopy.go
+++ b/internal/ir/zz_generated.deepcopy.go
@@ -1306,11 +1306,6 @@ func (in *GlobalRateLimit) DeepCopyInto(out *GlobalRateLimit) {
 			}
 		}
 	}
-	if in.Shared != nil {
-		in, out := &in.Shared, &out.Shared
-		*out = new(bool)
-		**out = **in
-	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalRateLimit.
@@ -2753,6 +2748,11 @@ func (in *RateLimitRule) DeepCopyInto(out *RateLimitRule) {
 		*out = new(RateLimitCost)
 		(*in).DeepCopyInto(*out)
 	}
+	if in.Shared != nil {
+		in, out := &in.Shared, &out.Shared
+		*out = new(bool)
+		**out = **in
+	}
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RateLimitRule.
diff --git a/internal/utils/merge.go b/internal/utils/merge.go
index 337147ed0..2c0223090 100644
--- a/internal/utils/merge.go
+++ b/internal/utils/merge.go
@@ -14,6 +14,7 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
+	"github.com/envoyproxy/gateway/internal/ir"
 )
 
 func MergeWithPatch[T client.Object](original T, patch *egv1a1.KubernetesPatchSpec) (T, error) {
@@ -77,3 +78,52 @@ func Merge[T client.Object](original, patch T, mergeType egv1a1.MergeType) (T, e
 	}
 	return mergeInternal(original, patchJSON, mergeType)
 }
+
+func mergeRLInternal[T *ir.RateLimit](original T, patchJSON []byte, mergeType egv1a1.MergeType) (T, error) {
+	var (
+		patchedJSON  []byte
+		originalJSON []byte
+		err          error
+		empty        T
+	)
+
+	originalJSON, err = json.Marshal(original)
+	if err != nil {
+		return empty, fmt.Errorf("error marshaling original service: %w", err)
+	}
+	switch mergeType {
+	case egv1a1.StrategicMerge:
+		patchedJSON, err = strategicpatch.StrategicMergePatch(originalJSON, patchJSON, empty)
+		if err != nil {
+			return empty, fmt.Errorf("error during strategic merge: %w", err)
+		}
+	case egv1a1.JSONMerge:
+		patchedJSON, err = jsonpatch.MergePatch(originalJSON, patchJSON)
+		if err != nil {
+			return empty, fmt.Errorf("error during JSON merge: %w", err)
+		}
+	default:
+		return empty, fmt.Errorf("unsupported merge type: %v", mergeType)
+	}
+
+	res := new(T)
+	if err = json.Unmarshal(patchedJSON, res); err != nil {
+		return empty, fmt.Errorf("error unmarshaling patched service: %w", err)
+	}
+
+	return *res, nil
+}
+
+func MergeRL[T *ir.RateLimit](original, patch T, mergeType egv1a1.MergeType) (T, error) {
+	var (
+		patchJSON []byte
+		err       error
+		empty     T
+	)
+
+	patchJSON, err = json.Marshal(patch)
+	if err != nil {
+		return empty, fmt.Errorf("error marshaling original service: %w", err)
+	}
+	return mergeRLInternal(original, patchJSON, mergeType)
+}
diff --git a/internal/xds/translator/ratelimit.go b/internal/xds/translator/ratelimit.go
index 03b01298d..e2d8ff8f7 100644
--- a/internal/xds/translator/ratelimit.go
+++ b/internal/xds/translator/ratelimit.go
@@ -63,15 +63,6 @@ func (t *Translator) patchHCMWithRateLimit(mgr *hcmv3.HttpConnectionManager, irL
 	}
 }
 
-// routeContainsGlobalRateLimit checks if a route has global rate limit configuration.
-// Returns false if any required component is nil.
-func routeContainsGlobalRateLimit(irRoute *ir.HTTPRoute) bool {
-	return irRoute != nil &&
-		irRoute.Traffic != nil &&
-		irRoute.Traffic.RateLimit != nil &&
-		irRoute.Traffic.RateLimit.Global != nil
-}
-
 // isRateLimitPresent returns true if rate limit config exists for the listener.
 func (t *Translator) isRateLimitPresent(irListener *ir.HTTPListener) bool {
 	// Return false if global ratelimiting is disabled.
@@ -80,7 +71,7 @@ func (t *Translator) isRateLimitPresent(irListener *ir.HTTPListener) bool {
 	}
 	// Return true if rate limit config exists.
 	for _, route := range irListener.Routes {
-		if routeContainsGlobalRateLimit(route) {
+		if isValidGlobalRateLimit(route) {
 			return true
 		}
 	}
@@ -88,42 +79,52 @@ func (t *Translator) isRateLimitPresent(irListener *ir.HTTPListener) bool {
 }
 
 // buildRateLimitFilter constructs a list of HTTP filters for rate limiting based on the provided HTTP listener configuration.
-// It creates at most one filter per domain to avoid duplicates.
+// It creates separate filters for shared and non-shared rate limits.
 func (t *Translator) buildRateLimitFilter(irListener *ir.HTTPListener) []*hcmv3.HttpFilter {
 	if irListener == nil || irListener.Routes == nil {
 		return nil
 	}
 
-	var filters []*hcmv3.HttpFilter
-	// Map to track which domains we've already created filters for, prevents creating duplicate filters for the same domain
-	processedDomains := make(map[string]bool)
+	filters := []*hcmv3.HttpFilter{}
+	created := make(map[string]bool)
 
-	// Iterate over each route in the listener to create rate limit filters for shared rate limits.
 	for _, route := range irListener.Routes {
-		if !routeContainsGlobalRateLimit(route) {
+		if !isValidGlobalRateLimit(route) {
 			continue
 		}
 
-		var domain string
-		filterName := getRateLimitFilterName(route)
-		if isSharedRateLimit(route) {
-			// For shared rate limits, use the domain derived from the traffic policy
-			domain = getDomainName(route)
-		} else {
-			// For non-shared rate limits, use the listener domain
-			domain = irListener.Name
+		hasShared, hasNonShared := false, false
+		var sharedRuleName string
+
+		for _, rule := range route.Traffic.RateLimit.Global.Rules {
+			if isRuleShared(rule) {
+				hasShared = true
+				sharedRuleName = stripRuleIndexSuffix(rule.Name)
+			} else {
+				hasNonShared = true
+			}
 		}
 
-		// Skip if we've already created a filter for this domain
-		if processedDomains[domain] {
-			continue
+		if hasShared {
+			sharedDomain := sharedRuleName
+			if !created[sharedDomain] {
+				filterName := fmt.Sprintf("%s/%s", egv1a1.EnvoyFilterRateLimit.String(), sharedRuleName)
+				if filter := createRateLimitFilter(t, irListener, sharedDomain, filterName); filter != nil {
+					filters = append(filters, filter)
+				}
+				created[sharedDomain] = true
+			}
 		}
-		processedDomains[domain] = true
 
-		// Create a filter for this domain
-		filter := createRateLimitFilter(t, irListener, domain, filterName)
-		if filter != nil {
-			filters = append(filters, filter)
+		if hasNonShared {
+			nonSharedDomain := irListener.Name
+			if !created[nonSharedDomain] {
+				filterName := egv1a1.EnvoyFilterRateLimit.String()
+				if filter := createRateLimitFilter(t, irListener, nonSharedDomain, filterName); filter != nil {
+					filters = append(filters, filter)
+				}
+				created[nonSharedDomain] = true
+			}
 		}
 	}
 
@@ -184,7 +185,7 @@ func createRateLimitFilter(t *Translator, irListener *ir.HTTPListener, domain, f
 func patchRouteWithRateLimit(route *routev3.Route, irRoute *ir.HTTPRoute) error { //nolint:unparam
 	// Return early if no rate limit config exists.
 	xdsRouteAction := route.GetRoute()
-	if !routeContainsGlobalRateLimit(irRoute) || xdsRouteAction == nil {
+	if !isValidGlobalRateLimit(irRoute) || xdsRouteAction == nil {
 		return nil
 	}
 	rateLimits, costSpecified := buildRouteRateLimits(irRoute)
@@ -223,42 +224,47 @@ func patchRouteWithRateLimitOnTypedFilterConfig(route *routev3.Route, rateLimits
 
 // buildRouteRateLimits constructs rate limit actions for a given route based on the global rate limit configuration.
 func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit, costSpecified bool) {
-	descriptorPrefix := route.Name
 	// Ensure route has rate limit config
-	if !routeContainsGlobalRateLimit(route) {
+	if !isValidGlobalRateLimit(route) {
 		return nil, false
 	}
 
-	// Determine if the rate limit is shared across multiple routes.
+	// Get the global rate limit configuration
 	global := route.Traffic.RateLimit.Global
-	isShared := isSharedRateLimit(route)
-
-	// Set the descriptor key based on whether the rate limit is shared.
-	var descriptorKey, descriptorValue string
-	if isShared {
-		// For shared rate limits, use BTP name as key and namespace as value
-		descriptorKey = route.Traffic.Name
-		descriptorValue = route.Traffic.Name
-	} else {
-		// For non-shared rate limits, include the route name in the descriptor
-		descriptorKey = getRouteDescriptor(descriptorPrefix)
-		descriptorValue = descriptorKey
-	}
-
-	// Create a generic key action for the route descriptor.
-	routeDescriptor := &routev3.RateLimit_Action{
-		ActionSpecifier: &routev3.RateLimit_Action_GenericKey_{
-			GenericKey: &routev3.RateLimit_Action_GenericKey{
-				DescriptorKey:   descriptorKey,
-				DescriptorValue: descriptorValue,
-			},
-		},
-	}
 
 	// Iterate over each rule in the global rate limit configuration.
 	for rIdx, rule := range global.Rules {
-		// Initialize a list of rate limit actions for the current rule.
-		rlActions := []*routev3.RateLimit_Action{routeDescriptor}
+		// Create a list of rate limit actions for the current rule.
+		var rlActions []*routev3.RateLimit_Action
+
+		// Create the route descriptor using the rule's shared attribute
+		var descriptorKey, descriptorValue string
+		if isRuleShared(rule) {
+			// For shared rule, use full rule name
+			descriptorKey = rule.Name
+			descriptorValue = rule.Name
+		} else {
+			// For non-shared rule, use route name in descriptor
+			descriptorKey = getRouteDescriptor(route.Name)
+			descriptorValue = descriptorKey
+		}
+
+		// Create a generic key action for the route descriptor.
+		routeDescriptor := &routev3.RateLimit_Action{
+			ActionSpecifier: &routev3.RateLimit_Action_GenericKey_{
+				GenericKey: &routev3.RateLimit_Action_GenericKey{
+					DescriptorKey:   descriptorKey,
+					DescriptorValue: descriptorValue,
+				},
+			},
+		}
+
+		// Add the generic key action
+		rlActions = append(rlActions, routeDescriptor)
+
+		// Calculate the domain-specific rule index (0-based for each domain)
+		ruleIsShared := isRuleShared(rule)
+		domainRuleIdx := getDomainRuleIndex(global.Rules, rIdx, ruleIsShared)
 
 		// Process each header match in the rule.
 		for mIdx, match := range rule.HeaderMatches {
@@ -266,7 +272,7 @@ func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit,
 
 			// Handle distinct matches by setting up request header actions.
 			if match.Distinct {
-				descriptorKey := getRouteRuleDescriptor(rIdx, mIdx)
+				descriptorKey := getRouteRuleDescriptor(domainRuleIdx, mIdx)
 				action = &routev3.RateLimit_Action{
 					ActionSpecifier: &routev3.RateLimit_Action_RequestHeaders_{
 						RequestHeaders: &routev3.RateLimit_Action_RequestHeaders{
@@ -277,8 +283,8 @@ func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit,
 				}
 			} else {
 				// Handle non-distinct matches by setting up header value match actions.
-				descriptorKey := getRouteRuleDescriptor(rIdx, mIdx)
-				descriptorVal := getRouteRuleDescriptor(rIdx, mIdx)
+				descriptorKey := getRouteRuleDescriptor(domainRuleIdx, mIdx)
+				descriptorVal := getRouteRuleDescriptor(domainRuleIdx, mIdx)
 				headerMatcher := &routev3.HeaderMatcher{
 					Name: match.Name,
 					HeaderMatchSpecifier: &routev3.HeaderMatcher_StringMatch{
@@ -358,8 +364,8 @@ func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit,
 			action := &routev3.RateLimit_Action{
 				ActionSpecifier: &routev3.RateLimit_Action_GenericKey_{
 					GenericKey: &routev3.RateLimit_Action_GenericKey{
-						DescriptorKey:   getRouteRuleDescriptor(rIdx, -1),
-						DescriptorValue: getRouteRuleDescriptor(rIdx, -1),
+						DescriptorKey:   getRouteRuleDescriptor(domainRuleIdx, -1),
+						DescriptorValue: getRouteRuleDescriptor(domainRuleIdx, -1),
 					},
 				},
 			}
@@ -368,6 +374,7 @@ func buildRouteRateLimits(route *ir.HTTPRoute) (rateLimits []*routev3.RateLimit,
 
 		// Create a rate limit object for the current rule.
 		rateLimit := &routev3.RateLimit{Actions: rlActions}
+
 		if c := rule.RequestCost; c != nil {
 			// Set the hits addend for the request cost if specified.
 			rateLimit.HitsAddend = rateLimitCostToHitsAddend(c)
@@ -423,43 +430,38 @@ func GetRateLimitServiceConfigStr(pbCfg *rlsconfv3.RateLimitConfig) (string, err
 // It returns a list of unique configurations, one for each domain needed across all listeners.
 // For shared rate limits, it ensures we only process each shared domain once to improve efficiency.
 func BuildRateLimitServiceConfig(irListeners []*ir.HTTPListener) []*rlsconfv3.RateLimitConfig {
-	// Map to store descriptors for each domain
-	domainDescriptors := make(map[string][]*rlsconfv3.RateLimitDescriptor)
-	// Map to track which domains we've already created filters for, prevents creating duplicate filters for the same domain
-	processedSharedDomains := make(map[string]bool)
+	// Map to store rate limit descriptors by domain name
+	domainDesc := make(map[string][]*rlsconfv3.RateLimitDescriptor)
 
 	// Process each listener
 	for _, irListener := range irListeners {
-		// Process each route to build descriptors
+		// Process each route in the listener
 		for _, route := range irListener.Routes {
-			if !routeContainsGlobalRateLimit(route) {
+			// Skip routes without valid global rate limit configuration
+			if !isValidGlobalRateLimit(route) {
 				continue
 			}
 
-			domain := irListener.Name
-			if isSharedRateLimit(route) {
-				domain = getDomainName(route)
-
-				// Skip if we've already processed this shared domain
-				if processedSharedDomains[domain] {
-					continue
-				}
-				processedSharedDomains[domain] = true
-			}
+			// Build all descriptors for this route in a single pass to maintain consistent indices
+			descriptors := buildRateLimitServiceDescriptors(route)
 
-			// Get route rule descriptors within each route
-			serviceDescriptors := buildRateLimitServiceDescriptors(route)
-			if len(serviceDescriptors) == 0 {
+			// Skip if no descriptors were created
+			if len(descriptors) == 0 {
 				continue
 			}
 
-			// Add the rate limit descriptor (handles both shared and non-shared)
-			addRateLimitDescriptor(route, serviceDescriptors, domain, domainDescriptors)
+			// Process shared rules - add to traffic policy domain
+			sharedDomain := getDomainSharedName(route)
+			addRateLimitDescriptor(route, descriptors, sharedDomain, domainDesc, true)
+
+			// Process non-shared rules - add to listener-specific domain
+			listenerDomain := irListener.Name
+			addRateLimitDescriptor(route, descriptors, listenerDomain, domainDesc, false)
 		}
 	}
 
-	configs := createRateLimitConfigs(domainDescriptors)
-	return configs
+	// Convert domain descriptor map to list of rate limit configurations
+	return createRateLimitConfigs(domainDesc)
 }
 
 // createRateLimitConfigs creates rate limit configs from the domain descriptor map
@@ -479,6 +481,25 @@ func createRateLimitConfigs(
 	return configs
 }
 
+// Helper to recursively compare two RateLimitDescriptors for equality
+func descriptorsEqual(a, b *rlsconfv3.RateLimitDescriptor) bool {
+	if a == nil || b == nil {
+		return a == b
+	}
+	if a.Key != b.Key || a.Value != b.Value {
+		return false
+	}
+	if len(a.Descriptors) != len(b.Descriptors) {
+		return false
+	}
+	for i := range a.Descriptors {
+		if !descriptorsEqual(a.Descriptors[i], b.Descriptors[i]) {
+			return false
+		}
+	}
+	return true
+}
+
 // addRateLimitDescriptor adds rate limit descriptors to the domain descriptor map.
 // Handles both shared and route-specific rate limits.
 //
@@ -495,31 +516,107 @@ func addRateLimitDescriptor(
 	serviceDescriptors []*rlsconfv3.RateLimitDescriptor,
 	domain string,
 	domainDescriptors map[string][]*rlsconfv3.RateLimitDescriptor,
+	includeShared bool,
 ) {
-	var key, value string
-
-	if isSharedRateLimit(route) {
-		// For shared rate limits, use traffic policy name key/value
-		key = route.Traffic.Name
-		value = route.Traffic.Name
-	} else {
-		// For non-shared rate limits, use route descriptor key/value
-		key = getRouteDescriptor(route.Name)
-		value = getRouteDescriptor(route.Name)
+	if !isValidGlobalRateLimit(route) || len(serviceDescriptors) == 0 {
+		return
 	}
 
-	descriptor := &rlsconfv3.RateLimitDescriptor{
-		Key:         key,
-		Value:       value,
-		Descriptors: serviceDescriptors,
+	for i, rule := range route.Traffic.RateLimit.Global.Rules {
+		if i >= len(serviceDescriptors) || (includeShared != isRuleShared(rule)) {
+			continue
+		}
+
+		var descriptorKey string
+		if isRuleShared(rule) {
+			descriptorKey = rule.Name
+		} else {
+			descriptorKey = getRouteDescriptor(route.Name)
+		}
+
+		// Find or create descriptor in domainDescriptors[domain]
+		var descriptorRule *rlsconfv3.RateLimitDescriptor
+		found := false
+		for _, d := range domainDescriptors[domain] {
+			if d.Key == descriptorKey {
+				descriptorRule = d
+				found = true
+				break
+			}
+		}
+		if !found {
+			descriptorRule = &rlsconfv3.RateLimitDescriptor{Key: descriptorKey, Value: descriptorKey}
+			domainDescriptors[domain] = append(domainDescriptors[domain], descriptorRule)
+		}
+
+		// Ensure no duplicate descriptors
+		alreadyExists := false
+		for _, existing := range descriptorRule.Descriptors {
+			if descriptorsEqual(existing, serviceDescriptors[i]) {
+				alreadyExists = true
+				break
+			}
+		}
+		if !alreadyExists {
+			descriptorRule.Descriptors = append(descriptorRule.Descriptors, serviceDescriptors[i])
+		}
 	}
-	domainDescriptors[domain] = append(domainDescriptors[domain], descriptor)
 }
 
-// Helper function to check if a route has a shared rate limit
+// isSharedRateLimit checks if a route has at least one shared rate limit rule.
+// It returns true if any rule in the global rate limit configuration is marked as shared.
+// If no rules are shared or there's no global rate limit configuration, it returns false.
 func isSharedRateLimit(route *ir.HTTPRoute) bool {
+	if !isValidGlobalRateLimit(route) {
+		return false
+	}
+
 	global := route.Traffic.RateLimit.Global
-	return global != nil && global.Shared != nil && *global.Shared && len(global.Rules) > 0
+	if len(global.Rules) == 0 {
+		return false
+	}
+
+	// Check if any rule has shared=true
+	for _, rule := range global.Rules {
+		if isRuleShared(rule) {
+			return true
+		}
+	}
+
+	return false
+}
+
+// Helper function to check if a specific rule is shared
+func isRuleShared(rule *ir.RateLimitRule) bool {
+	return rule != nil && rule.Shared != nil && *rule.Shared
+}
+
+// Helper function to check if a specific rule in a route is shared
+func isRuleAtIndexShared(route *ir.HTTPRoute, ruleIndex int) bool {
+	if route == nil || route.Traffic == nil || route.Traffic.RateLimit == nil ||
+		route.Traffic.RateLimit.Global == nil || len(route.Traffic.RateLimit.Global.Rules) <= ruleIndex || ruleIndex < 0 {
+		return false
+	}
+
+	return isRuleShared(route.Traffic.RateLimit.Global.Rules[ruleIndex])
+}
+
+// Helper function to map a global rule index to a domain-specific rule index
+// This ensures that both shared and non-shared rules have indices starting from 0 in their own domains.
+func getDomainRuleIndex(rules []*ir.RateLimitRule, globalRuleIdx int, ruleIsShared bool) int {
+	if globalRuleIdx < 0 || globalRuleIdx >= len(rules) {
+		return 0
+	}
+
+	// Count how many rules of the same "shared" status came before this one
+	count := 0
+	for i := 0; i < globalRuleIdx; i++ {
+		// If we're looking for shared rules, count shared ones; otherwise count non-shared ones
+		if (ruleIsShared && isRuleShared(rules[i])) || (!ruleIsShared && !isRuleShared(rules[i])) {
+			count++
+		}
+	}
+	return count
 }
 
 // buildRateLimitServiceDescriptors creates the rate limit service pb descriptors based on the global rate limit IR config.
@@ -531,7 +628,6 @@ func buildRateLimitServiceDescriptors(route *ir.HTTPRoute) []*rlsconfv3.RateLimi
 	global := route.Traffic.RateLimit.Global
 
 	pbDescriptors := make([]*rlsconfv3.RateLimitDescriptor, 0, len(global.Rules))
-	usedSharedKey := false // Track if the shared key has been used
 
 	// The order in which matching descriptors are built is consistent with
 	// the order in which ratelimit actions are built:
@@ -549,17 +645,21 @@ func buildRateLimitServiceDescriptors(route *ir.HTTPRoute) []*rlsconfv3.RateLimi
 		// We use a chain structure to describe the matching descriptors for one rule.
 		var head, cur *rlsconfv3.RateLimitDescriptor
 
+		// Calculate the domain-specific rule index (0-based for each domain)
+		ruleIsShared := isRuleShared(rule)
+		domainRuleIdx := getDomainRuleIndex(global.Rules, rIdx, ruleIsShared)
+
 		// 1) Header Matches
 		for mIdx, match := range rule.HeaderMatches {
 			pbDesc := new(rlsconfv3.RateLimitDescriptor)
 			// Distinct vs HeaderValueMatch
 			if match.Distinct {
 				// RequestHeader case
-				pbDesc.Key = getRouteRuleDescriptor(rIdx, mIdx)
+				pbDesc.Key = getRouteRuleDescriptor(domainRuleIdx, mIdx)
 			} else {
 				// HeaderValueMatch case
-				pbDesc.Key = getRouteRuleDescriptor(rIdx, mIdx)
-				pbDesc.Value = getRouteRuleDescriptor(rIdx, mIdx)
+				pbDesc.Key = getRouteRuleDescriptor(domainRuleIdx, mIdx)
+				pbDesc.Value = getRouteRuleDescriptor(domainRuleIdx, mIdx)
 			}
 
 			if mIdx == 0 {
@@ -584,14 +684,14 @@ func buildRateLimitServiceDescriptors(route *ir.HTTPRoute) []*rlsconfv3.RateLimi
 		//
 		// An example of rate limit server configuration looks like this:
 		//
-		//	descriptors:
-		//	  - key: masked_remote_address //catch all the source IPs inside a CIDR
-		//	    value: 192.168.0.0/16
-		//	    descriptors:
-		//	      - key: remote_address //set limit for individual IP
-		//	        rate_limit:
-		//	          unit: second
-		//	          requests_per_unit: 100
+		//  descriptors:
+		//    - key: masked_remote_address //catch all the source IPs inside a CIDR
+		//      value: 192.168.0.0/16
+		//      descriptors:
+		//        - key: remote_address //set limit for individual IP
+		//          rate_limit:
+		//            unit: second
+		//            requests_per_unit: 100
 		//
 		// Please refer to [Rate Limit Service Descriptor list definition](https://github.com/envoyproxy/ratelimit#descriptor-list-definition) for details.
 		// 2) CIDR Match
@@ -617,22 +717,21 @@ func buildRateLimitServiceDescriptors(route *ir.HTTPRoute) []*rlsconfv3.RateLimi
 				cur = pbDesc
 			}
 		}
-
 		// Case when both header and cidr match are not set and the ratelimit
 		// will be applied to all traffic.
 		// 3) No Match (apply to all traffic)
 		if !rule.IsMatchSet() {
 			pbDesc := new(rlsconfv3.RateLimitDescriptor)
 
-			// Determine if we should use the shared rate limit key (BTP-based) or a generic route key
-			if isSharedRateLimit(route) && !usedSharedKey {
-				// For shared rate limits, use BTP name and namespace
-				pbDesc.Key = route.Traffic.Name
-				pbDesc.Value = route.Traffic.Name
-				usedSharedKey = true
+			// Determine if we should use the shared rate limit key (rule-based) or a generic route key
+			if isRuleAtIndexShared(route, rIdx) {
+				// For shared rate limits, use rule name
+				pbDesc.Key = rule.Name
+				pbDesc.Value = rule.Name
 			} else {
-				// Use generic key for non-shared rate limits
-				pbDesc.Key = getRouteRuleDescriptor(rIdx, -1)
+				// Use generic key for non-shared rate limits, with prefix for uniqueness
+				descriptorKey := getRouteRuleDescriptor(domainRuleIdx, -1)
+				pbDesc.Key = descriptorKey
 				pbDesc.Value = pbDesc.Key
 			}
 
@@ -715,8 +814,9 @@ func (t *Translator) createRateLimitServiceCluster(tCtx *types.ResourceVersionTa
 	})
 }
 
-func getDomainName(route *ir.HTTPRoute) string {
-	return strings.Replace(route.Traffic.Name, "/", "-", 1)
+// getDomainSharedName returns the shared domain (stripped policy name), stripRuleIndexSuffix is used to remove the rule index suffix.
+func getDomainSharedName(route *ir.HTTPRoute) string {
+	return stripRuleIndexSuffix(route.Traffic.RateLimit.Global.Rules[0].Name)
 }
 
 func getRouteRuleDescriptor(ruleIndex, matchIndex int) string {
@@ -743,12 +843,37 @@ func (t *Translator) getRateLimitServiceGrpcHostPort() (string, uint32) {
 	return u.Hostname(), uint32(p)
 }
 
-// For shared rate limits, it appends the traffic policy name to the base filter name.
+// getRateLimitFilterName gets the filter name for rate limits.
+// If any rule in the route is shared, it appends the rule name to the base filter name.
 // For non-shared rate limits, it returns just the base filter name.
+// Note: This function is primarily used for route-level filter configuration, not for HTTP filters at the listener level.
 func getRateLimitFilterName(route *ir.HTTPRoute) string {
 	filterName := egv1a1.EnvoyFilterRateLimit.String()
+	// If any rule is shared, include the rule name in the filter name
 	if isSharedRateLimit(route) {
-		filterName = fmt.Sprintf("%s/%s", filterName, route.Traffic.Name)
+		// Find the first shared rule to use its name
+		for _, rule := range route.Traffic.RateLimit.Global.Rules {
+			if isRuleShared(rule) {
+				filterName = fmt.Sprintf("%s/%s", filterName, stripRuleIndexSuffix(rule.Name))
+				break
+			}
+		}
 	}
 	return filterName
 }
+
+// Helper to strip /rule/<index> from a rule name in order to use shared http filter
+func stripRuleIndexSuffix(name string) string {
+	if i := strings.LastIndex(name, "/rule/"); i != -1 {
+		return name[:i]
+	}
+	return strings.Replace(name, "/", "-", 1)
+}
+
+// Helper to check if a route has a valid global rate limit config
+func isValidGlobalRateLimit(route *ir.HTTPRoute) bool {
+	return route != nil &&
+		route.Traffic != nil &&
+		route.Traffic.RateLimit != nil &&
+		route.Traffic.RateLimit.Global != nil
+}
diff --git a/release-notes/current.yaml b/release-notes/current.yaml
index c80f6aad5..3271a4f90 100644
--- a/release-notes/current.yaml
+++ b/release-notes/current.yaml
@@ -8,12 +8,8 @@ security updates: |
 
 # New features or capabilities added in this release.
 new features: |
-  Added support for optionally installing the Gateway API standard channel CRDs through the gateway-crds-helm chart.
 
 bug fixes: |
-  Fix reference grant from SecurityPolicy to referenced remoteJWKS backend not respected.
-  Added validation for header values.
-  Added validation for duplicated API keys.
 
 # Enhancements that improve performance.
 performance improvements: |
diff --git a/release-notes/v1.4.0.yaml b/release-notes/v1.4.0.yaml
new file mode 100644
index 000000000..38348067d
--- /dev/null
+++ b/release-notes/v1.4.0.yaml
@@ -0,0 +1,85 @@
+date: May 13, 2025
+
+# Changes that are expected to cause an incompatibility with previous versions, such as deletions or modifications to existing APIs.
+breaking changes: |
+  Use a dedicated listener port(19003) for envoy proxy readiness
+  Uses the envoy JSON formatter for the default access log instead of text formatter.
+  Envoy Gateway will skip xDS snapshot updates in case of errors during xDS translation.
+  When Extension Manager is configured to Fail Open, translation errors are logged and suppressed.
+  When Extension Manager is configured to not Fail Open, Envoy Gateway will no longer replace affected resources. Instead, xDS snapshot update would be skipped.
+
+# Updates addressing vulnerabilities, security flaws, or compliance requirements.
+security updates: |
+
+# New features or capabilities added in this release.
+new features: |
+  Added support for the extension server in standalone mode.
+  Added support for the `DynamicResolver` backend type, which can route traffic to any backend service based on the request's hostname.
+  Added support for installing CRDs through the `gateway-crds-helm` chart.
+  Added support for the offline Kubernetes controller and enabled its use with the file provider.
+  Added support for configuring `maxUnavailable` in `KubernetesPodDisruptionBudgetSpec`.
+  Added support for percentage-based request mirroring.
+  Allowed `matchExpressions` in `TargetSelector`.
+  Added a defaulter for Gateway API resources loaded from file to set default values.
+  Added support for defining Lua `EnvoyExtensionPolicies`.
+  Added `RequestID` field in `ClientTrafficPolicy.HeaderSettings` to configure Envoy `X-Request-ID` behavior.
+  Added support for `HorizontalPodAutoscaler` for Envoy Gateway in the Helm chart.
+  Added support for distinct header and distinct source CIDR-based local rate limiting.
+  Added support for forwarding the authenticated username to the backend via a configurable header in `BasicAuth`.
+  Added support for HTTP method and header-based authorization in `SecurityPolicy`.
+  Added support for Zone Aware Routing.
+  Added support for `BackendTLSPolicy` targeting `ServiceImport`.
+  Added support for the `kubernetes.io/h2c` application protocol in `ServiceImport`.
+  Added support for per-host circuit breaker thresholds.
+  Added support for injecting a credential from a Kubernetes `Secret` into a request header using the `HTTPRouteFilter` filter.
+  Added support for `egctl` WebSocket in addition to SPDY.
+  Added a configuration option in the Helm chart to set the `TrafficDistribution` field in the `Envoy Gateway` Service.
+  Added support for setting the log level to `trace` for the Envoy proxy.
+  Added support for global `imageRegistry` and `imagePullSecrets` in the Helm chart.
+  Added support for using a local JWKS in an inline string or in a `ConfigMap` to validate JWT tokens in `SecurityPolicy`.
+  Added support for logging the status of resources in standalone mode.
+  Added support for per-route tracing in `BackendTrafficPolicy`.
+  Added support for configuring retry settings for Extension Service hooks in the Envoy Gateway config.
+  Added support for request buffering using the Envoy Buffer filter.
+  Added support for merge type in `BackendTrafficPolicy`.
+  Added support for the `OverlappingTLSConfig` condition in Gateway status. This condition is set if there are overlapping hostnames or certificates between listeners. The ALPN protocol is set to HTTP/1.1 for overlapping listeners to avoid HTTP/2 connection coalescing.
+  Added support for running Envoy infrastructure proxies in the Gateway namespace. Please note that this is currently an experimental feature and not recommended for production use.
+  Added support for Shared Global RateLimiting buckets.
+  Added support for fuzz testing the codebase.
+  Added Backend API Support for Telemetry backends in Envoy Proxy
+  Added support for FullDuplexedStreamed mode in Ext Proc
+
+bug fixes: |
+  Fixed traffic splitting when filters are attached to the `backendRef`.
+  Added support for `Secret` and `ConfigMap` parsing in standalone mode.
+  Bypassed overload manager for stats and ready listeners.
+  Fixed translation of `backendSettings` for external authorization.
+  Fixed an issue where the stats compressor was not working.
+  Added support for `BackendTLSPolicy` and `EnvoyExtensionPolicy` parsing in standalone mode.
+  Re-triggered reconciliation when a `backendRef` of type `ServiceImport` is updated or when `EndpointSlice` resources for a `ServiceImport` are updated.
+  Fixed missing error logs and returns in the Kubernetes Reconcile method when a `GatewayClass` is not accepted.
+  Allowed empty text field for OpenTelemetry sink when using JSON format.
+  Fixed the `SamplingFraction` implementation within the Tracing API.
+  Fixed Kubernetes resources not being deleted when a custom name was used.
+  Prevented essential resources like `Namespace` from being treated as missing when loading from file.
+  Avoided setting retriable status codes to 503 when `RetryOn` is configured in `BackendTrafficPolicy`.
+  Fixed reconciliation logic to continue processing all `GatewayClasses` even after an error with one.
+  Fixed an issue where a `ReferenceGrant` from a `SecurityPolicy` to a referenced `remoteJWKS` backend was not respected.
+  Added additional newline validation for header values.
+  Added validation to prevent duplicated API keys in API Key Auth.
+  Fixed `HTTPRoute` precedence by correctly considering header and query match types.
+  Ensured the TLS inspector filter is only added to TCP listeners (not UDP/QUIC) when HTTP/3 is enabled via `ClientTrafficPolicy`.
+  Fix reconciling mirror backendRef endpoints once they've changed.
+
+# Enhancements that improve performance.
+performance improvements: |
+  Added a cache for the Wasm OCI image permission checks and check the pullSecrets against the OCI image registry in
+  a background goroutine.
+
+# Deprecated features or APIs.
+deprecations: |
+  Deprecated the `PreserveXRequestID` field in `ClientTrafficPolicy.Spec.Headers`. Use `RequestID` instead.
+
+# Other notable changes not covered by the above sections.
+Other changes: |
+  Updated gateway-api to v1.3.0.
diff --git a/site/content/en/contributions/RELEASING.md b/site/content/en/contributions/RELEASING.md
index bdd6b4668..fc4d77121 100644
--- a/site/content/en/contributions/RELEASING.md
+++ b/site/content/en/contributions/RELEASING.md
@@ -173,7 +173,7 @@ export GITHUB_REMOTE=origin
 6. If the tip of the release branch does not match the tip of `main`, perform the following:
 
    1. Create a topic branch from the release branch.
-   2. Cherry-pick the commits from `main` that differ from the release branch.
+   2. Cherry-pick the commits from `main` that differ from the release branch, e.g. `git cherry-pick <present commit in rc>..<latest commit on main> -s`
    3. Run tests locally, e.g. `make lint`.
    4. Sign, commit, and push your topic branch to your Envoy Gateway fork.
    5. Submit a PR to merge the topic from of your fork into the Envoy Gateway release branch.
diff --git a/site/content/en/news/releases/matrix.md b/site/content/en/news/releases/matrix.md
index e48592381..172ec40ea 100644
--- a/site/content/en/news/releases/matrix.md
+++ b/site/content/en/news/releases/matrix.md
@@ -7,7 +7,8 @@ Envoy Gateway relies on the Envoy Proxy and the Gateway API, and runs within a K
 
 | Envoy Gateway version | Envoy Proxy version         | Rate Limit version | Gateway API version | Kubernetes version         |  End of Life |
 |-----------------------|-----------------------------|--------------------|---------------------|----------------------------|--------------|
-| latest                | **dev-latest**              | **master**         | **v1.2.1**          | v1.30, v1.31, v1.32, v1.33 |  n/a         |
+| latest                | **dev-latest**              | **master**         | **v1.3.0**          | v1.30, v1.31, v1.32, v1.33 |  n/a         |
+| v1.4                  | **distroless-v1.34.1**      | **3e085e5b**       | **v1.3.0**          | v1.30, v1.31, v1.32, v1.33 |  2025/11/13  |
 | v1.3                  | **distroless-v1.33.0**      | **60d8e81b**       | **v1.2.1**          | v1.29, v1.30, v1.31, v1.32 |  2025/07/30  |
 | v1.2                  | **distroless-v1.32.1**      | **28b1629a**       | **v1.2.0**          | v1.28, v1.29, v1.30, v1.31 |  2025/05/06  |
 | v1.1                  | **distroless-v1.31.0**      | **91484c59**       | **v1.1.0**          | v1.27, v1.28, v1.29, v1.30 |  2025/01/22  |
diff --git a/site/content/en/news/releases/notes/v1.4.0.md b/site/content/en/news/releases/notes/v1.4.0.md
new file mode 100644
index 000000000..2417581c8
--- /dev/null
+++ b/site/content/en/news/releases/notes/v1.4.0.md
@@ -0,0 +1,87 @@
+---
+title: "v1.4.0"
+publishdate: 2025-05-13
+---
+
+
+## Breaking changes
+
+- Use a dedicated listener port(19003) for envoy proxy readiness
+- Uses the envoy JSON formatter for the default access log instead of text formatter.
+- Envoy Gateway will skip xDS snapshot updates in case of errors during xDS translation.
+- When Extension Manager is configured to Fail Open, translation errors are logged and suppressed.
+- When Extension Manager is configured to not Fail Open, Envoy Gateway will no longer replace affected resources. Instead, xDS snapshot update would be skipped.
+
+## New Features
+
+- Added support for the extension server in standalone mode.
+- Added support for the `DynamicResolver` backend type, which can route traffic to any backend service based on the request's hostname.
+- Added support for installing CRDs through the `gateway-crds-helm` chart.
+- Added support for the offline Kubernetes controller and enabled its use with the file provider.
+- Added support for configuring `maxUnavailable` in `KubernetesPodDisruptionBudgetSpec`.
+- Added support for percentage-based request mirroring.
+- Allowed `matchExpressions` in `TargetSelector`.
+- Added a defaulter for Gateway API resources loaded from file to set default values.
+- Added support for defining Lua `EnvoyExtensionPolicies`.
+- Added `RequestID` field in `ClientTrafficPolicy.HeaderSettings` to configure Envoy `X-Request-ID` behavior.
+- Added support for `HorizontalPodAutoscaler` for Envoy Gateway in the Helm chart.
+- Added support for distinct header and distinct source CIDR-based local rate limiting.
+- Added support for forwarding the authenticated username to the backend via a configurable header in `BasicAuth`.
+- Added support for HTTP method and header-based authorization in `SecurityPolicy`.
+- Added support for Zone Aware Routing.
+- Added support for `BackendTLSPolicy` targeting `ServiceImport`.
+- Added support for the `kubernetes.io/h2c` application protocol in `ServiceImport`.
+- Added support for per-host circuit breaker thresholds.
+- Added support for injecting a credential from a Kubernetes `Secret` into a request header using the `HTTPRouteFilter` filter.
+- Added support for `egctl` WebSocket in addition to SPDY.
+- Added a configuration option in the Helm chart to set the `TrafficDistribution` field in the `Envoy Gateway` Service.
+- Added support for setting the log level to `trace` for the Envoy proxy.
+- Added support for global `imageRegistry` and `imagePullSecrets` in the Helm chart.
+- Added support for using a local JWKS in an inline string or in a `ConfigMap` to validate JWT tokens in `SecurityPolicy`.
+- Added support for logging the status of resources in standalone mode.
+- Added support for per-route tracing in `BackendTrafficPolicy`.
+- Added support for configuring retry settings for Extension Service hooks in the Envoy Gateway config.
+- Added support for request buffering using the Envoy Buffer filter.
+- Added support for merge type in `BackendTrafficPolicy`.
+- Added support for the `OverlappingTLSConfig` condition in Gateway status. This condition is set if there are overlapping hostnames or certificates between listeners. The ALPN protocol is set to HTTP/1.1 for overlapping listeners to avoid HTTP/2 connection coalescing.
+- Added support for running Envoy infrastructure proxies in the Gateway namespace. Please note that this is currently an experimental feature and not recommended for production use.
+- Added support for Shared Global RateLimiting buckets.
+- Added support for fuzz testing the codebase.
+- Added Backend API Support for Telemetry backends in Envoy Proxy
+- Added support for FullDuplexedStreamed mode in Ext Proc
+
+## Bug Fixes
+
+- Fixed traffic splitting when filters are attached to the `backendRef`.
+- Added support for `Secret` and `ConfigMap` parsing in standalone mode.
+- Bypassed overload manager for stats and ready listeners.
+- Fixed translation of `backendSettings` for external authorization.
+- Fixed an issue where the stats compressor was not working.
+- Added support for `BackendTLSPolicy` and `EnvoyExtensionPolicy` parsing in standalone mode.
+- Re-triggered reconciliation when a `backendRef` of type `ServiceImport` is updated or when `EndpointSlice` resources for a `ServiceImport` are updated.
+- Fixed missing error logs and returns in the Kubernetes Reconcile method when a `GatewayClass` is not accepted.
+- Allowed empty text field for OpenTelemetry sink when using JSON format.
+- Fixed the `SamplingFraction` implementation within the Tracing API.
+- Fixed Kubernetes resources not being deleted when a custom name was used.
+- Prevented essential resources like `Namespace` from being treated as missing when loading from file.
+- Avoided setting retriable status codes to 503 when `RetryOn` is configured in `BackendTrafficPolicy`.
+- Fixed reconciliation logic to continue processing all `GatewayClasses` even after an error with one.
+- Fixed an issue where a `ReferenceGrant` from a `SecurityPolicy` to a referenced `remoteJWKS` backend was not respected.
+- Added additional newline validation for header values.
+- Added validation to prevent duplicated API keys in API Key Auth.
+- Fixed `HTTPRoute` precedence by correctly considering header and query match types.
+- Ensured the TLS inspector filter is only added to TCP listeners (not UDP/QUIC) when HTTP/3 is enabled via `ClientTrafficPolicy`.
+- Fix reconciling mirror backendRef endpoints once they've changed.
+
+## Performance Improvements
+
+- Added a cache for the Wasm OCI image permission checks and check the pullSecrets against the OCI image registry in
+  a background goroutine.
+
+# Deprecations
+
+- Deprecated the `PreserveXRequestID` field in `ClientTrafficPolicy.Spec.Headers`. Use `RequestID` instead.
+
+## Other Changes
+
+- Updated gateway-api to v1.3.0.
diff --git a/site/content/en/news/releases/v1.4.md b/site/content/en/news/releases/v1.4.md
new file mode 100644
index 000000000..5f774df32
--- /dev/null
+++ b/site/content/en/news/releases/v1.4.md
@@ -0,0 +1,117 @@
+---
+title: Announcing Envoy Gateway v1.4
+subtitle: Minor Update
+linktitle: Release v1.4
+description: Envoy Gateway v1.4 release announcement.
+publishdate: 2025-05-13
+release: v1.4.0
+skip_list: true
+---
+
+We are thrilled to announce the arrival of Envoy Gateway v1.4.0.
+
+This release represents a significant achievement, and we extend our heartfelt gratitude to the entire Envoy Gateway community for their contributions, dedication, and support. Your collaborative efforts have been instrumental in reaching this pivotal release.
+
+Thank you for being an integral part of this journey. We are excited to see how Envoy Gateway v1.4.0 will empower your operations and look forward to continuing our work together to drive the future of Cloud Native API Gateway.
+
+| [Release Notes][] | [Docs][docs] | [Compatibility Matrix][matrix] | [Install][] |
+|-------------------|--------------|--------------------------------|--------------|
+
+## What's New
+
+Envoy Gateway v1.4.0 introduces powerful new features across traffic management, observability, security, extensibility, and infrastructure — along with key stability improvements.
+
+---
+
+## 🚨 Breaking Changes
+
+- **Envoy Readiness Port**: A dedicated listener port (`19003`) is now used for Envoy proxy readiness.
+- **Access Log Format**: The default access log now uses the Envoy JSON formatter instead of the plain text formatter.
+- **xDS Snapshot Behavior**: Envoy Gateway now skips xDS snapshot updates if errors occur during xDS translation.
+- **Extension Manager Behavior**:
+  - With `failOpen: true`, translation errors are logged and suppressed.
+  - With `failOpen: false`, xDS updates are skipped for affected resources (no longer replaced).
+
+---
+
+## ✨ New Features
+
+### API & Traffic Management Enhancements
+
+- Dynamic backend routing via the new `DynamicResolver` type based on request hostnames.
+- Support for zone-aware routing.
+- Percentage-based request mirroring support.
+- New circuit breaker support for per-host thresholds.
+- Request buffering using the Envoy Buffer filter.
+- Support for merge-type configuration in `BackendTrafficPolicy`.
+- Enhanced support for request retry configuration with Extension Services.
+- Support for Shared Global RateLimiting buckets.
+- Support distinct match support for Local Ratelimiting.
+
+### Security Enhancements
+
+- `SecurityPolicy` now supports forwarding authenticated usernames to backends via configurable headers in Basic Auth.
+- Support for local JWKS sources (inline or via `ConfigMap`) to validate JWT tokens.
+- Support for injecting credentials from Kubernetes Secrets into request headers via `HTTPRouteFilter`.
+- Support for HTTP method and header-based authorization via `SecurityPolicy`.
+
+### Observability & Tracing
+
+- Added `RequestID` header configuration via `ClientTrafficPolicy`.
+- OpenTelemetry sink improvements for JSON formatting.
+- Per-route tracing configuration in `BackendTrafficPolicy`.
+- Backend API support for Telemetry Backends
+
+### Infra
+
+- Helm chart improvements:
+  - `HorizontalPodAutoscaler` support for Envoy Gateway.
+  - Global `imageRegistry` and `imagePullSecrets` configuration.
+  - Helm config for `TrafficDistribution` field.
+- Added support for CRD installation via `gateway-crds-helm` chart.
+- Option to run infrastructure Envoy proxies in the Gateway namespace (experimental).
+- Support for `maxUnavailable` in `PodDisruptionBudget`.
+
+### Extensibility
+
+- Support for Lua-based `EnvoyExtensionPolicy`.
+- Support for Extension Server in standalone mode.
+- Retry support for Extension Service hooks.
+- Support for FullDuplexedStreamed mode in External Processor filter.
+---
+
+## 🐞 Bug Fixes
+
+- Traffic splitting now works correctly when filters are attached to `backendRef`.
+- Fixed handling and validation of headers, OpenTelemetry fields, and duplicated API keys.
+- Stats compressor and overload manager behavior corrected.
+- Correct precedence in `HTTPRoute` header and query matching.
+- Fixed behavior of TLS inspector filters for UDP/QUIC.
+- Corrected retryOn behavior for `BackendTrafficPolicy`.
+- Avoid HTTP/2 Connection Coalescing scenarios.
+---
+
+## 🚀 Performance Improvements
+
+- Added cache for Wasm OCI image permission checks and pulled secrets asynchronously.
+
+---
+
+## 🛑 Deprecations
+
+- The `PreserveXRequestID` field in `ClientTrafficPolicy.Spec.Headers` is deprecated. Use the new `RequestID` field instead.
+
+---
+
+## 📌 Other Notable Changes
+
+- Updated to use `gateway-api` v1.3.0.
+
+---
+
+We encourage users to upgrade to v1.4.0 and explore these improvements. For full details, see the [Release Notes][] and updated [Documentation][docs].
+
+[Release Notes]: ./notes/v1.4.0.md
+[docs]: https://gateway.envoyproxy.io
+[matrix]: https://gateway.envoyproxy.io/news/releases/matrix/
+[Install]: https://gateway.envoyproxy.io/docs/tasks/quickstart/
diff --git a/site/hugo.toml b/site/hugo.toml
index f2cf2b88c..da20f65aa 100644
--- a/site/hugo.toml
+++ b/site/hugo.toml
@@ -93,7 +93,7 @@ copyright = "The Envoy Gateway Authors"
 
 
 # First one is picked as the Twitter card image if not set on page, as well as the open graph image.
-images = ["site/static/img/envoy-gateway-feature.png"]
+images = ["/img/envoy-gateway-feature.png"]
 
 # Menu title if your navbar has a versions selector to access old versions of your site.
 # This menu appears only if you have at least one [params.versions] set.


Test patch:
diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml
index 651841c7b..17bac1026 100644
--- a/.github/workflows/build_and_test.yaml
+++ b/.github/workflows/build_and_test.yaml
@@ -220,7 +220,7 @@ jobs:
 
   publish:
     runs-on: ubuntu-latest
-    needs: [conformance-test, e2e-test, resilience-test]
+    needs: [conformance-test, e2e-test]
     steps:
     - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683  # v4.2.2
     - uses: ./tools/github-actions/setup-deps
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit-out-of-range-error.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit-out-of-range-error.out.yaml
index 7a971b946..8906c3c11 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit-out-of-range-error.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit-out-of-range-error.out.yaml
@@ -284,7 +284,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           timeout:
             http:
               connectionIdleTimeout: 16s
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit-with-invalid-value.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit-with-invalid-value.out.yaml
index 9f79eab20..55f4c8854 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit-with-invalid-value.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit-with-invalid-value.out.yaml
@@ -284,7 +284,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           timeout:
             http:
               connectionIdleTimeout: 16s
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit.out.yaml
index fb4ae09a9..b3d716c81 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-buffer-limit.out.yaml
@@ -284,7 +284,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           timeout:
             http:
               connectionIdleTimeout: 16s
@@ -340,7 +339,6 @@ xdsIR:
         traffic:
           backendConnection:
             bufferLimit: 100000000
-          name: default/policy-for-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-compression.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-compression.out.yaml
index aa1385507..df89978b3 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-compression.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-compression.out.yaml
@@ -171,7 +171,6 @@ xdsIR:
           compression:
           - type: Brotli
           - type: Gzip
-          name: default/policy-for-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-dns-lookup-family.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-dns-lookup-family.out.yaml
index a7aba4132..0db7d5ab1 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-dns-lookup-family.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-dns-lookup-family.out.yaml
@@ -449,7 +449,6 @@ xdsIR:
             dnsRefreshRate: 5s
             lookupFamily: IPv6
             respectDnsTtl: false
-          name: default/backend-traffic-policy
       - destination:
           name: grpcroute/default/grpcroute-1/rule/0
           settings:
@@ -495,7 +494,6 @@ xdsIR:
             dnsRefreshRate: 5s
             lookupFamily: IPv6
             respectDnsTtl: false
-          name: default/backend-traffic-policy
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-http-upgrade-spdy.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-http-upgrade-spdy.out.yaml
index 689cb9c29..1903430df 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-http-upgrade-spdy.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-http-upgrade-spdy.out.yaml
@@ -169,7 +169,6 @@ xdsIR:
         traffic:
           httpUpgrade:
           - spdy/3.1
-          name: default/policy-for-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-http-upgrade-websocket.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-http-upgrade-websocket.out.yaml
index 0cefe0206..5e43ac665 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-http-upgrade-websocket.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-http-upgrade-websocket.out.yaml
@@ -171,7 +171,6 @@ xdsIR:
           httpUpgrade:
           - websocket
           - spdy/3.1
-          name: default/policy-for-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-override-replace.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-override-replace.out.yaml
index e43484d45..ad527fcee 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-override-replace.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-override-replace.out.yaml
@@ -313,7 +313,6 @@ xdsIR:
           loadBalancer:
             consistentHash:
               sourceIP: true
-          name: default/policy-for-route-1
       - destination:
           name: httproute/default/httproute-2/rule/0
           settings:
@@ -338,7 +337,6 @@ xdsIR:
         traffic:
           loadBalancer:
             random: {}
-          name: envoy-gateway/policy-for-gateway-1
           timeout:
             http:
               connectionIdleTimeout: 21s
@@ -366,8 +364,7 @@ xdsIR:
           distinct: false
           name: ""
           prefix: /baz
-        traffic:
-          name: default/policy-for-route-3
+        traffic: {}
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-request-buffer.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-request-buffer.out.yaml
index 4b8fd4217..4b0955aab 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-request-buffer.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-request-buffer.out.yaml
@@ -288,7 +288,6 @@ xdsIR:
           name: ""
           prefix: /foo
         traffic:
-          name: envoy-gateway/policy-for-gateway
           requestBuffer:
             limit: 4Mi
     readyListener:
@@ -338,7 +337,6 @@ xdsIR:
           name: ""
           prefix: /foo
         traffic:
-          name: default/policy-for-route
           requestBuffer:
             limit: 4Mi
     readyListener:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml
index fdefe01e1..daf9e5d20 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-status-conditions.out.yaml
@@ -584,8 +584,7 @@ xdsIR:
           distinct: false
           name: ""
           prefix: /
-        traffic:
-          name: envoy-gateway/target-httproute-in-gateway-1
+        traffic: {}
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -632,8 +631,7 @@ xdsIR:
           name: grpcroute-1
           namespace: envoy-gateway
         name: grpcroute/envoy-gateway/grpcroute-1/rule/0/match/0/*
-        traffic:
-          name: envoy-gateway/target-grpcroute-in-gateway-2
+        traffic: {}
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-status-fault-injection.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-status-fault-injection.out.yaml
index a180cead0..41e2c5a0c 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-status-fault-injection.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-status-fault-injection.out.yaml
@@ -371,7 +371,6 @@ xdsIR:
             delay:
               fixedDelay: 5.4s
               percentage: 80
-          name: default/policy-for-grpcroute
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -423,7 +422,6 @@ xdsIR:
             abort:
               httpStatus: 14
               percentage: 0.01
-          name: envoy-gateway/policy-for-gateway
       - destination:
           name: httproute/default/httproute-1/rule/0
           settings:
@@ -453,7 +451,6 @@ xdsIR:
             delay:
               fixedDelay: 5.4s
               percentage: 80
-          name: default/policy-for-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-global-ratelimit.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-global-ratelimit.in.yaml
new file mode 100644
index 000000000..585a70dc0
--- /dev/null
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-global-ratelimit.in.yaml
@@ -0,0 +1,115 @@
+gateways:
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: Gateway
+    metadata:
+      namespace: envoy-gateway
+      name: gateway-1
+    spec:
+      gatewayClassName: envoy-gateway-class
+      listeners:
+        - name: http
+          protocol: HTTP
+          port: 80
+          allowedRoutes:
+            namespaces:
+              from: All
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: Gateway
+    metadata:
+      namespace: envoy-gateway
+      name: gateway-2
+    spec:
+      gatewayClassName: envoy-gateway-class
+      listeners:
+        - name: http
+          protocol: HTTP
+          port: 80
+          allowedRoutes:
+            namespaces:
+              from: All
+httpRoutes:
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: HTTPRoute
+    metadata:
+      namespace: default
+      name: httproute-1
+    spec:
+      hostnames:
+        - gateway.envoyproxy.io
+      parentRefs:
+        - namespace: envoy-gateway
+          name: gateway-1
+          sectionName: http
+        - namespace: envoy-gateway
+          name: gateway-2
+          sectionName: http
+      rules:
+        - matches:
+            - path:
+                value: "/"
+          backendRefs:
+            - name: service-1
+              port: 8080
+backendTrafficPolicies:
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: BackendTrafficPolicy
+    metadata:
+      namespace: envoy-gateway
+      name: policy-for-gateway1
+    spec:
+      targetRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+      timeout:
+        tcp:
+          connectTimeout: 15s
+        http:
+          connectionIdleTimeout: 16s
+          maxConnectionDuration: 17s
+      httpUpgrade:
+        - type: websocket
+      rateLimit:
+        type: Global
+        global:
+          rules:
+            - clientSelectors:
+                - headers:
+                    - name: x-user-id
+                      type: Exact
+                      value: two
+              limit:
+                requests: 5
+                unit: Hour
+              shared: true
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: BackendTrafficPolicy
+    metadata:
+      namespace: default
+      name: policy-for-route
+    spec:
+      targetRef:
+        group: gateway.networking.k8s.io
+        kind: HTTPRoute
+        name: httproute-1
+      mergeType: StrategicMerge
+      timeout:
+        tcp:
+          connectTimeout: 10s
+      connection:
+        bufferLimit: 100M
+      httpUpgrade:
+        - type: "spdy/3.1"
+      rateLimit:
+        type: Global
+        global:
+          rules:
+            - clientSelectors:
+                - headers:
+                    - name: x-user-id
+                      type: Exact
+                      value: one
+              limit:
+                requests: 5
+                unit: Hour
+              shared: true
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-global-ratelimit.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-global-ratelimit.out.yaml
new file mode 100644
index 000000000..c70c9d724
--- /dev/null
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-global-ratelimit.out.yaml
@@ -0,0 +1,443 @@
+backendTrafficPolicies:
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: BackendTrafficPolicy
+  metadata:
+    creationTimestamp: null
+    name: policy-for-route
+    namespace: default
+  spec:
+    connection:
+      bufferLimit: 100M
+    httpUpgrade:
+    - type: spdy/3.1
+    mergeType: StrategicMerge
+    rateLimit:
+      global:
+        rules:
+        - clientSelectors:
+          - headers:
+            - name: x-user-id
+              type: Exact
+              value: one
+          limit:
+            requests: 5
+            unit: Hour
+          shared: true
+      type: Global
+    targetRef:
+      group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: httproute-1
+    timeout:
+      tcp:
+        connectTimeout: 10s
+  status:
+    ancestors:
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+      conditions:
+      - lastTransitionTime: null
+        message: Merged with policy envoy-gateway/policy-for-gateway1
+        reason: Merged
+        status: "True"
+        type: Merged
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+      conditions:
+      - lastTransitionTime: null
+        message: Policy has been accepted.
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-2
+        namespace: envoy-gateway
+        sectionName: http
+      conditions:
+      - lastTransitionTime: null
+        message: Policy has been accepted.
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: BackendTrafficPolicy
+  metadata:
+    creationTimestamp: null
+    name: policy-for-gateway1
+    namespace: envoy-gateway
+  spec:
+    httpUpgrade:
+    - type: websocket
+    rateLimit:
+      global:
+        rules:
+        - clientSelectors:
+          - headers:
+            - name: x-user-id
+              type: Exact
+              value: two
+          limit:
+            requests: 5
+            unit: Hour
+          shared: true
+      type: Global
+    targetRef:
+      group: gateway.networking.k8s.io
+      kind: Gateway
+      name: gateway-1
+    timeout:
+      http:
+        connectionIdleTimeout: 16s
+        maxConnectionDuration: 17s
+      tcp:
+        connectTimeout: 15s
+  status:
+    ancestors:
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+      conditions:
+      - lastTransitionTime: null
+        message: Policy has been accepted.
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: 'This policy is being merged by other backendTrafficPolicies for
+          these routes: [default/httproute-1]'
+        reason: Merged
+        status: "True"
+        type: Merged
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+gateways:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: Gateway
+  metadata:
+    creationTimestamp: null
+    name: gateway-1
+    namespace: envoy-gateway
+  spec:
+    gatewayClassName: envoy-gateway-class
+    listeners:
+    - allowedRoutes:
+        namespaces:
+          from: All
+      name: http
+      port: 80
+      protocol: HTTP
+  status:
+    listeners:
+    - attachedRoutes: 1
+      conditions:
+      - lastTransitionTime: null
+        message: Sending translated listener configuration to the data plane
+        reason: Programmed
+        status: "True"
+        type: Programmed
+      - lastTransitionTime: null
+        message: Listener has been successfully translated
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Listener references have been resolved
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      name: http
+      supportedKinds:
+      - group: gateway.networking.k8s.io
+        kind: HTTPRoute
+      - group: gateway.networking.k8s.io
+        kind: GRPCRoute
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: Gateway
+  metadata:
+    creationTimestamp: null
+    name: gateway-2
+    namespace: envoy-gateway
+  spec:
+    gatewayClassName: envoy-gateway-class
+    listeners:
+    - allowedRoutes:
+        namespaces:
+          from: All
+      name: http
+      port: 80
+      protocol: HTTP
+  status:
+    listeners:
+    - attachedRoutes: 1
+      conditions:
+      - lastTransitionTime: null
+        message: Sending translated listener configuration to the data plane
+        reason: Programmed
+        status: "True"
+        type: Programmed
+      - lastTransitionTime: null
+        message: Listener has been successfully translated
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Listener references have been resolved
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      name: http
+      supportedKinds:
+      - group: gateway.networking.k8s.io
+        kind: HTTPRoute
+      - group: gateway.networking.k8s.io
+        kind: GRPCRoute
+httpRoutes:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-1
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    - name: gateway-2
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      matches:
+      - path:
+          value: /
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-2
+        namespace: envoy-gateway
+        sectionName: http
+infraIR:
+  envoy-gateway/gateway-1:
+    proxy:
+      listeners:
+      - address: null
+        name: envoy-gateway/gateway-1/http
+        ports:
+        - containerPort: 10080
+          name: http-80
+          protocol: HTTP
+          servicePort: 80
+      metadata:
+        labels:
+          gateway.envoyproxy.io/owning-gateway-name: gateway-1
+          gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
+      name: envoy-gateway/gateway-1
+      namespace: envoy-gateway-system
+  envoy-gateway/gateway-2:
+    proxy:
+      listeners:
+      - address: null
+        name: envoy-gateway/gateway-2/http
+        ports:
+        - containerPort: 10080
+          name: http-80
+          protocol: HTTP
+          servicePort: 80
+      metadata:
+        labels:
+          gateway.envoyproxy.io/owning-gateway-name: gateway-2
+          gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
+      name: envoy-gateway/gateway-2
+      namespace: envoy-gateway-system
+xdsIR:
+  envoy-gateway/gateway-1:
+    accessLog:
+      json:
+      - path: /dev/stdout
+    http:
+    - address: 0.0.0.0
+      hostnames:
+      - '*'
+      isHTTP2: false
+      metadata:
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+      name: envoy-gateway/gateway-1/http
+      path:
+        escapedSlashesAction: UnescapeAndRedirect
+        mergeSlashes: true
+      port: 10080
+      routes:
+      - destination:
+          name: httproute/default/httproute-1/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            name: httproute/default/httproute-1/rule/0/backend/0
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        metadata:
+          kind: HTTPRoute
+          name: httproute-1
+          namespace: default
+        name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /
+        traffic:
+          backendConnection:
+            bufferLimit: 100000000
+          httpUpgrade:
+          - spdy/3.1
+          - websocket
+          rateLimit:
+            global:
+              rules:
+              - headerMatches:
+                - distinct: false
+                  exact: one
+                  name: x-user-id
+                limit:
+                  requests: 5
+                  unit: Hour
+                name: default/policy-for-route/rule/0
+                shared: true
+              - headerMatches:
+                - distinct: false
+                  exact: two
+                  name: x-user-id
+                limit:
+                  requests: 5
+                  unit: Hour
+                name: envoy-gateway/policy-for-gateway1/rule/0
+                shared: true
+          timeout:
+            http:
+              connectionIdleTimeout: 16s
+              maxConnectionDuration: 17s
+            tcp:
+              connectTimeout: 10s
+    readyListener:
+      address: 0.0.0.0
+      ipFamily: IPv4
+      path: /ready
+      port: 19003
+  envoy-gateway/gateway-2:
+    accessLog:
+      json:
+      - path: /dev/stdout
+    http:
+    - address: 0.0.0.0
+      hostnames:
+      - '*'
+      isHTTP2: false
+      metadata:
+        kind: Gateway
+        name: gateway-2
+        namespace: envoy-gateway
+        sectionName: http
+      name: envoy-gateway/gateway-2/http
+      path:
+        escapedSlashesAction: UnescapeAndRedirect
+        mergeSlashes: true
+      port: 10080
+      routes:
+      - destination:
+          name: httproute/default/httproute-1/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            name: httproute/default/httproute-1/rule/0/backend/0
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        metadata:
+          kind: HTTPRoute
+          name: httproute-1
+          namespace: default
+        name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /
+        traffic:
+          backendConnection:
+            bufferLimit: 100000000
+          httpUpgrade:
+          - spdy/3.1
+          rateLimit:
+            global:
+              rules:
+              - headerMatches:
+                - distinct: false
+                  exact: one
+                  name: x-user-id
+                limit:
+                  requests: 5
+                  unit: Hour
+                name: default/policy-for-route/rule/0
+                shared: true
+          timeout:
+            tcp:
+              connectTimeout: 10s
+    readyListener:
+      address: 0.0.0.0
+      ipFamily: IPv4
+      path: /ready
+      port: 19003
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-local-ratelimit.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-local-ratelimit.in.yaml
new file mode 100644
index 000000000..3a9c8ccf7
--- /dev/null
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-local-ratelimit.in.yaml
@@ -0,0 +1,113 @@
+gateways:
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: Gateway
+    metadata:
+      namespace: envoy-gateway
+      name: gateway-1
+    spec:
+      gatewayClassName: envoy-gateway-class
+      listeners:
+        - name: http
+          protocol: HTTP
+          port: 80
+          allowedRoutes:
+            namespaces:
+              from: All
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: Gateway
+    metadata:
+      namespace: envoy-gateway
+      name: gateway-2
+    spec:
+      gatewayClassName: envoy-gateway-class
+      listeners:
+        - name: http
+          protocol: HTTP
+          port: 80
+          allowedRoutes:
+            namespaces:
+              from: All
+httpRoutes:
+  - apiVersion: gateway.networking.k8s.io/v1
+    kind: HTTPRoute
+    metadata:
+      namespace: default
+      name: httproute-1
+    spec:
+      hostnames:
+        - gateway.envoyproxy.io
+      parentRefs:
+        - namespace: envoy-gateway
+          name: gateway-1
+          sectionName: http
+        - namespace: envoy-gateway
+          name: gateway-2
+          sectionName: http
+      rules:
+        - matches:
+            - path:
+                value: "/"
+          backendRefs:
+            - name: service-1
+              port: 8080
+backendTrafficPolicies:
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: BackendTrafficPolicy
+    metadata:
+      namespace: envoy-gateway
+      name: policy-for-gateway1
+    spec:
+      targetRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+      timeout:
+        tcp:
+          connectTimeout: 15s
+        http:
+          connectionIdleTimeout: 16s
+          maxConnectionDuration: 17s
+      httpUpgrade:
+        - type: websocket
+      rateLimit:
+        type: Local
+        local:
+          rules:
+            - clientSelectors:
+                - headers:
+                    - name: x-user-id
+                      type: Exact
+                      value: two
+              limit:
+                requests: 5
+                unit: Hour
+  - apiVersion: gateway.envoyproxy.io/v1alpha1
+    kind: BackendTrafficPolicy
+    metadata:
+      namespace: default
+      name: policy-for-route
+    spec:
+      targetRef:
+        group: gateway.networking.k8s.io
+        kind: HTTPRoute
+        name: httproute-1
+      mergeType: StrategicMerge
+      timeout:
+        tcp:
+          connectTimeout: 10s
+      connection:
+        bufferLimit: 100M
+      httpUpgrade:
+        - type: "spdy/3.1"
+      rateLimit:
+        type: Local
+        local:
+          rules:
+            - clientSelectors:
+                - headers:
+                    - name: x-user-id
+                      type: Exact
+                      value: one
+              limit:
+                requests: 5
+                unit: Hour
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-local-ratelimit.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-local-ratelimit.out.yaml
new file mode 100644
index 000000000..e0eb784ad
--- /dev/null
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-local-ratelimit.out.yaml
@@ -0,0 +1,444 @@
+backendTrafficPolicies:
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: BackendTrafficPolicy
+  metadata:
+    creationTimestamp: null
+    name: policy-for-route
+    namespace: default
+  spec:
+    connection:
+      bufferLimit: 100M
+    httpUpgrade:
+    - type: spdy/3.1
+    mergeType: StrategicMerge
+    rateLimit:
+      local:
+        rules:
+        - clientSelectors:
+          - headers:
+            - name: x-user-id
+              type: Exact
+              value: one
+          limit:
+            requests: 5
+            unit: Hour
+      type: Local
+    targetRef:
+      group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: httproute-1
+    timeout:
+      tcp:
+        connectTimeout: 10s
+  status:
+    ancestors:
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+      conditions:
+      - lastTransitionTime: null
+        message: Merged with policy envoy-gateway/policy-for-gateway1
+        reason: Merged
+        status: "True"
+        type: Merged
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+      conditions:
+      - lastTransitionTime: null
+        message: Policy has been accepted.
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-2
+        namespace: envoy-gateway
+        sectionName: http
+      conditions:
+      - lastTransitionTime: null
+        message: Policy has been accepted.
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+- apiVersion: gateway.envoyproxy.io/v1alpha1
+  kind: BackendTrafficPolicy
+  metadata:
+    creationTimestamp: null
+    name: policy-for-gateway1
+    namespace: envoy-gateway
+  spec:
+    httpUpgrade:
+    - type: websocket
+    rateLimit:
+      local:
+        rules:
+        - clientSelectors:
+          - headers:
+            - name: x-user-id
+              type: Exact
+              value: two
+          limit:
+            requests: 5
+            unit: Hour
+      type: Local
+    targetRef:
+      group: gateway.networking.k8s.io
+      kind: Gateway
+      name: gateway-1
+    timeout:
+      http:
+        connectionIdleTimeout: 16s
+        maxConnectionDuration: 17s
+      tcp:
+        connectTimeout: 15s
+  status:
+    ancestors:
+    - ancestorRef:
+        group: gateway.networking.k8s.io
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+      conditions:
+      - lastTransitionTime: null
+        message: Policy has been accepted.
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: 'This policy is being merged by other backendTrafficPolicies for
+          these routes: [default/httproute-1]'
+        reason: Merged
+        status: "True"
+        type: Merged
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+gateways:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: Gateway
+  metadata:
+    creationTimestamp: null
+    name: gateway-1
+    namespace: envoy-gateway
+  spec:
+    gatewayClassName: envoy-gateway-class
+    listeners:
+    - allowedRoutes:
+        namespaces:
+          from: All
+      name: http
+      port: 80
+      protocol: HTTP
+  status:
+    listeners:
+    - attachedRoutes: 1
+      conditions:
+      - lastTransitionTime: null
+        message: Sending translated listener configuration to the data plane
+        reason: Programmed
+        status: "True"
+        type: Programmed
+      - lastTransitionTime: null
+        message: Listener has been successfully translated
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Listener references have been resolved
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      name: http
+      supportedKinds:
+      - group: gateway.networking.k8s.io
+        kind: HTTPRoute
+      - group: gateway.networking.k8s.io
+        kind: GRPCRoute
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: Gateway
+  metadata:
+    creationTimestamp: null
+    name: gateway-2
+    namespace: envoy-gateway
+  spec:
+    gatewayClassName: envoy-gateway-class
+    listeners:
+    - allowedRoutes:
+        namespaces:
+          from: All
+      name: http
+      port: 80
+      protocol: HTTP
+  status:
+    listeners:
+    - attachedRoutes: 1
+      conditions:
+      - lastTransitionTime: null
+        message: Sending translated listener configuration to the data plane
+        reason: Programmed
+        status: "True"
+        type: Programmed
+      - lastTransitionTime: null
+        message: Listener has been successfully translated
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Listener references have been resolved
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      name: http
+      supportedKinds:
+      - group: gateway.networking.k8s.io
+        kind: HTTPRoute
+      - group: gateway.networking.k8s.io
+        kind: GRPCRoute
+httpRoutes:
+- apiVersion: gateway.networking.k8s.io/v1
+  kind: HTTPRoute
+  metadata:
+    creationTimestamp: null
+    name: httproute-1
+    namespace: default
+  spec:
+    hostnames:
+    - gateway.envoyproxy.io
+    parentRefs:
+    - name: gateway-1
+      namespace: envoy-gateway
+      sectionName: http
+    - name: gateway-2
+      namespace: envoy-gateway
+      sectionName: http
+    rules:
+    - backendRefs:
+      - name: service-1
+        port: 8080
+      matches:
+      - path:
+          value: /
+  status:
+    parents:
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+    - conditions:
+      - lastTransitionTime: null
+        message: Route is accepted
+        reason: Accepted
+        status: "True"
+        type: Accepted
+      - lastTransitionTime: null
+        message: Resolved all the Object references for the Route
+        reason: ResolvedRefs
+        status: "True"
+        type: ResolvedRefs
+      controllerName: gateway.envoyproxy.io/gatewayclass-controller
+      parentRef:
+        name: gateway-2
+        namespace: envoy-gateway
+        sectionName: http
+infraIR:
+  envoy-gateway/gateway-1:
+    proxy:
+      listeners:
+      - address: null
+        name: envoy-gateway/gateway-1/http
+        ports:
+        - containerPort: 10080
+          name: http-80
+          protocol: HTTP
+          servicePort: 80
+      metadata:
+        labels:
+          gateway.envoyproxy.io/owning-gateway-name: gateway-1
+          gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
+      name: envoy-gateway/gateway-1
+      namespace: envoy-gateway-system
+  envoy-gateway/gateway-2:
+    proxy:
+      listeners:
+      - address: null
+        name: envoy-gateway/gateway-2/http
+        ports:
+        - containerPort: 10080
+          name: http-80
+          protocol: HTTP
+          servicePort: 80
+      metadata:
+        labels:
+          gateway.envoyproxy.io/owning-gateway-name: gateway-2
+          gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
+      name: envoy-gateway/gateway-2
+      namespace: envoy-gateway-system
+xdsIR:
+  envoy-gateway/gateway-1:
+    accessLog:
+      json:
+      - path: /dev/stdout
+    http:
+    - address: 0.0.0.0
+      hostnames:
+      - '*'
+      isHTTP2: false
+      metadata:
+        kind: Gateway
+        name: gateway-1
+        namespace: envoy-gateway
+        sectionName: http
+      name: envoy-gateway/gateway-1/http
+      path:
+        escapedSlashesAction: UnescapeAndRedirect
+        mergeSlashes: true
+      port: 10080
+      routes:
+      - destination:
+          name: httproute/default/httproute-1/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            name: httproute/default/httproute-1/rule/0/backend/0
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        metadata:
+          kind: HTTPRoute
+          name: httproute-1
+          namespace: default
+        name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /
+        traffic:
+          backendConnection:
+            bufferLimit: 100000000
+          httpUpgrade:
+          - spdy/3.1
+          - websocket
+          rateLimit:
+            local:
+              default:
+                requests: 4294967295
+                unit: Second
+              rules:
+              - headerMatches:
+                - distinct: false
+                  exact: one
+                  name: x-user-id
+                limit:
+                  requests: 5
+                  unit: Hour
+                name: default/policy-for-route/rule/0
+              - headerMatches:
+                - distinct: false
+                  exact: two
+                  name: x-user-id
+                limit:
+                  requests: 5
+                  unit: Hour
+                name: envoy-gateway/policy-for-gateway1/rule/0
+          timeout:
+            http:
+              connectionIdleTimeout: 16s
+              maxConnectionDuration: 17s
+            tcp:
+              connectTimeout: 10s
+    readyListener:
+      address: 0.0.0.0
+      ipFamily: IPv4
+      path: /ready
+      port: 19003
+  envoy-gateway/gateway-2:
+    accessLog:
+      json:
+      - path: /dev/stdout
+    http:
+    - address: 0.0.0.0
+      hostnames:
+      - '*'
+      isHTTP2: false
+      metadata:
+        kind: Gateway
+        name: gateway-2
+        namespace: envoy-gateway
+        sectionName: http
+      name: envoy-gateway/gateway-2/http
+      path:
+        escapedSlashesAction: UnescapeAndRedirect
+        mergeSlashes: true
+      port: 10080
+      routes:
+      - destination:
+          name: httproute/default/httproute-1/rule/0
+          settings:
+          - addressType: IP
+            endpoints:
+            - host: 7.7.7.7
+              port: 8080
+            name: httproute/default/httproute-1/rule/0/backend/0
+            protocol: HTTP
+            weight: 1
+        hostname: gateway.envoyproxy.io
+        isHTTP2: false
+        metadata:
+          kind: HTTPRoute
+          name: httproute-1
+          namespace: default
+        name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io
+        pathMatch:
+          distinct: false
+          name: ""
+          prefix: /
+        traffic:
+          backendConnection:
+            bufferLimit: 100000000
+          httpUpgrade:
+          - spdy/3.1
+          rateLimit:
+            local:
+              default:
+                requests: 4294967295
+                unit: Second
+              rules:
+              - headerMatches:
+                - distinct: false
+                  exact: one
+                  name: x-user-id
+                limit:
+                  requests: 5
+                  unit: Hour
+                name: default/policy-for-route/rule/0
+          timeout:
+            tcp:
+              connectTimeout: 10s
+    readyListener:
+      address: 0.0.0.0
+      ipFamily: IPv4
+      path: /ready
+      port: 19003
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-with-multi-parents.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-with-multi-parents.out.yaml
index 70ff8aee3..1c466803e 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-with-multi-parents.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge-with-multi-parents.out.yaml
@@ -317,7 +317,6 @@ xdsIR:
           httpUpgrade:
           - spdy/3.1
           - websocket
-          name: default/policy-for-route
           timeout:
             http:
               connectionIdleTimeout: 16s
@@ -375,7 +374,6 @@ xdsIR:
             bufferLimit: 100000000
           httpUpgrade:
           - spdy/3.1
-          name: default/policy-for-route
           timeout:
             tcp:
               connectTimeout: 10s
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge.out.yaml
index 8905ab639..f7cdccc6c 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-strategic-merge.out.yaml
@@ -297,7 +297,6 @@ xdsIR:
           httpUpgrade:
           - spdy/3.1
           - websocket
-          name: default/merged-policy-for-route
           timeout:
             http:
               connectionIdleTimeout: 16s
@@ -324,7 +323,6 @@ xdsIR:
         traffic:
           backendConnection:
             bufferLimit: 100000000
-          name: default/policy-for-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-tracing.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-tracing.out.yaml
index 03a2b28d4..c1996019f 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-tracing.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-tracing.out.yaml
@@ -185,7 +185,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: default/policy-for-route
           telemetry:
             tracing:
               customTags:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-use-client-protocol.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-use-client-protocol.out.yaml
index c03c4cbc1..d3cb4bdd7 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-use-client-protocol.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-use-client-protocol.out.yaml
@@ -164,8 +164,7 @@ xdsIR:
           distinct: false
           name: ""
           prefix: /
-        traffic:
-          name: envoy-gateway/policy-for-gateway
+        traffic: {}
         useClientProtocol: true
     readyListener:
       address: 0.0.0.0
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-circuitbreakers.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-circuitbreakers.out.yaml
index 34f11b574..919e9fdb8 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-circuitbreakers.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-circuitbreakers.out.yaml
@@ -294,7 +294,6 @@ xdsIR:
             maxParallelRetries: 1024
             maxPendingRequests: 1
             maxRequestsPerConnection: 1
-          name: envoy-gateway/policy-for-gateway
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -348,7 +347,6 @@ xdsIR:
             maxParallelRetries: 24
             maxPendingRequests: 42
             maxRequestsPerConnection: 42
-          name: default/policy-for-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-dns-settings.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dns-settings.out.yaml
index c92652e8d..d42ca5614 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-dns-settings.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-dns-settings.out.yaml
@@ -360,7 +360,6 @@ xdsIR:
           dns:
             dnsRefreshRate: 10s
             respectDnsTtl: true
-          name: envoy-gateway/policy-for-all-routes-in-gateway-1
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -411,7 +410,6 @@ xdsIR:
           dns:
             dnsRefreshRate: 5s
             respectDnsTtl: false
-          name: default/policy-for-route-2
       - destination:
           name: httproute/default/httproute-1/rule/0
           settings:
@@ -437,7 +435,6 @@ xdsIR:
           dns:
             dnsRefreshRate: 1s
             respectDnsTtl: true
-          name: default/policy-for-route-1
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck.out.yaml
index 75d73b9a7..96dff6b97 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-healthcheck.out.yaml
@@ -736,7 +736,6 @@ xdsIR:
               interval: 2s
               maxEjectionPercent: 100
               splitExternalLocalOriginErrors: false
-          name: envoy-gateway/policy-for-gateway
       - destination:
           name: grpcroute/default/grpcroute-3/rule/0
           settings:
@@ -763,7 +762,6 @@ xdsIR:
               interval: 3s
               timeout: 1s
               unhealthyThreshold: 3
-          name: default/policy-for-grpc-route-3
       - destination:
           name: grpcroute/default/grpcroute-2/rule/0
           settings:
@@ -789,7 +787,6 @@ xdsIR:
               interval: 3s
               timeout: 1s
               unhealthyThreshold: 3
-          name: default/policy-for-grpc-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -856,7 +853,6 @@ xdsIR:
               interval: 10s
               maxEjectionPercent: 10
               splitExternalLocalOriginErrors: false
-          name: default/policy-for-route-2
       - destination:
           name: httproute/default/httproute-3/rule/0
           settings:
@@ -898,7 +894,6 @@ xdsIR:
               interval: 8ms
               maxEjectionPercent: 11
               splitExternalLocalOriginErrors: false
-          name: default/policy-for-route-3
       - destination:
           name: httproute/default/httproute-4/rule/0
           settings:
@@ -935,7 +930,6 @@ xdsIR:
               interval: 5s
               timeout: 1s
               unhealthyThreshold: 3
-          name: default/policy-for-route-4
       - destination:
           name: httproute/default/httproute-1/rule/0
           settings:
@@ -981,7 +975,6 @@ xdsIR:
               interval: 1s
               maxEjectionPercent: 100
               splitExternalLocalOriginErrors: false
-          name: default/policy-for-route-1
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-http2.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-http2.out.yaml
index a35346675..9b7586837 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-http2.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-http2.out.yaml
@@ -291,7 +291,6 @@ xdsIR:
             initialStreamWindowSize: 1073741824
             maxConcurrentStreams: 500
             resetStreamOnError: false
-          name: envoy-gateway/policy-for-gateway
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -344,7 +343,6 @@ xdsIR:
             initialStreamWindowSize: 524288000
             maxConcurrentStreams: 200
             resetStreamOnError: true
-          name: default/policy-for-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-httproute-timeout.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-httproute-timeout.out.yaml
index d0285325e..de1862159 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-httproute-timeout.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-httproute-timeout.out.yaml
@@ -246,8 +246,7 @@ xdsIR:
           name: ""
           prefix: /
         timeout: 2m10s
-        traffic:
-          name: default/policy-for-http-route-1
+        traffic: {}
         useClientProtocol: true
       - destination:
           name: httproute/default/httproute-2/rule/0
@@ -276,7 +275,6 @@ xdsIR:
             consistentHash:
               cookie:
                 name: test
-          name: envoy-gateway/policy-for-gateway
         useClientProtocol: true
     readyListener:
       address: 0.0.0.0
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml
index 2b69a9bab..3a5678c79 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-loadbalancer.out.yaml
@@ -458,7 +458,6 @@ xdsIR:
         traffic:
           loadBalancer:
             random: {}
-          name: envoy-gateway/policy-for-gateway
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -510,7 +509,6 @@ xdsIR:
             leastRequest:
               slowStart:
                 window: 5m0s
-          name: default/policy-for-route2
       - destination:
           name: httproute/default/httproute-3/rule/0
           settings:
@@ -537,7 +535,6 @@ xdsIR:
             consistentHash:
               cookie:
                 name: test
-          name: default/policy-for-route3
       - destination:
           name: httproute/default/httproute-1/rule/0
           settings:
@@ -564,7 +561,6 @@ xdsIR:
             consistentHash:
               sourceIP: true
               tableSize: 524287
-          name: default/policy-for-route
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit-default-route-level-limit.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit-default-route-level-limit.out.yaml
index 6faf1dd11..fffa3d8ef 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit-default-route-level-limit.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit-default-route-level-limit.out.yaml
@@ -188,7 +188,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: envoy-gateway/policy-for-gateway
           rateLimit:
             local:
               default:
@@ -205,6 +204,7 @@ xdsIR:
                 limit:
                   requests: 10
                   unit: Hour
+                name: envoy-gateway/policy-for-gateway/rule/0
               - cidrMatch:
                   cidr: 192.168.0.0/16
                   distinct: false
@@ -221,6 +221,7 @@ xdsIR:
                 limit:
                   requests: 10
                   unit: Minute
+                name: envoy-gateway/policy-for-gateway/rule/1
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit-distinct-match-type.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit-distinct-match-type.out.yaml
index ad18d6471..bb901670b 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit-distinct-match-type.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit-distinct-match-type.out.yaml
@@ -188,7 +188,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: envoy-gateway/policy-for-gateway
           rateLimit:
             local:
               default:
@@ -204,6 +203,7 @@ xdsIR:
                 limit:
                   requests: 10
                   unit: Hour
+                name: envoy-gateway/policy-for-gateway/rule/0
               - cidrMatch:
                   cidr: 192.168.0.0/16
                   distinct: false
@@ -220,6 +220,7 @@ xdsIR:
                 limit:
                   requests: 10
                   unit: Minute
+                name: envoy-gateway/policy-for-gateway/rule/1
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit.out.yaml
index 1f70bc3c2..7509c8444 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-local-ratelimit.out.yaml
@@ -191,7 +191,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: envoy-gateway/policy-for-gateway
           rateLimit:
             local:
               default:
@@ -208,6 +207,7 @@ xdsIR:
                 limit:
                   requests: 10
                   unit: Hour
+                name: envoy-gateway/policy-for-gateway/rule/1
               - cidrMatch:
                   cidr: 192.168.0.0/16
                   distinct: false
@@ -224,6 +224,7 @@ xdsIR:
                 limit:
                   requests: 10
                   unit: Minute
+                name: envoy-gateway/policy-for-gateway/rule/2
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-panic-threshold.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-panic-threshold.out.yaml
index 5054a6877..cb30f5b23 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-panic-threshold.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-panic-threshold.out.yaml
@@ -356,7 +356,6 @@ xdsIR:
         traffic:
           healthCheck:
             panicThreshold: 80
-          name: envoy-gateway/policy-for-all-routes-in-gateway-1
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -406,7 +405,6 @@ xdsIR:
         traffic:
           healthCheck:
             panicThreshold: 10
-          name: default/policy-for-route-2
       - destination:
           name: httproute/default/httproute-1/rule/0
           settings:
@@ -431,7 +429,6 @@ xdsIR:
         traffic:
           healthCheck:
             panicThreshold: 66
-          name: default/policy-for-route-1
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-proxyprotocol.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-proxyprotocol.out.yaml
index dfadd197e..45e87169d 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-proxyprotocol.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-proxyprotocol.out.yaml
@@ -280,7 +280,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           proxyProtocol:
             version: V1
     readyListener:
@@ -330,7 +329,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: default/policy-for-route
           proxyProtocol:
             version: V2
     readyListener:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml
index c0c8debf2..435096820 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-ratelimit.out.yaml
@@ -312,7 +312,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           rateLimit:
             global:
               rules:
@@ -329,6 +328,7 @@ xdsIR:
                 limit:
                   requests: 10
                   unit: Hour
+                name: envoy-gateway/policy-for-gateway/rule/0
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -376,7 +376,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: default/policy-for-route
           rateLimit:
             global:
               rules:
@@ -390,6 +389,7 @@ xdsIR:
                 limit:
                   requests: 20
                   unit: Hour
+                name: default/policy-for-route/rule/0
                 requestCost:
                   number: 1
                 responseCost:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-response-override.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-response-override.out.yaml
index c7cc354af..15c062a97 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-response-override.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-response-override.out.yaml
@@ -399,7 +399,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: default/policy-for-gateway
           responseOverride:
             name: backendtrafficpolicy/default/policy-for-gateway
             rules:
@@ -470,7 +469,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: default/policy-for-route-1
           responseOverride:
             name: backendtrafficpolicy/default/policy-for-route-1
             rules:
@@ -516,7 +514,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: default/policy-for-route-2
           responseOverride:
             name: backendtrafficpolicy/default/policy-for-route-2
             rules:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-retries.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-retries.out.yaml
index 5b1f96de9..5785fcf00 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-retries.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-retries.out.yaml
@@ -436,7 +436,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           retry:
             perRetry:
               backOff:
@@ -539,7 +538,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: default/policy-for-route-1
           retry:
             numRetries: 5
             perRetry:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-same-prefix-httproutes.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-same-prefix-httproutes.out.yaml
index a449e2ea1..d2ae6de9a 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-same-prefix-httproutes.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-same-prefix-httproutes.out.yaml
@@ -211,7 +211,6 @@ xdsIR:
             maxConnections: 2048
             maxParallelRequests: 4294967295
             maxPendingRequests: 1
-          name: default/policy-for-httproute-1
       - destination:
           name: httproute/default/httproute-1-1/rule/0
           settings:
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-shared-ratelimit.in.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-shared-ratelimit.in.yaml
index 16513852d..3386225ff 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-shared-ratelimit.in.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-shared-ratelimit.in.yaml
@@ -76,7 +76,6 @@ backendTrafficPolicies:
     rateLimit:
       type: Global
       global:
-        shared: true
         rules:
         - clientSelectors:
           - headers:
@@ -90,6 +89,7 @@ backendTrafficPolicies:
           limit:
             requests: 10
             unit: Hour
+          shared: true
 - apiVersion: gateway.envoyproxy.io/v1alpha1
   kind: BackendTrafficPolicy
   metadata:
@@ -103,7 +103,6 @@ backendTrafficPolicies:
     rateLimit:
       type: Global
       global:
-        shared: true
         rules:
         - clientSelectors:
           - sourceCIDR:
@@ -112,6 +111,7 @@ backendTrafficPolicies:
           limit:
             requests: 20
             unit: Hour
+          shared: true
         - clientSelectors:
           - sourceCIDR:
               type: "Distinct"
@@ -119,3 +119,4 @@ backendTrafficPolicies:
           limit:
             requests: 20
             unit: Hour
+          shared: true
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-shared-ratelimit.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-shared-ratelimit.out.yaml
index 2ff5ac392..90a365156 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-shared-ratelimit.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-shared-ratelimit.out.yaml
@@ -16,6 +16,7 @@ backendTrafficPolicies:
           limit:
             requests: 20
             unit: Hour
+          shared: true
         - clientSelectors:
           - sourceCIDR:
               type: Distinct
@@ -23,7 +24,7 @@ backendTrafficPolicies:
           limit:
             requests: 20
             unit: Hour
-        shared: true
+          shared: true
       type: Global
     targetRef:
       group: gateway.networking.k8s.io
@@ -66,7 +67,7 @@ backendTrafficPolicies:
           limit:
             requests: 10
             unit: Hour
-        shared: true
+          shared: true
       type: Global
     targetRef:
       group: gateway.networking.k8s.io
@@ -312,7 +313,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           rateLimit:
             global:
               rules:
@@ -329,7 +329,8 @@ xdsIR:
                 limit:
                   requests: 10
                   unit: Hour
-              shared: true
+                name: envoy-gateway/policy-for-gateway/rule/0
+                shared: true
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
@@ -377,7 +378,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: default/policy-for-route
           rateLimit:
             global:
               rules:
@@ -391,6 +391,8 @@ xdsIR:
                 limit:
                   requests: 20
                   unit: Hour
+                name: default/policy-for-route/rule/0
+                shared: true
               - cidrMatch:
                   cidr: ::/64
                   distinct: true
@@ -401,7 +403,8 @@ xdsIR:
                 limit:
                   requests: 20
                   unit: Hour
-              shared: true
+                name: default/policy-for-route/rule/1
+                shared: true
     readyListener:
       address: 0.0.0.0
       ipFamily: IPv4
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-tcpkeepalive.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-tcpkeepalive.out.yaml
index f614c6eb9..7c9c2587e 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-tcpkeepalive.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-tcpkeepalive.out.yaml
@@ -284,7 +284,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           tcpKeepalive:
             idleTime: 1200
             interval: 60
@@ -336,7 +335,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: default/policy-for-route
           tcpKeepalive:
             idleTime: 10
             interval: 1800
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.out.yaml
index eb123fd10..d8a27d8b0 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout-targetrefs.out.yaml
@@ -272,7 +272,6 @@ xdsIR:
           namespace: envoy-gateway
         name: grpcroute/envoy-gateway/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           timeout:
             http:
               connectionIdleTimeout: 16s
@@ -326,7 +325,6 @@ xdsIR:
           name: ""
           prefix: /
         traffic:
-          name: envoy-gateway/policy-for-gateway
           timeout:
             http:
               connectionIdleTimeout: 16s
diff --git a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml
index 40e234b1f..f567963c6 100644
--- a/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml
+++ b/internal/gatewayapi/testdata/backendtrafficpolicy-with-timeout.out.yaml
@@ -292,7 +292,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           timeout:
             http:
               connectionIdleTimeout: 16s
@@ -348,7 +347,6 @@ xdsIR:
           prefix: /
         timeout: 1s
         traffic:
-          name: default/policy-for-route
           timeout:
             http:
               connectionIdleTimeout: 21s
diff --git a/internal/gatewayapi/testdata/httproute-and-backendtrafficpolicy-with-timeout.out.yaml b/internal/gatewayapi/testdata/httproute-and-backendtrafficpolicy-with-timeout.out.yaml
index 5dffce1c9..3b14a31d9 100644
--- a/internal/gatewayapi/testdata/httproute-and-backendtrafficpolicy-with-timeout.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-and-backendtrafficpolicy-with-timeout.out.yaml
@@ -289,7 +289,6 @@ xdsIR:
           namespace: default
         name: grpcroute/default/grpcroute-1/rule/0/match/-1/*
         traffic:
-          name: envoy-gateway/policy-for-gateway
           timeout:
             http:
               connectionIdleTimeout: 16s
@@ -344,7 +343,6 @@ xdsIR:
           prefix: /
         timeout: 1s
         traffic:
-          name: default/policy-for-route
           timeout:
             http:
               maxConnectionDuration: 22s
diff --git a/internal/gatewayapi/testdata/httproute-retry.out.yaml b/internal/gatewayapi/testdata/httproute-retry.out.yaml
index d252da5b5..2d9e06df3 100644
--- a/internal/gatewayapi/testdata/httproute-retry.out.yaml
+++ b/internal/gatewayapi/testdata/httproute-retry.out.yaml
@@ -310,7 +310,6 @@ xdsIR:
             - 500
         timeout: 3s
         traffic:
-          name: default/policy-for-route
           retry:
             numRetries: 5
             perRetry:
diff --git a/internal/gatewayapi/testdata/merge-with-isolated-policies-2.out.yaml b/internal/gatewayapi/testdata/merge-with-isolated-policies-2.out.yaml
index 4d416250b..4a93a03ed 100644
--- a/internal/gatewayapi/testdata/merge-with-isolated-policies-2.out.yaml
+++ b/internal/gatewayapi/testdata/merge-with-isolated-policies-2.out.yaml
@@ -555,7 +555,6 @@ xdsIR:
             - x-header-8
             maxAge: 33m20s
         traffic:
-          name: default/policy-for-gateway
           tcpKeepalive:
             idleTime: 1200
             interval: 60
@@ -616,7 +615,6 @@ xdsIR:
             - x-header-8
             maxAge: 33m20s
         traffic:
-          name: default/policy-for-gateway
           tcpKeepalive:
             idleTime: 1200
             interval: 60
diff --git a/internal/gatewayapi/testdata/merge-with-isolated-policies.out.yaml b/internal/gatewayapi/testdata/merge-with-isolated-policies.out.yaml
index 501ed5795..b56dfd285 100644
--- a/internal/gatewayapi/testdata/merge-with-isolated-policies.out.yaml
+++ b/internal/gatewayapi/testdata/merge-with-isolated-policies.out.yaml
@@ -347,7 +347,6 @@ xdsIR:
             - x-header-8
             maxAge: 33m20s
         traffic:
-          name: default/policy-for-gateway
           tcpKeepalive:
             idleTime: 1200
             interval: 60
diff --git a/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.in.yaml b/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.in.yaml
index 3dc8eee65..3bf35dc88 100644
--- a/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.in.yaml
+++ b/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.in.yaml
@@ -1,12 +1,12 @@
 kind: BackendTrafficPolicy
 metadata:
-  name: original
+  name: original-1
 spec:
   rateLimit:
     type: Global
     global:
       rules:
-        - name: one
+        - shared: true
           clientSelectors:
             - headers:
                 - name: x-user-id
diff --git a/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.jsonmerge.out.yaml b/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.jsonmerge.out.yaml
index a679b04d1..17f6d2cb0 100644
--- a/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.jsonmerge.out.yaml
+++ b/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.jsonmerge.out.yaml
@@ -1,7 +1,7 @@
 kind: BackendTrafficPolicy
 metadata:
   creationTimestamp: null
-  name: original
+  name: original-2
 spec:
   rateLimit:
     global:
@@ -23,7 +23,7 @@ spec:
         limit:
           requests: 21
           unit: Hour
-        name: two
+        shared: false
     type: Global
 status:
   ancestors: null
diff --git a/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.patch.yaml b/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.patch.yaml
index 2d13bd03b..40b6d9186 100644
--- a/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.patch.yaml
+++ b/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.patch.yaml
@@ -1,12 +1,13 @@
 kind: BackendTrafficPolicy
 metadata:
-  name: original
+  name: original-2
 spec:
   rateLimit:
     type: Global
     global:
       rules:
         - name: two
+          shared: false
           clientSelectors:
             - headers:
                 - name: x-user-id
diff --git a/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.strategicmerge.out.yaml b/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.strategicmerge.out.yaml
index 1833716e3..17f6d2cb0 100644
--- a/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.strategicmerge.out.yaml
+++ b/internal/utils/testdata/backendtrafficpolicy_ratelimitrule_merge.strategicmerge.out.yaml
@@ -1,7 +1,7 @@
 kind: BackendTrafficPolicy
 metadata:
   creationTimestamp: null
-  name: original
+  name: original-2
 spec:
   rateLimit:
     global:
@@ -23,25 +23,7 @@ spec:
         limit:
           requests: 21
           unit: Hour
-        name: two
-      - clientSelectors:
-        - headers:
-          - name: x-user-id
-            type: Exact
-            value: one
-        cost:
-          request:
-            from: Number
-            number: 0
-          response:
-            from: Metadata
-            metadata:
-              key: request_cost_set_by_ext_proc
-              namespace: io.envoyproxy.gateway.e2e
-        limit:
-          requests: 21
-          unit: Hour
-        name: one
+        shared: false
     type: Global
 status:
   ancestors: null
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/distinct-match.yaml b/internal/xds/translator/testdata/in/ratelimit-config/distinct-match.yaml
index 238ad7a6b..7a9a6b0d1 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/distinct-match.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/distinct-match.yaml
@@ -10,11 +10,11 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               distinct: true
             limit:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/distinct-remote-address-match.yaml b/internal/xds/translator/testdata/in/ratelimit-config/distinct-remote-address-match.yaml
index 59b50eadb..1ab9355d9 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/distinct-remote-address-match.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/distinct-remote-address-match.yaml
@@ -10,11 +10,11 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
           rules:
-          - cidrMatch:
+          - name: "test-namespace/test-policy-1/rule/0"
+            cidrMatch:
               cidr: "192.168.0.0/16"
               ipv6: false
               maskLen: 16
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/empty-header-matches.yaml b/internal/xds/translator/testdata/in/ratelimit-config/empty-header-matches.yaml
index 55375b28c..390285f56 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/empty-header-matches.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/empty-header-matches.yaml
@@ -10,11 +10,11 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
           rules:
-          - limit:
+          - name: "test-namespace/test-policy-1/rule/0"
+            limit:
               requests: 5
               unit: second
     pathMatch:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/global-shared-distinct-match.yaml b/internal/xds/translator/testdata/in/ratelimit-config/global-shared-distinct-match.yaml
index 84a159a0f..50929cd84 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/global-shared-distinct-match.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/global-shared-distinct-match.yaml
@@ -10,17 +10,17 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: true
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               distinct: true
             limit:
               requests: 5
               unit: second
+            shared: true
     pathMatch:
       exact: "foo/bar"
     destination:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/global-shared-multiple-shared-policies.yaml b/internal/xds/translator/testdata/in/ratelimit-config/global-shared-multiple-shared-policies.yaml
index a586d563d..a3271bb66 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/global-shared-multiple-shared-policies.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/global-shared-multiple-shared-policies.yaml
@@ -10,58 +10,58 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: true
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "one"
             limit:
               requests: 5
               unit: second
+            shared: true
   - name: "second-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: true
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "one"
             limit:
               requests: 5
               unit: second
+            shared: true
     pathMatch:
       exact: "foo/baz"
   - name: "third-route"
     traffic:
-      name: "test-policy-2/test-namespace"
       rateLimit:
         global:
-          shared: true
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-2/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "two"
             limit:
               requests: 10
               unit: second
+            shared: true
   - name: "fourth-route"
     traffic:
-      name: "test-policy-3/test-namespace"
       rateLimit:
         global:
-          shared: false
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-3/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "three"
             limit:
               requests: 10
               unit: second
+            shared: false
     pathMatch:
       exact: "foo/bar"
     destination:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/header-and-cidr-matches.yaml b/internal/xds/translator/testdata/in/ratelimit-config/header-and-cidr-matches.yaml
index 8849d5b9d..65df64720 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/header-and-cidr-matches.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/header-and-cidr-matches.yaml
@@ -10,11 +10,11 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "one"
             - name: "x-user-id"
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/masked-remote-address-match.yaml b/internal/xds/translator/testdata/in/ratelimit-config/masked-remote-address-match.yaml
index 9756be479..501c3b49d 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/masked-remote-address-match.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/masked-remote-address-match.yaml
@@ -10,11 +10,11 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
           rules:
-          - cidrMatch:
+          - name: "test-namespace/test-policy-1/rule/0"
+            cidrMatch:
               cidr: "192.168.0.0/16"
               ipv6: false
               maskLen: 16
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-domains.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-domains.yaml
index 8321c3cbe..87f60a62b 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/multiple-domains.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-domains.yaml
@@ -10,27 +10,27 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: true
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "one"
             limit:
               requests: 5
               unit: second
+            shared: true
   - name: "second-route"
     traffic:
-      name: "test-policy-2/test-namespace"
       rateLimit:
         global:
-          shared: false
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-2/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "one"
             limit:
               requests: 5
               unit: second
+            shared: false
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-global-shared-distinct-match.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-global-shared-distinct-match.yaml
new file mode 100644
index 000000000..54e33e635
--- /dev/null
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-global-shared-distinct-match.yaml
@@ -0,0 +1,47 @@
+http:
+- name: "first-listener"
+  address: "0.0.0.0"
+  port: 10080
+  hostnames:
+  - "*"
+  path:
+    mergeSlashes: true
+    escapedSlashesAction: UnescapeAndRedirect
+  routes:
+  - name: "first-route"
+    traffic:
+      rateLimit:
+        global:
+          rules:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
+            - name: "x-user-id"
+              distinct: true
+            limit:
+              requests: 5
+              unit: second
+            shared: true
+          - name: "test-namespace/test-policy-1/rule/1"
+            headerMatches:
+            - name: "x-user-id"
+              distinct: true
+            limit:
+              requests: 5
+              unit: second
+            shared: true
+          - name: "test-namespace/test-policy-1/rule/2"
+            headerMatches:
+            - name: "x-user-id"
+              distinct: true
+            limit:
+              requests: 5
+              unit: second
+            shared: true
+    pathMatch:
+      exact: "foo/bar"
+    destination:
+      name: "first-route-dest"
+      settings:
+      - endpoints:
+        - host: "1.2.3.4"
+          port: 50000
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-distinct-match.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-distinct-match.yaml
index 55dc7c79e..ccc36f04a 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-distinct-match.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-distinct-match.yaml
@@ -10,11 +10,11 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               distinct: true
             limit:
@@ -39,11 +39,11 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-2/test-namespace"
       rateLimit:
         global:
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-2/rule/0"
+            headerMatches:
             - name: "x-user-id"
               distinct: true
             limit:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-same-shared-distinct-match.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-same-shared-distinct-match.yaml
index c694042ab..b37bc3220 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-same-shared-distinct-match.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-same-shared-distinct-match.yaml
@@ -10,17 +10,17 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: true
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               distinct: true
             limit:
               requests: 5
               unit: second
+            shared: true
     pathMatch:
       exact: "foo/bar"
     destination:
@@ -40,17 +40,17 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: true
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               distinct: true
             limit:
               requests: 5
               unit: second
+            shared: true
     pathMatch:
       exact: "foo/bar"
     destination:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-shared-distinct-match.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-shared-distinct-match.yaml
index b6d93f8b2..9d4593077 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-shared-distinct-match.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-listeners-shared-distinct-match.yaml
@@ -10,11 +10,12 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
+      name: "test-namespace/test-policy-1"
       rateLimit:
         global:
           rules:
-          - headerMatches:
+          - name: "test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               distinct: true
             limit:
@@ -39,17 +40,17 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-2/test-namespace"
       rateLimit:
         global:
-          shared: true
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-2/rule/0"
+            headerMatches:
             - name: "x-user-id"
               distinct: true
             limit:
               requests: 5
               unit: second
+            shared: true
     pathMatch:
       exact: "foo/bar"
     destination:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-masked-remote-address-match-with-same-cidr.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-masked-remote-address-match-with-same-cidr.yaml
index d98835320..fae723091 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/multiple-masked-remote-address-match-with-same-cidr.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-masked-remote-address-match-with-same-cidr.yaml
@@ -10,18 +10,18 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: false
           rules:
-          - cidrMatch:
+          - name: "test-namespace/test-policy-1/rule/0"
+            cidrMatch:
               cidr: "192.168.0.10/32"
               ipv6: false
               maskLen: 32
             limit:
               requests: 15
               unit: Hour
+            shared: false
     pathMatch:
       exact: "foo/bar"
     destination:
@@ -32,18 +32,18 @@ http:
           port: 50000
   - name: "second-route"
     traffic:
-      name: "test-policy-2/test-namespace"
       rateLimit:
         global:
-          shared: false
           rules:
-          - cidrMatch:
+          - name: "test-namespace/test-policy-2/rule/0"
+            cidrMatch:
               cidr: "192.168.0.10/32"
               ipv6: false
               maskLen: 32
             limit:
               requests: 300
               unit: Hour
+            shared: false
     pathMatch:
       exact: "foo/bar"
     destination:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-matches.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-matches.yaml
index 15a90087a..2da0e13a5 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/multiple-matches.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-matches.yaml
@@ -10,12 +10,11 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: false
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "one"
             - name: "x-user-id"
@@ -23,6 +22,7 @@ http:
             limit:
               requests: 5
               unit: second
+            shared: false
     pathMatch:
       exact: "foo/bar"
     destination:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-routes.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-routes.yaml
index 0a6a885c7..909b2388e 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/multiple-routes.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-routes.yaml
@@ -10,12 +10,12 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
           shared: false
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "one"
             limit:
@@ -25,12 +25,12 @@ http:
       exact: "foo/baz"
   - name: "second-route"
     traffic:
-      name: "test-policy-2/test-namespace"
       rateLimit:
         global:
           shared: false
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-2/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "two"
             limit:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-rules.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-rules.yaml
index 92817339d..351dcf2fa 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/multiple-rules.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-rules.yaml
@@ -10,23 +10,25 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: false
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "one"
             limit:
               requests: 5
               unit: second
-          - headerMatches:
+            shared: false
+          - name: "test-namespace/test-policy-1/rule/1"
+            headerMatches:
             - name: "x-user-id"
               exact: "two"
             limit:
               requests: 10
               unit: second
+            shared: false
     pathMatch:
       exact: "foo/bar"
     destination:
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-shared-and-unshared.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-shared-and-unshared.yaml
new file mode 100644
index 000000000..e70a5ecd8
--- /dev/null
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-shared-and-unshared.yaml
@@ -0,0 +1,47 @@
+http:
+- name: "first-listener"
+  address: "0.0.0.0"
+  port: 10080
+  hostnames:
+  - "*"
+  path:
+    mergeSlashes: true
+    escapedSlashesAction: UnescapeAndRedirect
+  routes:
+  - name: "first-route"
+    traffic:
+      rateLimit:
+        global:
+          rules:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
+            - name: "x-user-id"
+              exact: "one"
+            limit:
+              requests: 5
+              unit: second
+            shared: true
+          - name: "test-namespace/test-policy-1/rule/1"
+            headerMatches:
+            - name: "x-user-id"
+              exact: "two"
+            limit:
+              requests: 5
+              unit: second
+            shared: false
+          - name: "test-namespace/test-policy-1/rule/2"
+            headerMatches:
+            - name: "x-user-id"
+              exact: "three"
+            limit:
+              requests: 5
+              unit: second
+            shared: true
+          - name: "test-namespace/test-policy-1/rule/3"
+            headerMatches:
+            - name: "x-user-id"
+              exact: "four"
+            limit:
+              requests: 5
+              unit: second
+            shared: false
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/multiple-shared-ratelimit-rules.yaml b/internal/xds/translator/testdata/in/ratelimit-config/multiple-shared-ratelimit-rules.yaml
new file mode 100644
index 000000000..77fc67e7a
--- /dev/null
+++ b/internal/xds/translator/testdata/in/ratelimit-config/multiple-shared-ratelimit-rules.yaml
@@ -0,0 +1,47 @@
+http:
+- name: "first-listener"
+  address: "0.0.0.0"
+  port: 10080
+  hostnames:
+  - "*"
+  path:
+    mergeSlashes: true
+    escapedSlashesAction: UnescapeAndRedirect
+  routes:
+  - name: "first-route"
+    traffic:
+      rateLimit:
+        global:
+          rules:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
+            - name: "x-user-id"
+              exact: "one"
+            limit:
+              requests: 1
+              unit: second
+            shared: true
+          - name: "test-namespace/test-policy-1/rule/1"
+            headerMatches:
+            - name: "x-user-id"
+              exact: "two"
+            limit:
+              requests: 2
+              unit: second
+            shared: true
+          - name: "test-namespace/test-policy-1/rule/2"
+            headerMatches:
+            - name: "x-user-id"
+              exact: "three"
+            limit:
+              requests: 3
+              unit: second
+            shared: false
+    pathMatch:
+      exact: "foo/bar"
+    destination:
+      name: "first-route-dest"
+      settings:
+      - endpoints:
+        - host: "1.2.3.4"
+          port: 50000
diff --git a/internal/xds/translator/testdata/in/ratelimit-config/value-match.yaml b/internal/xds/translator/testdata/in/ratelimit-config/value-match.yaml
index 2f27cd072..2e0dcf966 100644
--- a/internal/xds/translator/testdata/in/ratelimit-config/value-match.yaml
+++ b/internal/xds/translator/testdata/in/ratelimit-config/value-match.yaml
@@ -10,17 +10,17 @@ http:
   routes:
   - name: "first-route"
     traffic:
-      name: "test-policy-1/test-namespace"
       rateLimit:
         global:
-          shared: false
           rules:
-          - headerMatches:
+          - name: "test-namespace/test-policy-1/rule/0"
+            headerMatches:
             - name: "x-user-id"
               exact: "one"
             limit:
               requests: 5
               unit: second
+            shared: false
     pathMatch:
       exact: "foo/bar"
     destination:
diff --git a/internal/xds/translator/testdata/in/xds-ir/ratelimit-global-shared.yaml b/internal/xds/translator/testdata/in/xds-ir/ratelimit-global-shared.yaml
index 8d59e27bc..2b36d593e 100644
--- a/internal/xds/translator/testdata/in/xds-ir/ratelimit-global-shared.yaml
+++ b/internal/xds/translator/testdata/in/xds-ir/ratelimit-global-shared.yaml
@@ -13,17 +13,18 @@ http:
       - name: "first-route"
         hostname: "*"
         traffic:
-          name: "test-policy-1/test-namespace"
+          name: "test-namespace/test-policy-1"
           rateLimit:
             global:
-              shared: true
               rules:
-                - headerMatches:
+                - name: "test-namespace/test-policy-1/rule/0"
+                  headerMatches:
                     - name: "x-user-id"
                       exact: "one"
                   limit:
                     requests: 5
                     unit: second
+                  shared: true
         pathMatch:
           exact: "foo/bar"
         destination:
@@ -37,17 +38,18 @@ http:
       - name: "second-route"
         hostname: "*"
         traffic:
-          name: "test-policy-1/test-namespace"
+          name: "test-namespace/test-policy-1"
           rateLimit:
             global:
-              shared: true
               rules:
-                - headerMatches:
+                - name: "test-namespace/test-policy-1/rule/0"
+                  headerMatches:
                     - name: "x-user-id"
                       exact: "one"
                   limit:
                     requests: 5
                     unit: second
+                  shared: true
         pathMatch:
           exact: "foo/baz"
         destination:
@@ -61,17 +63,18 @@ http:
       - name: "third-route"
         hostname: "*"
         traffic:
-          name: "test-policy-2/test-namespace"
+          name: "test-namespace/test-policy-2"
           rateLimit:
             global:
-              shared: true
               rules:
-                - headerMatches:
+                - name: "test-namespace/test-policy-2/rule/0"
+                  headerMatches:
                     - name: "x-user-id"
                       exact: "two"
                   limit:
                     requests: 10
                     unit: second
+                  shared: true
         pathMatch:
           exact: "test"
         destination:
@@ -85,17 +88,18 @@ http:
       - name: "fourth-route"
         hostname: "*"
         traffic:
-          name: "test-policy-3/test-namespace"
+          name: "test-namespace/test-policy-3"
           rateLimit:
             global:
-              shared: false
               rules:
-                - headerMatches:
+                - name: "test-namespace/test-policy-3/rule/0"
+                  headerMatches:
                     - name: "x-user-id"
                       exact: "two"
                   limit:
                     requests: 10
                     unit: second
+                  shared: false
         pathMatch:
           exact: "foo/bar"
         destination:
diff --git a/internal/xds/translator/testdata/in/xds-ir/ratelimit-multi-global-shared.yaml b/internal/xds/translator/testdata/in/xds-ir/ratelimit-multi-global-shared.yaml
new file mode 100644
index 000000000..ebd57e1ad
--- /dev/null
+++ b/internal/xds/translator/testdata/in/xds-ir/ratelimit-multi-global-shared.yaml
@@ -0,0 +1,94 @@
+metrics:
+  enablePerEndpointStats: true
+http:
+  - name: "first-listener"
+    address: "::"
+    port: 10080
+    hostnames:
+      - "*"
+    path:
+      mergeSlashes: true
+      escapedSlashesAction: UnescapeAndRedirect
+    routes:
+      - name: "first-route"
+        hostname: "*"
+        traffic:
+          name: "test-namespace/test-policy-1"
+          rateLimit:
+            global:
+              rules:
+                - name: "test-namespace/test-policy-1/rule/0"
+                  headerMatches:
+                    - name: "x-user-id"
+                      exact: "one"
+                  limit:
+                    requests: 5
+                    unit: second
+                  shared: true
+        pathMatch:
+          exact: "foo/bar"
+        destination:
+          name: "first-route-dest"
+          settings:
+            - endpoints:
+                - host: "1.2.3.4"
+                  port: 50000
+              name: "first-route-dest/backend/0"
+
+      - name: "second-route"
+        hostname: "*"
+        traffic:
+          name: "test-namespace/test-policy-1"
+          rateLimit:
+            global:
+              rules:
+                - name: "test-namespace/test-policy-1/rule/0"
+                  headerMatches:
+                    - name: "x-user-id"
+                      exact: "one"
+                  limit:
+                    requests: 5
+                    unit: second
+                  shared: true
+        pathMatch:
+          exact: "foo/baz"
+        destination:
+          name: "second-route-dest"
+          settings:
+            - endpoints:
+                - host: "1.2.3.4"
+                  port: 50000
+              name: "second-route-dest/backend/0"
+
+      - name: "third-route"
+        hostname: "*"
+        traffic:
+          name: "test-namespace/test-policy-2"
+          rateLimit:
+            global:
+              rules:
+                - name: "test-namespace/test-policy-2/rule/0"
+                  headerMatches:
+                    - name: "x-user-id"
+                      exact: "two"
+                  limit:
+                    requests: 10
+                    unit: second
+                  shared: true
+                - name: "test-namespace/test-policy-2/rule/1"
+                  headerMatches:
+                    - name: "x-user-id"
+                      exact: "two"
+                  limit:
+                    requests: 10
+                    unit: second
+                  shared: true
+        pathMatch:
+          exact: "test"
+        destination:
+          name: "third-route-dest"
+          settings:
+            - endpoints:
+                - host: "1.2.3.4"
+                  port: 50000
+              name: "third-route-dest/backend/0"
diff --git a/internal/xds/translator/testdata/out/ratelimit-config/global-shared-distinct-match.yaml b/internal/xds/translator/testdata/out/ratelimit-config/global-shared-distinct-match.yaml
index 62a2ad78f..936dc97f4 100644
--- a/internal/xds/translator/testdata/out/ratelimit-config/global-shared-distinct-match.yaml
+++ b/internal/xds/translator/testdata/out/ratelimit-config/global-shared-distinct-match.yaml
@@ -1,8 +1,8 @@
-name: test-policy-1-test-namespace
-domain: test-policy-1-test-namespace
+name: test-namespace/test-policy-1
+domain: test-namespace/test-policy-1
 descriptors:
-  - key: test-policy-1/test-namespace
-    value: test-policy-1/test-namespace
+  - key: test-namespace/test-policy-1/rule/0
+    value: test-namespace/test-policy-1/rule/0
     rate_limit: null
     descriptors:
       - key: rule-0-match-0
diff --git a/internal/xds/translator/testdata/out/ratelimit-config/global-shared-multiple-shared-policies.yaml b/internal/xds/translator/testdata/out/ratelimit-config/global-shared-multiple-shared-policies.yaml
index 83ebd9a9b..5325d2fc0 100644
--- a/internal/xds/translator/testdata/out/ratelimit-config/global-shared-multiple-shared-policies.yaml
+++ b/internal/xds/translator/testdata/out/ratelimit-config/global-shared-multiple-shared-policies.yaml
@@ -19,11 +19,11 @@ descriptors:
     shadow_mode: false
     detailed_metric: false
 ---
-name: test-policy-1-test-namespace
-domain: test-policy-1-test-namespace
+name: test-namespace/test-policy-1
+domain: test-namespace/test-policy-1
 descriptors:
-  - key: test-policy-1/test-namespace
-    value: test-policy-1/test-namespace
+  - key: test-namespace/test-policy-1/rule/0
+    value: test-namespace/test-policy-1/rule/0
     rate_limit: null
     descriptors:
       - key: rule-0-match-0
@@ -40,11 +40,11 @@ descriptors:
     shadow_mode: false
     detailed_metric: false
 ---
-name: test-policy-2-test-namespace
-domain: test-policy-2-test-namespace
+name: test-namespace/test-policy-2
+domain: test-namespace/test-policy-2
 descriptors:
-  - key: test-policy-2/test-namespace
-    value: test-policy-2/test-namespace
+  - key: test-namespace/test-policy-2/rule/0
+    value: test-namespace/test-policy-2/rule/0
     rate_limit: null
     descriptors:
       - key: rule-0-match-0
diff --git a/internal/xds/translator/testdata/out/ratelimit-config/multiple-domains.yaml b/internal/xds/translator/testdata/out/ratelimit-config/multiple-domains.yaml
index 0562531e1..af737a0a2 100644
--- a/internal/xds/translator/testdata/out/ratelimit-config/multiple-domains.yaml
+++ b/internal/xds/translator/testdata/out/ratelimit-config/multiple-domains.yaml
@@ -19,11 +19,11 @@ descriptors:
     shadow_mode: false
     detailed_metric: false
 ---
-name: test-policy-1-test-namespace
-domain: test-policy-1-test-namespace
+name: test-namespace/test-policy-1
+domain: test-namespace/test-policy-1
 descriptors:
-  - key: test-policy-1/test-namespace
-    value: test-policy-1/test-namespace
+  - key: test-namespace/test-policy-1/rule/0
+    value: test-namespace/test-policy-1/rule/0
     rate_limit: null
     descriptors:
       - key: rule-0-match-0
diff --git a/internal/xds/translator/testdata/out/ratelimit-config/multiple-global-shared-distinct-match.yaml b/internal/xds/translator/testdata/out/ratelimit-config/multiple-global-shared-distinct-match.yaml
new file mode 100644
index 000000000..82ec4f708
--- /dev/null
+++ b/internal/xds/translator/testdata/out/ratelimit-config/multiple-global-shared-distinct-match.yaml
@@ -0,0 +1,54 @@
+name: test-namespace/test-policy-1
+domain: test-namespace/test-policy-1
+descriptors:
+  - key: test-namespace/test-policy-1/rule/0
+    value: test-namespace/test-policy-1/rule/0
+    rate_limit: null
+    descriptors:
+      - key: rule-0-match-0
+        value: ""
+        rate_limit:
+          requests_per_unit: 5
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+    shadow_mode: false
+    detailed_metric: false
+  - key: test-namespace/test-policy-1/rule/1
+    value: test-namespace/test-policy-1/rule/1
+    rate_limit: null
+    descriptors:
+      - key: rule-1-match-0
+        value: ""
+        rate_limit:
+          requests_per_unit: 5
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+    shadow_mode: false
+    detailed_metric: false
+  - key: test-namespace/test-policy-1/rule/2
+    value: test-namespace/test-policy-1/rule/2
+    rate_limit: null
+    descriptors:
+      - key: rule-2-match-0
+        value: ""
+        rate_limit:
+          requests_per_unit: 5
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+    shadow_mode: false
+    detailed_metric: false
diff --git a/internal/xds/translator/testdata/out/ratelimit-config/multiple-listeners-same-shared-distinct-match.yaml b/internal/xds/translator/testdata/out/ratelimit-config/multiple-listeners-same-shared-distinct-match.yaml
index 62a2ad78f..936dc97f4 100644
--- a/internal/xds/translator/testdata/out/ratelimit-config/multiple-listeners-same-shared-distinct-match.yaml
+++ b/internal/xds/translator/testdata/out/ratelimit-config/multiple-listeners-same-shared-distinct-match.yaml
@@ -1,8 +1,8 @@
-name: test-policy-1-test-namespace
-domain: test-policy-1-test-namespace
+name: test-namespace/test-policy-1
+domain: test-namespace/test-policy-1
 descriptors:
-  - key: test-policy-1/test-namespace
-    value: test-policy-1/test-namespace
+  - key: test-namespace/test-policy-1/rule/0
+    value: test-namespace/test-policy-1/rule/0
     rate_limit: null
     descriptors:
       - key: rule-0-match-0
diff --git a/internal/xds/translator/testdata/out/ratelimit-config/multiple-listeners-shared-distinct-match.yaml b/internal/xds/translator/testdata/out/ratelimit-config/multiple-listeners-shared-distinct-match.yaml
index 50b14f478..e7379e4af 100644
--- a/internal/xds/translator/testdata/out/ratelimit-config/multiple-listeners-shared-distinct-match.yaml
+++ b/internal/xds/translator/testdata/out/ratelimit-config/multiple-listeners-shared-distinct-match.yaml
@@ -19,11 +19,11 @@ descriptors:
     shadow_mode: false
     detailed_metric: false
 ---
-name: test-policy-2-test-namespace
-domain: test-policy-2-test-namespace
+name: test-namespace/test-policy-2
+domain: test-namespace/test-policy-2
 descriptors:
-  - key: test-policy-2/test-namespace
-    value: test-policy-2/test-namespace
+  - key: test-namespace/test-policy-2/rule/0
+    value: test-namespace/test-policy-2/rule/0
     rate_limit: null
     descriptors:
       - key: rule-0-match-0
diff --git a/internal/xds/translator/testdata/out/ratelimit-config/multiple-shared-and-unshared.yaml b/internal/xds/translator/testdata/out/ratelimit-config/multiple-shared-and-unshared.yaml
new file mode 100644
index 000000000..c02c4f20f
--- /dev/null
+++ b/internal/xds/translator/testdata/out/ratelimit-config/multiple-shared-and-unshared.yaml
@@ -0,0 +1,69 @@
+name: first-listener
+domain: first-listener
+descriptors:
+  - key: first-route
+    value: first-route
+    rate_limit: null
+    descriptors:
+      - key: rule-0-match-0
+        value: rule-0-match-0
+        rate_limit:
+          requests_per_unit: 5
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+      - key: rule-1-match-0
+        value: rule-1-match-0
+        rate_limit:
+          requests_per_unit: 5
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+    shadow_mode: false
+    detailed_metric: false
+---
+name: test-namespace/test-policy-1
+domain: test-namespace/test-policy-1
+descriptors:
+  - key: test-namespace/test-policy-1/rule/0
+    value: test-namespace/test-policy-1/rule/0
+    rate_limit: null
+    descriptors:
+      - key: rule-0-match-0
+        value: rule-0-match-0
+        rate_limit:
+          requests_per_unit: 5
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+    shadow_mode: false
+    detailed_metric: false
+  - key: test-namespace/test-policy-1/rule/2
+    value: test-namespace/test-policy-1/rule/2
+    rate_limit: null
+    descriptors:
+      - key: rule-1-match-0
+        value: rule-1-match-0
+        rate_limit:
+          requests_per_unit: 5
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+    shadow_mode: false
+    detailed_metric: false
diff --git a/internal/xds/translator/testdata/out/ratelimit-config/multiple-shared-ratelimit-rules.yaml b/internal/xds/translator/testdata/out/ratelimit-config/multiple-shared-ratelimit-rules.yaml
new file mode 100644
index 000000000..ecb7e8ca8
--- /dev/null
+++ b/internal/xds/translator/testdata/out/ratelimit-config/multiple-shared-ratelimit-rules.yaml
@@ -0,0 +1,58 @@
+name: first-listener
+domain: first-listener
+descriptors:
+  - key: first-route
+    value: first-route
+    rate_limit: null
+    descriptors:
+      - key: rule-0-match-0
+        value: rule-0-match-0
+        rate_limit:
+          requests_per_unit: 3
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+    shadow_mode: false
+    detailed_metric: false
+---
+name: test-namespace/test-policy-1
+domain: test-namespace/test-policy-1
+descriptors:
+  - key: test-namespace/test-policy-1/rule/0
+    value: test-namespace/test-policy-1/rule/0
+    rate_limit: null
+    descriptors:
+      - key: rule-0-match-0
+        value: rule-0-match-0
+        rate_limit:
+          requests_per_unit: 1
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+    shadow_mode: false
+    detailed_metric: false
+  - key: test-namespace/test-policy-1/rule/1
+    value: test-namespace/test-policy-1/rule/1
+    rate_limit: null
+    descriptors:
+      - key: rule-1-match-0
+        value: rule-1-match-0
+        rate_limit:
+          requests_per_unit: 2
+          unit: SECOND
+          unlimited: false
+          name: ""
+          replaces: []
+        descriptors: []
+        shadow_mode: false
+        detailed_metric: false
+    shadow_mode: false
+    detailed_metric: false
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.listeners.yaml
index 36c9cd543..fd03d88dc 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.listeners.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.listeners.yaml
@@ -14,20 +14,20 @@
           initialStreamWindowSize: 65536
           maxConcurrentStreams: 100
         httpFilters:
-        - name: envoy.filters.http.ratelimit/test-policy-1/test-namespace
+        - name: envoy.filters.http.ratelimit/test-namespace/test-policy-1
           typedConfig:
             '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
-            domain: test-policy-1-test-namespace
+            domain: test-namespace/test-policy-1
             enableXRatelimitHeaders: DRAFT_VERSION_03
             rateLimitService:
               grpcService:
                 envoyGrpc:
                   clusterName: ratelimit_cluster
               transportApiVersion: V3
-        - name: envoy.filters.http.ratelimit/test-policy-2/test-namespace
+        - name: envoy.filters.http.ratelimit/test-namespace/test-policy-2
           typedConfig:
             '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
-            domain: test-policy-2-test-namespace
+            domain: test-namespace/test-policy-2
             enableXRatelimitHeaders: DRAFT_VERSION_03
             rateLimitService:
               grpcService:
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.routes.yaml
index 6eeb9bee6..935fb21d8 100644
--- a/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.routes.yaml
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-global-shared.routes.yaml
@@ -13,8 +13,8 @@
         rateLimits:
         - actions:
           - genericKey:
-              descriptorKey: test-policy-1/test-namespace
-              descriptorValue: test-policy-1/test-namespace
+              descriptorKey: test-namespace/test-policy-1/rule/0
+              descriptorValue: test-namespace/test-policy-1/rule/0
           - headerValueMatch:
               descriptorKey: rule-0-match-0
               descriptorValue: rule-0-match-0
@@ -33,8 +33,8 @@
         rateLimits:
         - actions:
           - genericKey:
-              descriptorKey: test-policy-1/test-namespace
-              descriptorValue: test-policy-1/test-namespace
+              descriptorKey: test-namespace/test-policy-1/rule/0
+              descriptorValue: test-namespace/test-policy-1/rule/0
           - headerValueMatch:
               descriptorKey: rule-0-match-0
               descriptorValue: rule-0-match-0
@@ -53,8 +53,8 @@
         rateLimits:
         - actions:
           - genericKey:
-              descriptorKey: test-policy-2/test-namespace
-              descriptorValue: test-policy-2/test-namespace
+              descriptorKey: test-namespace/test-policy-2/rule/0
+              descriptorValue: test-namespace/test-policy-2/rule/0
           - headerValueMatch:
               descriptorKey: rule-0-match-0
               descriptorValue: rule-0-match-0
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.clusters.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.clusters.yaml
new file mode 100644
index 000000000..87afaadd1
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.clusters.yaml
@@ -0,0 +1,105 @@
+- circuitBreakers:
+    thresholds:
+    - maxRetries: 1024
+  commonLbConfig:
+    localityWeightedLbConfig: {}
+  connectTimeout: 10s
+  dnsLookupFamily: V4_PREFERRED
+  edsClusterConfig:
+    edsConfig:
+      ads: {}
+      resourceApiVersion: V3
+    serviceName: first-route-dest
+  ignoreHealthOnHostRemoval: true
+  lbPolicy: LEAST_REQUEST
+  name: first-route-dest
+  perConnectionBufferLimitBytes: 32768
+  trackClusterStats:
+    perEndpointStats: true
+  type: EDS
+- circuitBreakers:
+    thresholds:
+    - maxRetries: 1024
+  commonLbConfig:
+    localityWeightedLbConfig: {}
+  connectTimeout: 10s
+  dnsLookupFamily: V4_PREFERRED
+  edsClusterConfig:
+    edsConfig:
+      ads: {}
+      resourceApiVersion: V3
+    serviceName: second-route-dest
+  ignoreHealthOnHostRemoval: true
+  lbPolicy: LEAST_REQUEST
+  name: second-route-dest
+  perConnectionBufferLimitBytes: 32768
+  trackClusterStats:
+    perEndpointStats: true
+  type: EDS
+- circuitBreakers:
+    thresholds:
+    - maxRetries: 1024
+  commonLbConfig:
+    localityWeightedLbConfig: {}
+  connectTimeout: 10s
+  dnsLookupFamily: V4_PREFERRED
+  edsClusterConfig:
+    edsConfig:
+      ads: {}
+      resourceApiVersion: V3
+    serviceName: third-route-dest
+  ignoreHealthOnHostRemoval: true
+  lbPolicy: LEAST_REQUEST
+  name: third-route-dest
+  perConnectionBufferLimitBytes: 32768
+  trackClusterStats:
+    perEndpointStats: true
+  type: EDS
+- circuitBreakers:
+    thresholds:
+    - maxRetries: 1024
+  commonLbConfig:
+    localityWeightedLbConfig: {}
+  connectTimeout: 10s
+  dnsLookupFamily: V4_PREFERRED
+  dnsRefreshRate: 30s
+  lbPolicy: LEAST_REQUEST
+  loadAssignment:
+    clusterName: ratelimit_cluster
+    endpoints:
+    - lbEndpoints:
+      - endpoint:
+          address:
+            socketAddress:
+              address: envoy-ratelimit.envoy-gateway-system.svc.cluster.local
+              portValue: 8081
+        loadBalancingWeight: 1
+      loadBalancingWeight: 1
+      locality:
+        region: ratelimit_cluster/backend/-1
+  name: ratelimit_cluster
+  perConnectionBufferLimitBytes: 32768
+  respectDnsTtl: true
+  trackClusterStats:
+    perEndpointStats: true
+  transportSocket:
+    name: envoy.transport_sockets.tls
+    typedConfig:
+      '@type': type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
+      commonTlsContext:
+        tlsCertificates:
+        - certificateChain:
+            filename: /certs/tls.crt
+          privateKey:
+            filename: /certs/tls.key
+        validationContext:
+          trustedCa:
+            filename: /certs/ca.crt
+  type: STRICT_DNS
+  typedExtensionProtocolOptions:
+    envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
+      '@type': type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
+      explicitHttpConfig:
+        http2ProtocolOptions:
+          initialConnectionWindowSize: 1048576
+          initialStreamWindowSize: 65536
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.endpoints.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.endpoints.yaml
new file mode 100644
index 000000000..475b89a08
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.endpoints.yaml
@@ -0,0 +1,36 @@
+- clusterName: first-route-dest
+  endpoints:
+  - lbEndpoints:
+    - endpoint:
+        address:
+          socketAddress:
+            address: 1.2.3.4
+            portValue: 50000
+      loadBalancingWeight: 1
+    loadBalancingWeight: 1
+    locality:
+      region: first-route-dest/backend/0
+- clusterName: second-route-dest
+  endpoints:
+  - lbEndpoints:
+    - endpoint:
+        address:
+          socketAddress:
+            address: 1.2.3.4
+            portValue: 50000
+      loadBalancingWeight: 1
+    loadBalancingWeight: 1
+    locality:
+      region: second-route-dest/backend/0
+- clusterName: third-route-dest
+  endpoints:
+  - lbEndpoints:
+    - endpoint:
+        address:
+          socketAddress:
+            address: 1.2.3.4
+            portValue: 50000
+      loadBalancingWeight: 1
+    loadBalancingWeight: 1
+    locality:
+      region: third-route-dest/backend/0
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.listeners.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.listeners.yaml
new file mode 100644
index 000000000..0e7613089
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.listeners.yaml
@@ -0,0 +1,54 @@
+- address:
+    socketAddress:
+      address: '::'
+      portValue: 10080
+  defaultFilterChain:
+    filters:
+    - name: envoy.filters.network.http_connection_manager
+      typedConfig:
+        '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
+        commonHttpProtocolOptions:
+          headersWithUnderscoresAction: REJECT_REQUEST
+        http2ProtocolOptions:
+          initialConnectionWindowSize: 1048576
+          initialStreamWindowSize: 65536
+          maxConcurrentStreams: 100
+        httpFilters:
+        - name: envoy.filters.http.ratelimit/test-namespace/test-policy-1
+          typedConfig:
+            '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
+            domain: test-namespace/test-policy-1
+            enableXRatelimitHeaders: DRAFT_VERSION_03
+            rateLimitService:
+              grpcService:
+                envoyGrpc:
+                  clusterName: ratelimit_cluster
+              transportApiVersion: V3
+        - name: envoy.filters.http.ratelimit/test-namespace/test-policy-2
+          typedConfig:
+            '@type': type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
+            domain: test-namespace/test-policy-2
+            enableXRatelimitHeaders: DRAFT_VERSION_03
+            rateLimitService:
+              grpcService:
+                envoyGrpc:
+                  clusterName: ratelimit_cluster
+              transportApiVersion: V3
+        - name: envoy.filters.http.router
+          typedConfig:
+            '@type': type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
+            suppressEnvoyHeaders: true
+        mergeSlashes: true
+        normalizePath: true
+        pathWithEscapedSlashesAction: UNESCAPE_AND_REDIRECT
+        rds:
+          configSource:
+            ads: {}
+            resourceApiVersion: V3
+          routeConfigName: first-listener
+        serverHeaderTransformation: PASS_THROUGH
+        statPrefix: http-10080
+        useRemoteAddress: true
+    name: first-listener
+  name: first-listener
+  perConnectionBufferLimitBytes: 32768
diff --git a/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.routes.yaml b/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.routes.yaml
new file mode 100644
index 000000000..9ebf1dd63
--- /dev/null
+++ b/internal/xds/translator/testdata/out/xds-ir/ratelimit-multi-global-shared.routes.yaml
@@ -0,0 +1,79 @@
+- ignorePortInHostMatching: true
+  name: first-listener
+  virtualHosts:
+  - domains:
+    - '*'
+    name: first-listener/*
+    routes:
+    - match:
+        path: foo/bar
+      name: first-route
+      route:
+        cluster: first-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: test-namespace/test-policy-1/rule/0
+              descriptorValue: test-namespace/test-policy-1/rule/0
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
+        upgradeConfigs:
+        - upgradeType: websocket
+    - match:
+        path: foo/baz
+      name: second-route
+      route:
+        cluster: second-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: test-namespace/test-policy-1/rule/0
+              descriptorValue: test-namespace/test-policy-1/rule/0
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: one
+        upgradeConfigs:
+        - upgradeType: websocket
+    - match:
+        path: test
+      name: third-route
+      route:
+        cluster: third-route-dest
+        rateLimits:
+        - actions:
+          - genericKey:
+              descriptorKey: test-namespace/test-policy-2/rule/0
+              descriptorValue: test-namespace/test-policy-2/rule/0
+          - headerValueMatch:
+              descriptorKey: rule-0-match-0
+              descriptorValue: rule-0-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: two
+        - actions:
+          - genericKey:
+              descriptorKey: test-namespace/test-policy-2/rule/1
+              descriptorValue: test-namespace/test-policy-2/rule/1
+          - headerValueMatch:
+              descriptorKey: rule-1-match-0
+              descriptorValue: rule-1-match-0
+              expectMatch: true
+              headers:
+              - name: x-user-id
+                stringMatch:
+                  exact: two
+        upgradeConfigs:
+        - upgradeType: websocket
diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md
index 580c34083..8e7da3240 100644
--- a/site/content/en/latest/api/extension_types.md
+++ b/site/content/en/latest/api/extension_types.md
@@ -3870,10 +3870,10 @@ _Appears in:_
 
 | Field | Type | Required | Default | Description |
 | ---   | ---  | ---      | ---     | ---         |
-| `name` | _string_ |  false  |  | Name is the name of the rule. This is used to identify the rule<br />in the Envoy configuration and as a unique identifier for merging. |
 | `clientSelectors` | _[RateLimitSelectCondition](#ratelimitselectcondition) array_ |  false  |  | ClientSelectors holds the list of select conditions to select<br />specific clients using attributes from the traffic flow.<br />All individual select conditions must hold True for this rule<br />and its limit to be applied.<br />If no client selectors are specified, the rule applies to all traffic of<br />the targeted Route.<br />If the policy targets a Gateway, the rule applies to each Route of the Gateway.<br />Please note that each Route has its own rate limit counters. For example,<br />if a Gateway has two Routes, and the policy has a rule with limit 10rps,<br />each Route will have its own 10rps limit. |
 | `limit` | _[RateLimitValue](#ratelimitvalue)_ |  true  |  | Limit holds the rate limit values.<br />This limit is applied for traffic flows when the selectors<br />compute to True, causing the request to be counted towards the limit.<br />The limit is enforced and the request is ratelimited, i.e. a response with<br />429 HTTP status code is sent back to the client when<br />the selected requests have reached the limit. |
 | `cost` | _[RateLimitCost](#ratelimitcost)_ |  false  |  | Cost specifies the cost of requests and responses for the rule.<br />This is optional and if not specified, the default behavior is to reduce the rate limit counters by 1 on<br />the request path and do not reduce the rate limit counters on the response path. |
+| `shared` | _boolean_ |  false  |  | Shared determines whether this rate limit rule applies across all the policy targets.<br />If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).<br />Default: false. |
 
 
 #### RateLimitSelectCondition
diff --git a/site/content/en/latest/tasks/quickstart.md b/site/content/en/latest/tasks/quickstart.md
index e1943c21e..14a74ca52 100644
--- a/site/content/en/latest/tasks/quickstart.md
+++ b/site/content/en/latest/tasks/quickstart.md
@@ -15,8 +15,6 @@ __Note:__ Refer to the [Compatibility Matrix](/news/releases/matrix) for support
 __Note:__ In case your Kubernetes cluster does not have a LoadBalancer implementation, we recommend installing one
 so the `Gateway` resource has an Address associated with it. We recommend using [MetalLB](https://metallb.universe.tf/installation/).
 
-__Note:__ For Mac user, you need install and run [Docker Mac Net Connect](https://github.com/chipmk/docker-mac-net-connect) to make the Docker network work.
-
 ## Installation
 
 Install the Gateway API CRDs and Envoy Gateway:
@@ -124,7 +122,3 @@ Delete the Gateway API CRDs and Envoy Gateway:
 ```shell
 helm uninstall eg -n envoy-gateway-system
 ```
-
-## Next Steps
-
-Checkout the [Developer Guide](../../contributions/develop) to get involved in the project.
diff --git a/test/e2e/testdata/ratelimit-global-shared-and-unshared-header-match.yaml b/test/e2e/testdata/ratelimit-global-shared-and-unshared-header-match.yaml
new file mode 100644
index 000000000..639bbd725
--- /dev/null
+++ b/test/e2e/testdata/ratelimit-global-shared-and-unshared-header-match.yaml
@@ -0,0 +1,111 @@
+apiVersion: gateway.networking.k8s.io/v1
+kind: Gateway
+metadata:
+  name: eg-rate-limit
+  namespace: gateway-conformance-infra
+spec:
+  gatewayClassName: "{GATEWAY_CLASS_NAME}"
+  listeners:
+    - name: http-8080
+      protocol: HTTP
+      port: 8080
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: header-ratelimit-1
+  namespace: gateway-conformance-infra
+spec:
+  parentRefs:
+    - name: eg-rate-limit
+  rules:
+    - matches:
+        - path:
+            type: PathPrefix
+            value: /foo
+      backendRefs:
+        - name: infra-backend-v1
+          port: 8080
+---
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+  name: header-ratelimit-2
+  namespace: gateway-conformance-infra
+spec:
+  parentRefs:
+    - name: eg-rate-limit
+  rules:
+    - matches:
+        - path:
+            type: PathPrefix
+            value: /bar
+      backendRefs:
+        - name: infra-backend-v2
+          port: 8080
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: BackendTrafficPolicy
+metadata:
+  name: ratelimit-headers-route-policy
+  namespace: gateway-conformance-infra
+spec:
+  targetRefs:
+    - group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: header-ratelimit-1
+    - group: gateway.networking.k8s.io
+      kind: HTTPRoute
+      name: header-ratelimit-2
+  mergeType: StrategicMerge
+  rateLimit:
+    type: Global
+    global:
+      rules:
+        - clientSelectors:
+            - headers:
+                - name: x-user-id
+                  value: one
+          limit:
+            requests: 3
+            unit: Hour
+          shared: true
+        - clientSelectors:
+            - headers:
+                - name: x-user-id
+                  value: two
+          limit:
+            requests: 3
+            unit: Hour
+          shared: false
+---
+apiVersion: gateway.envoyproxy.io/v1alpha1
+kind: BackendTrafficPolicy
+metadata:
+  name: ratelimit-headers-gateway-policy
+  namespace: gateway-conformance-infra
+spec:
+  targetRefs:
+    - group: gateway.networking.k8s.io
+      kind: Gateway
+      name: eg-rate-limit
+  rateLimit:
+    type: Global
+    global:
+      rules:
+        - clientSelectors:
+            - headers:
+                - name: x-user-id
+                  value: three
+          limit:
+            requests: 3
+            unit: Hour
+          shared: true
+        - clientSelectors:
+            - headers:
+                - name: x-user-id
+                  value: four
+          limit:
+            requests: 3
+            unit: Hour
+          shared: false
diff --git a/test/e2e/testdata/ratelimit-global-shared-cidr-match.yaml b/test/e2e/testdata/ratelimit-global-shared-cidr-match.yaml
index 68f620df8..17871a252 100644
--- a/test/e2e/testdata/ratelimit-global-shared-cidr-match.yaml
+++ b/test/e2e/testdata/ratelimit-global-shared-cidr-match.yaml
@@ -14,7 +14,6 @@ spec:
   rateLimit:
     type: Global
     global:
-      shared: true
       rules:
         - clientSelectors:
             - sourceCIDR:
@@ -23,6 +22,7 @@ spec:
           limit:
             requests: 3
             unit: Hour
+          shared: true
 ---
 apiVersion: gateway.networking.k8s.io/v1
 kind: HTTPRoute
diff --git a/test/e2e/testdata/ratelimit-global-shared-gateway-header-match.yaml b/test/e2e/testdata/ratelimit-global-shared-gateway-header-match.yaml
index 04ff67b4b..95fd22ad7 100644
--- a/test/e2e/testdata/ratelimit-global-shared-gateway-header-match.yaml
+++ b/test/e2e/testdata/ratelimit-global-shared-gateway-header-match.yaml
@@ -57,7 +57,6 @@ spec:
   rateLimit:
     type: Global
     global:
-      shared: true
       rules:
         - clientSelectors:
             - headers:
@@ -67,3 +66,4 @@ spec:
           limit:
             requests: 3
             unit: Hour
+          shared: true
diff --git a/test/e2e/tests/ratelimit.go b/test/e2e/tests/ratelimit.go
index da8cff9fd..b3522af68 100644
--- a/test/e2e/tests/ratelimit.go
+++ b/test/e2e/tests/ratelimit.go
@@ -41,6 +41,7 @@ func init() {
 	ConformanceTests = append(ConformanceTests, UsageRateLimitTest)
 	ConformanceTests = append(ConformanceTests, RateLimitGlobalSharedCidrMatchTest)
 	ConformanceTests = append(ConformanceTests, RateLimitGlobalSharedGatewayHeaderMatchTest)
+	ConformanceTests = append(ConformanceTests, RateLimitGlobalMergeTest)
 }
 
 var RateLimitCIDRMatchTest = suite.ConformanceTest{
@@ -946,6 +947,89 @@ var RateLimitGlobalSharedGatewayHeaderMatchTest = suite.ConformanceTest{
 	},
 }
 
+var RateLimitGlobalMergeTest = suite.ConformanceTest{
+	ShortName:   "RateLimitGlobalMergeTest",
+	Description: "Limit requests with matching headers across multiple routes, verifying both shared and unshared rate limit behaviors",
+	Manifests:   []string{"testdata/ratelimit-global-shared-and-unshared-header-match.yaml"},
+	Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
+		ns := "gateway-conformance-infra"
+		route1NN := types.NamespacedName{Name: "header-ratelimit-1", Namespace: ns}
+		route2NN := types.NamespacedName{Name: "header-ratelimit-2", Namespace: ns}
+		gwNN := types.NamespacedName{Name: "eg-rate-limit", Namespace: ns}
+
+		gwAddr1 := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), route1NN)
+		gwAddr2 := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), route2NN)
+
+		t.Run("shared_route_policy_x-user-id=one", func(t *testing.T) {
+			headers := map[string]string{"x-user-id": "one"}
+
+			expectOk1 := http.ExpectedResponse{Request: http.Request{Path: "/bar", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			expectOk2 := http.ExpectedResponse{Request: http.Request{Path: "/foo", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			expectOk3 := http.ExpectedResponse{Request: http.Request{Path: "/bar", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			expectLimit := http.ExpectedResponse{Request: http.Request{Path: "/foo", Headers: headers}, Response: http.Response{StatusCode: 429}, Namespace: ns}
+
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr2, expectOk1)
+
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &expectOk1, gwAddr2, "HTTP", "http"), expectOk1)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &expectOk2, gwAddr1, "HTTP", "http"), expectOk2)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &expectOk3, gwAddr2, "HTTP", "http"), expectOk3)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &expectLimit, gwAddr1, "HTTP", "http"), expectLimit)
+		})
+
+		t.Run("unshared_route_policy_x-user-id=two", func(t *testing.T) {
+			headers := map[string]string{"x-user-id": "two"}
+
+			// Route 1 (/foo)
+			ok1 := http.ExpectedResponse{Request: http.Request{Path: "/foo", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			limit1 := http.ExpectedResponse{Request: http.Request{Path: "/foo", Headers: headers}, Response: http.Response{StatusCode: 429}, Namespace: ns}
+			// Route 2 (/bar)
+			ok2 := http.ExpectedResponse{Request: http.Request{Path: "/bar", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			limit2 := http.ExpectedResponse{Request: http.Request{Path: "/bar", Headers: headers}, Response: http.Response{StatusCode: 429}, Namespace: ns}
+
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr1, ok1)
+
+			_ = GotExactExpectedResponse(t, 3, suite.RoundTripper, http.MakeRequest(t, &ok1, gwAddr1, "HTTP", "http"), ok1)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &limit1, gwAddr1, "HTTP", "http"), limit1)
+
+			_ = GotExactExpectedResponse(t, 3, suite.RoundTripper, http.MakeRequest(t, &ok2, gwAddr2, "HTTP", "http"), ok2)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &limit2, gwAddr2, "HTTP", "http"), limit2)
+		})
+
+		t.Run("shared_gateway_policy_x-user-id=three", func(t *testing.T) {
+			headers := map[string]string{"x-user-id": "three"}
+
+			ok1 := http.ExpectedResponse{Request: http.Request{Path: "/bar", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			ok2 := http.ExpectedResponse{Request: http.Request{Path: "/foo", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			ok3 := http.ExpectedResponse{Request: http.Request{Path: "/bar", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			limit := http.ExpectedResponse{Request: http.Request{Path: "/foo", Headers: headers}, Response: http.Response{StatusCode: 429}, Namespace: ns}
+
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr2, ok1)
+
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &ok1, gwAddr2, "HTTP", "http"), ok1)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &ok2, gwAddr1, "HTTP", "http"), ok2)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &ok3, gwAddr2, "HTTP", "http"), ok3)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &limit, gwAddr1, "HTTP", "http"), limit)
+		})
+
+		t.Run("unshared_gateway_policy__x-user-id=four", func(t *testing.T) {
+			headers := map[string]string{"x-user-id": "four"}
+
+			ok1 := http.ExpectedResponse{Request: http.Request{Path: "/foo", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			limit1 := http.ExpectedResponse{Request: http.Request{Path: "/foo", Headers: headers}, Response: http.Response{StatusCode: 429}, Namespace: ns}
+			ok2 := http.ExpectedResponse{Request: http.Request{Path: "/bar", Headers: headers}, Response: http.Response{StatusCode: 200}, Namespace: ns}
+			limit2 := http.ExpectedResponse{Request: http.Request{Path: "/bar", Headers: headers}, Response: http.Response{StatusCode: 429}, Namespace: ns}
+
+			http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr1, ok1)
+
+			_ = GotExactExpectedResponse(t, 3, suite.RoundTripper, http.MakeRequest(t, &ok1, gwAddr1, "HTTP", "http"), ok1)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &limit1, gwAddr1, "HTTP", "http"), limit1)
+
+			_ = GotExactExpectedResponse(t, 3, suite.RoundTripper, http.MakeRequest(t, &ok2, gwAddr2, "HTTP", "http"), ok2)
+			_ = GotExactExpectedResponse(t, 1, suite.RoundTripper, http.MakeRequest(t, &limit2, gwAddr2, "HTTP", "http"), limit2)
+		})
+	},
+}
+
 func GotExactExpectedResponse(t *testing.T, n int, r roundtripper.RoundTripper, req roundtripper.Request, resp http.ExpectedResponse) error {
 	for i := 0; i < n; i++ {
 		cReq, cRes, err := r.CaptureRoundTrip(req)
diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml
index be47c7f6c..2612431a8 100644
--- a/test/helm/gateway-crds-helm/all.out.yaml
+++ b/test/helm/gateway-crds-helm/all.out.yaml
@@ -18570,23 +18570,17 @@ spec:
                               - requests
                               - unit
                               type: object
-                            name:
+                            shared:
                               description: |-
-                                Name is the name of the rule. This is used to identify the rule
-                                in the Envoy configuration and as a unique identifier for merging.
-                              type: string
+                                Shared determines whether this rate limit rule applies across all the policy targets.
+                                If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
+                                Default: false.
+                              type: boolean
                           required:
                           - limit
                           type: object
                         maxItems: 64
                         type: array
-                      shared:
-                        default: false
-                        description: |-
-                          Shared determines whether the rate limit rules apply across all the policy targets.
-                          If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
-                          Default: false.
-                        type: boolean
                     required:
                     - rules
                     type: object
@@ -18825,11 +18819,12 @@ spec:
                               - requests
                               - unit
                               type: object
-                            name:
+                            shared:
                               description: |-
-                                Name is the name of the rule. This is used to identify the rule
-                                in the Envoy configuration and as a unique identifier for merging.
-                              type: string
+                                Shared determines whether this rate limit rule applies across all the policy targets.
+                                If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
+                                Default: false.
+                              type: boolean
                           required:
                           - limit
                           type: object
diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
index a0e725710..9dc657ce7 100644
--- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
+++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml
@@ -1258,23 +1258,17 @@ spec:
                               - requests
                               - unit
                               type: object
-                            name:
+                            shared:
                               description: |-
-                                Name is the name of the rule. This is used to identify the rule
-                                in the Envoy configuration and as a unique identifier for merging.
-                              type: string
+                                Shared determines whether this rate limit rule applies across all the policy targets.
+                                If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
+                                Default: false.
+                              type: boolean
                           required:
                           - limit
                           type: object
                         maxItems: 64
                         type: array
-                      shared:
-                        default: false
-                        description: |-
-                          Shared determines whether the rate limit rules apply across all the policy targets.
-                          If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
-                          Default: false.
-                        type: boolean
                     required:
                     - rules
                     type: object
@@ -1513,11 +1507,12 @@ spec:
                               - requests
                               - unit
                               type: object
-                            name:
+                            shared:
                               description: |-
-                                Name is the name of the rule. This is used to identify the rule
-                                in the Envoy configuration and as a unique identifier for merging.
-                              type: string
+                                Shared determines whether this rate limit rule applies across all the policy targets.
+                                If set to true, the rule is treated as a common bucket and is shared across all policy targets (xRoutes).
+                                Default: false.
+                              type: boolean
                           required:
                           - limit
                           type: object