Repository: lightstep/otel-launcher-go
Pull request #385 (2023-02-15 19:15:36)

Add cardinality limits to the Lightstep metrics SDK
**Description:** This is a prototype for https://github.com/open-telemetry/opentelemetry-specification/pull/2960.

This adds both `InstrumentCardinalityLimit` and `AggregatorCardinalityLimit`.

The instrument-level limit is meant as a circuit-breaker and the aggregator-level limit is a meant to allow views to correct overflow problems. Both of these features use `otel.metrics.overflow=true` to indicate the loss of attributes due to overflow. Only the synchronous instrument code path uses `InstrumentCardinalityLimit` in this PR, asynchronous do not, a low-priority issue to be solved separately. The problem is described in https://github.com/lightstep/otel-launcher-go/issues/410. 

The aggregator-level limit is applied after view-configured filters are applied, so is useful to correct overflow problems.

The aggregator-level is treated as a hard-limit, when configured the aggregator will produce no more than the configured number of aggregations. The instrument-level limit is considered a circuit-breaker. For delta-temporality outputs, this should be set larger than the aggregator-level limit (considering inactivity periods) sufficiently to ensure that instrument-level records are recycled fast enough for dynamic cardinality changes.

Note there is a special case for overflow treatment in the async-delta output path (in viewstate); the cumulative overflow value is calculated so that the delta is correct. This is also low-priority, but as this is a prototype for an OTel specification, I considered it and tested it.

**Link to tracking Issue:** https://github.com/open-telemetry/opentelemetry-specification/issues/1891

**Testing:** Detailed new tests in syncstate, viewstate. 

**Documentation:** Added.

codecov-commenter: # [Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/385?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lightstep) Report
Base: **87.84**% // Head: **87.76**% // Decreases project coverage by **`-0.09%`** :warning:
> Coverage data is based on head [(`f05909f`)](https://codecov.io/gh/lightstep/otel-launcher-go/pull/385?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lightstep) compared to base [(`1fb5140`)](https://codecov.io/gh/lightstep/otel-launcher-go/commit/1fb5140adc2be0c53b42fcf374bbbbec956c3baf?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lightstep).
> Patch coverage: 70.58% of modified lines in pull request are covered.

> :exclamation: Current head f05909f differs from pull request most recent head 02ef200. Consider uploading reports for the commit 02ef200 to get more accurate results

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


```diff
@@            Coverage Diff             @@
##             main     #385      +/-   ##
==========================================
- Coverage   87.84%   87.76%   -0.09%     
==========================================
  Files          74       74              
  Lines        4205     4218      +13     
==========================================
+ Hits         3694     3702       +8     
- Misses        438      442       +4     
- Partials       73       74       +1     
```


| [Impacted Files](https://codecov.io/gh/lightstep/otel-launcher-go/pull/385?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lightstep) | Coverage Δ | |
|---|---|---|
| [lightstep/sdk/metric/internal/syncstate/sync.go](https://codecov.io/gh/lightstep/otel-launcher-go/pull/385?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lightstep#diff-bGlnaHRzdGVwL3Nkay9tZXRyaWMvaW50ZXJuYWwvc3luY3N0YXRlL3N5bmMuZ28=) | `95.02% <70.58%> (-2.60%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lightstep). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lightstep)

</details>

[:umbrella: View full report at Codecov](https://codecov.io/gh/lightstep/otel-launcher-go/pull/385?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lightstep).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=lightstep).

jmacd: https://github.com/open-telemetry/opentelemetry-specification/pull/2960#issuecomment-1454203830

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7ed61c7..c2aa73a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -8,7 +8,14 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
 
 ## Unreleased
 
-## [1.13.4](https://github.com/lightstep/otel-launcher-go/releases/tag/v1.13.3) - 2023-03-01)
+## [1.14.0](https://github.com/lightstep/otel-launcher-go/releases/tag/v1.14.0) - 2023-03-17)
+
+- Support cardinality limits.  Synchronous instruments support an
+  instrument-level cardinality limit; Synchronous and Asynchronous
+  aggregators support per-view cardinality limits.  Performance settings
+  determine the view-configured defaults. [#385](https://github.com/lightstep/otel-launcher-go/pull/385)
+
+## [1.13.4](https://github.com/lightstep/otel-launcher-go/releases/tag/v1.13.3) - 2023-03-02)
 
 - Minor performance improvement, one less allocation under the lock
   when fingerprint collisions are being checked. [#407](https://github.com/lightstep/otel-launcher-go/pull/407)
diff --git a/VERSION b/VERSION
index 80138e7..850e742 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-1.13.4
+1.14.0
diff --git a/go.mod b/go.mod
index 7bcedc4..05a127e 100644
--- a/go.mod
+++ b/go.mod
@@ -3,14 +3,14 @@ module github.com/lightstep/otel-launcher-go
 go 1.18
 
 require (
-	github.com/lightstep/otel-launcher-go/lightstep/sdk/metric v1.13.4
-	github.com/lightstep/otel-launcher-go/pipelines v1.13.4
+	github.com/lightstep/otel-launcher-go/lightstep/sdk/metric v1.14.0
+	github.com/lightstep/otel-launcher-go/pipelines v1.14.0
 	github.com/sethvargo/go-envconfig v0.8.3
-	github.com/stretchr/testify v1.8.1
-	go.opentelemetry.io/otel v1.12.0
+	github.com/stretchr/testify v1.8.2
+	go.opentelemetry.io/otel v1.14.0
 	go.opentelemetry.io/otel/metric v0.35.0
-	go.opentelemetry.io/otel/sdk v1.12.0
-	go.opentelemetry.io/otel/trace v1.12.0
+	go.opentelemetry.io/otel/sdk v1.14.0
+	go.opentelemetry.io/otel/trace v1.14.0
 )
 
 require (
@@ -23,7 +23,7 @@ require (
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0 // indirect
 	github.com/lightstep/go-expohisto v1.0.0 // indirect
-	github.com/lightstep/otel-launcher-go/lightstep/instrumentation v1.13.4 // indirect
+	github.com/lightstep/otel-launcher-go/lightstep/instrumentation v1.14.0 // indirect
 	github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
@@ -44,9 +44,9 @@ require (
 	go.opentelemetry.io/proto/otlp v0.19.0 // indirect
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.9.0 // indirect
-	golang.org/x/net v0.4.0 // indirect
-	golang.org/x/sys v0.4.0 // indirect
-	golang.org/x/text v0.5.0 // indirect
+	golang.org/x/net v0.7.0 // indirect
+	golang.org/x/sys v0.5.0 // indirect
+	golang.org/x/text v0.7.0 // indirect
 	google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
 	google.golang.org/grpc v1.52.3 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
diff --git a/go.sum b/go.sum
index de69cce..096218d 100644
--- a/go.sum
+++ b/go.sum
@@ -171,8 +171,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
+github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
 github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
 github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
@@ -195,8 +196,8 @@ go.opentelemetry.io/contrib/propagators/b3 v1.13.0 h1:f17PBmZK60RoHvOpJVqEka8oS2
 go.opentelemetry.io/contrib/propagators/b3 v1.13.0/go.mod h1:zy2hz1TpGUoJzSwlBchVGvVAFQS8s2pglKLbrAFZ+Sc=
 go.opentelemetry.io/contrib/propagators/ot v1.13.0 h1:tHWNd0WRS6w9keZoZg9aF3zYohdaBacQfojPYZJgATQ=
 go.opentelemetry.io/contrib/propagators/ot v1.13.0/go.mod h1:R6Op9T6LxNaMRVlGD0wVwz40LSsAq296CXiEydKLQBU=
-go.opentelemetry.io/otel v1.12.0 h1:IgfC7kqQrRccIKuB7Cl+SRUmsKbEwSGPr0Eu+/ht1SQ=
-go.opentelemetry.io/otel v1.12.0/go.mod h1:geaoz0L0r1BEOR81k7/n9W4TCXYCJ7bPO7K374jQHG0=
+go.opentelemetry.io/otel v1.14.0 h1:/79Huy8wbf5DnIPhemGB+zEPVwnN6fuQybr/SRXa6hM=
+go.opentelemetry.io/otel v1.14.0/go.mod h1:o4buv+dJzx8rohcUeRmWUZhqupFvzWis188WlggnNeU=
 go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.13.0 h1:pa05sNT/P8OsIQ8mPZKTIyiBuzS/xDGLVx+DCt0y6Vs=
 go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.13.0/go.mod h1:rqbht/LlhVBgn5+k3M5QK96K5Xb0DvXpMJ5SFQpY6uw=
 go.opentelemetry.io/otel/exporters/otlp/otlpmetric v0.35.0 h1:KPV7w2qbszG6XnudnWDffM4CI+KjCYajryGrhoReBR4=
@@ -209,12 +210,12 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.12.0 h1:+tsVd
 go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.12.0/go.mod h1:jSqjV+Knu1Jyvh+l3fx7V210Ev3HHgNQAi8YqpXaQP8=
 go.opentelemetry.io/otel/metric v0.35.0 h1:aPT5jk/w7F9zW51L7WgRqNKDElBdyRLGuBtI5MX34e8=
 go.opentelemetry.io/otel/metric v0.35.0/go.mod h1:qAcbhaTRFU6uG8QM7dDo7XvFsWcugziq/5YI065TokQ=
-go.opentelemetry.io/otel/sdk v1.12.0 h1:8npliVYV7qc0t1FKdpU08eMnOjgPFMnriPhn0HH4q3o=
-go.opentelemetry.io/otel/sdk v1.12.0/go.mod h1:WYcvtgquYvgODEvxOry5owO2y9MyciW7JqMz6cpXShE=
+go.opentelemetry.io/otel/sdk v1.14.0 h1:PDCppFRDq8A1jL9v6KMI6dYesaq+DFcDZvjsoGvxGzY=
+go.opentelemetry.io/otel/sdk v1.14.0/go.mod h1:bwIC5TjrNG6QDCHNWvW4HLHtUQ4I+VQDsnjhvyZCALM=
 go.opentelemetry.io/otel/sdk/metric v0.35.0 h1:gryV4W5GzpOhKK48/lZb8ldyWIs3DRugSVlQZmCwELA=
 go.opentelemetry.io/otel/sdk/metric v0.35.0/go.mod h1:eDyp1GxSiwV98kr7w4pzrszQh/eze9MqBqPd2bCPmyE=
-go.opentelemetry.io/otel/trace v1.12.0 h1:p28in++7Kd0r2d8gSt931O57fdjUyWxkVbESuILAeUc=
-go.opentelemetry.io/otel/trace v1.12.0/go.mod h1:pHlgBynn6s25qJ2szD+Bv+iwKJttjHSI3lUAyf0GNuQ=
+go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyKcFq/M=
+go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.19.0 h1:IVN6GR+mhC4s5yfcTbmzHYODqvWAp3ZedA2SJPI1Nnw=
 go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
@@ -285,8 +286,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
-golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 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=
@@ -333,8 +334,9 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
 golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -342,8 +344,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
-golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/launcher/version.go b/launcher/version.go
index 6ef3228..3489d2f 100644
--- a/launcher/version.go
+++ b/launcher/version.go
@@ -14,4 +14,4 @@
 
 package launcher
 
-const version = "1.13.4"
+const version = "1.14.0"
diff --git a/lightstep/sdk/metric/README.md b/lightstep/sdk/metric/README.md
index 6ff71d9..1fe6759 100644
--- a/lightstep/sdk/metric/README.md
+++ b/lightstep/sdk/metric/README.md
@@ -147,3 +147,27 @@ Setting this field to 1 means records will be removed from memory
 after one inactive collection cycle.
 
 Setting this field to 0 causes the default value 10 to be used.
+
+#### InstrumentCardinalityLimit
+
+Synchronous instruments are implemented using a map of intermediate
+state.  When this map grows to `InstrumentCardinalityLimit`, new
+attribute sets will be replaced by the overflow attribute set, which
+is `{ otel.metric.overflow=true }`.  This limit is applied to all
+instruments regardless of view configuration before attribute filters
+are applied.
+
+For instruments configured with Delta temporality, where it is
+possible for the map to shrink, note that the size of this map
+includes records maintained due to `InactiveCollectionPeriods`.  The
+inactivity period should be taken into account when setting
+`InstrumentCardinalityLimit` to avoid overflow.
+
+#### AggregatorCardinalityLimit
+
+All views maintain a configurable cardinality limit, calculated after
+attribute filters are applied.
+
+When the aggregator's output grows to `AggregatorCardinalityLimit`,
+new attribute sets will be replaced by the overflow attribute set,
+which is `{ otel.metric.overflow=true }`.
diff --git a/lightstep/sdk/metric/aggregator/aggregator.go b/lightstep/sdk/metric/aggregator/aggregator.go
index abc56f6..9df98e2 100644
--- a/lightstep/sdk/metric/aggregator/aggregator.go
+++ b/lightstep/sdk/metric/aggregator/aggregator.go
@@ -75,19 +75,18 @@ type JSONHistogramConfig struct {
 
 // JSONConfig supports the configuration for all aggregators in a single struct.
 type JSONConfig struct {
-	Histogram JSONHistogramConfig `json:"histogram"`
-}
-
-// ToConfig returns a Config from the fixed-JSON represented.
-func (jc JSONConfig) ToConfig() Config {
-	return Config{
-		Histogram: histostruct.NewConfig(histostruct.WithMaxSize(jc.Histogram.MaxSize)),
-	}
+	Histogram        JSONHistogramConfig `json:"histogram"`
+	CardinalityLimit uint32              `json:"cardinality_limit"`
 }
 
 // Config supports the configuration for all aggregators in a single struct.
 type Config struct {
+	// Histogram configuration, specifically.
 	Histogram histostruct.Config
+
+	// CardinalityLimit limits the number of instances of this
+	// aggregator in a given view.
+	CardinalityLimit uint32
 }
 
 // Valid returns true for valid configurations.
@@ -101,6 +100,11 @@ func (c Config) Valid() bool {
 func (c Config) Validate() (Config, error) {
 	var err error
 	c.Histogram, err = c.Histogram.Validate()
+
+	if c.CardinalityLimit == 0 {
+		c.CardinalityLimit = sdkinstrument.DefaultAggregatorCardinalityLimit
+	}
+
 	return c, err
 }
 
diff --git a/lightstep/sdk/metric/config.go b/lightstep/sdk/metric/config.go
index 34eaa32..9126c86 100644
--- a/lightstep/sdk/metric/config.go
+++ b/lightstep/sdk/metric/config.go
@@ -17,7 +17,6 @@ package metric // import "github.com/lightstep/otel-launcher-go/lightstep/sdk/me
 import (
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/sdkinstrument"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/view"
-	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/sdk/resource"
 )
 
@@ -30,9 +29,9 @@ type config struct {
 	// the i'th reader uses the i'th entry in views.
 	readers []Reader
 
-	// views is a slice of *Views instances corresponding with readers.
-	// the i'th views applies to the i'th reader.
-	views []*view.Views
+	// vopts is a slice of []view.Option corresponding with readers.
+	// the i'th view option list applies to the i'th reader.
+	vopts [][]view.Option
 
 	// performance settings
 	performance sdkinstrument.Performance
@@ -63,12 +62,8 @@ func WithResource(res *resource.Resource) Option {
 // a new MeterProvider
 func WithReader(r Reader, opts ...view.Option) Option {
 	return optionFunction(func(cfg config) config {
-		v, err := view.Validate(view.New(r.String(), opts...))
-		if err != nil {
-			otel.Handle(err)
-		}
 		cfg.readers = append(cfg.readers, r)
-		cfg.views = append(cfg.views, v)
+		cfg.vopts = append(cfg.vopts, opts)
 		return cfg
 	})
 }
diff --git a/lightstep/sdk/metric/example/go.mod b/lightstep/sdk/metric/example/go.mod
index 2b6d332..107c505 100644
--- a/lightstep/sdk/metric/example/go.mod
+++ b/lightstep/sdk/metric/example/go.mod
@@ -3,7 +3,7 @@ module github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/example
 go 1.18
 
 require (
-	github.com/lightstep/otel-launcher-go/lightstep/sdk/metric v1.13.4
+	github.com/lightstep/otel-launcher-go/lightstep/sdk/metric v1.14.0
 	github.com/lightstep/otel-launcher-go/pipelines v1.8.0
 	go.opentelemetry.io/proto/otlp v0.19.0
 )
@@ -23,9 +23,9 @@ require (
 	go.opentelemetry.io/otel/trace v1.12.0 // indirect
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.9.0 // indirect
-	golang.org/x/net v0.4.0 // indirect
-	golang.org/x/sys v0.4.0 // indirect
-	golang.org/x/text v0.5.0 // indirect
+	golang.org/x/net v0.7.0 // indirect
+	golang.org/x/sys v0.5.0 // indirect
+	golang.org/x/text v0.7.0 // indirect
 	google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
 	google.golang.org/grpc v1.52.3 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
diff --git a/lightstep/sdk/metric/example/go.sum b/lightstep/sdk/metric/example/go.sum
index 202b76d..7c65522 100644
--- a/lightstep/sdk/metric/example/go.sum
+++ b/lightstep/sdk/metric/example/go.sum
@@ -241,8 +241,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
-golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 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=
@@ -286,8 +286,8 @@ golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
-golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -295,8 +295,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
-golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/lightstep/sdk/metric/go.mod b/lightstep/sdk/metric/go.mod
index 57f31b6..668e86e 100644
--- a/lightstep/sdk/metric/go.mod
+++ b/lightstep/sdk/metric/go.mod
@@ -32,9 +32,9 @@ require (
 	github.com/rogpeppe/go-internal v1.9.0 // indirect
 	go.opentelemetry.io/otel/trace v1.12.0 // indirect
 	go.uber.org/atomic v1.7.0 // indirect
-	golang.org/x/net v0.2.0 // indirect
-	golang.org/x/sys v0.2.0 // indirect
-	golang.org/x/text v0.4.0 // indirect
+	golang.org/x/net v0.7.0 // indirect
+	golang.org/x/sys v0.5.0 // indirect
+	golang.org/x/text v0.7.0 // indirect
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
 )
diff --git a/lightstep/sdk/metric/go.sum b/lightstep/sdk/metric/go.sum
index bfc65b9..159986c 100644
--- a/lightstep/sdk/metric/go.sum
+++ b/lightstep/sdk/metric/go.sum
@@ -262,8 +262,8 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 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=
@@ -311,8 +311,8 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -320,8 +320,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/lightstep/sdk/metric/internal/asyncstate/async.go b/lightstep/sdk/metric/internal/asyncstate/async.go
index 498422e..4c0ae52 100644
--- a/lightstep/sdk/metric/internal/asyncstate/async.go
+++ b/lightstep/sdk/metric/internal/asyncstate/async.go
@@ -86,9 +86,10 @@ func New(desc sdkinstrument.Descriptor, _ sdkinstrument.Performance, opaque inte
 	// disabled the instrument. This ensures that certain error
 	// checks still work (wrong meter, wrong callback, etc).
 	//
-	// Note: performance settings are not used because async
-	// instruments do not use fingerprinting so IgnoreCollisions is
-	// meaningless.
+	// Note: performance settings are not used.
+	// 1. There is no fingerprinting, so IgnoreCollisions is meaningless.
+	// 2. InstrumentCardinalityLimit is not enforceable, because of duplicate
+	//    suppression -- better left to the aggregator.
 	return &Observer{
 		opaque:     opaque,
 		descriptor: desc,
diff --git a/lightstep/sdk/metric/internal/pipeline/overflow.go b/lightstep/sdk/metric/internal/pipeline/overflow.go
new file mode 100644
index 0000000..c5a7161
--- /dev/null
+++ b/lightstep/sdk/metric/internal/pipeline/overflow.go
@@ -0,0 +1,26 @@
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package pipeline // import "github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/internal/pipeline"
+
+import "go.opentelemetry.io/otel/attribute"
+
+// OverflowAttributes is the specified list of attributes to use when
+// configured mechanisms overflow a cardinality limit.
+var OverflowAttributes = []attribute.KeyValue{
+	attribute.Bool("otel.metric.overflow", true),
+}
+
+// OverflowAttributeSet is the set corresponding with OverflowAttributes.
+var OverflowAttributeSet = attribute.NewSet(OverflowAttributes...)
diff --git a/lightstep/sdk/metric/internal/syncstate/sync.go b/lightstep/sdk/metric/internal/syncstate/sync.go
index 59762ed..b26f165 100644
--- a/lightstep/sdk/metric/internal/syncstate/sync.go
+++ b/lightstep/sdk/metric/internal/syncstate/sync.go
@@ -30,6 +30,8 @@ import (
 	"go.opentelemetry.io/otel/metric/instrument"
 )
 
+var overflowAttributesFingerprint = fingerprintAttributes(pipeline.OverflowAttributes)
+
 // Instrument maintains a mapping from attribute.Set to an internal
 // record type for a single API-level instrument.  This type is
 // organized so that a single attribute.Set lookup is performed
@@ -129,7 +131,7 @@ func (inst *Observer) SnapshotAndProcess() {
 			}
 		}
 
-		// When records are kept, delete the map entry.
+		// When no records are kept, delete the map entry.
 		if head == nil {
 			delete(inst.current, key)
 			continue
@@ -429,11 +431,31 @@ func attributesEqual(a, b []attribute.KeyValue) bool {
 	return true
 }
 
-// acquireRead acquires the read lock and searches for a `*record`.
-func acquireRead(inst *Observer, fp uint64, attrs []attribute.KeyValue) *record {
+// acquireRead acquires the lock and searches for a `*record`.
+// This returns the overflow attributes and fingerprint in case the
+// the cardinality limit is reached.  The caller should exchange their
+// fp and attrs for the ones returned by this call.
+func acquireRead(inst *Observer, fp uint64, attrs []attribute.KeyValue) (uint64, []attribute.KeyValue, *record) {
 	inst.lock.RLock()
 	defer inst.lock.RUnlock()
 
+	overflow := false
+	fp, attrs, rec := acquireReadLocked(inst, fp, attrs, &overflow)
+
+	if rec != nil {
+		return fp, attrs, rec
+	}
+	// The overflow signal indicates another call is needed w/ the
+	// same logic but updated fp and attrs.
+	if !overflow {
+		// Otherwise, this is the first appearance of an overflow.
+		return fp, attrs, nil
+	}
+	// In which case fp and attrs are now the overflow attributes.
+	return acquireReadLocked(inst, fp, attrs, &overflow)
+}
+
+func acquireReadLocked(inst *Observer, fp uint64, attrs []attribute.KeyValue, overflow *bool) (uint64, []attribute.KeyValue, *record) {
 	rec := inst.current[fp]
 
 	// Potentially test for hash collisions.
@@ -447,10 +469,21 @@ func acquireRead(inst *Observer, fp uint64, attrs []attribute.KeyValue) *record
 	if rec != nil && rec.refMapped.ref() {
 		// At this moment it is guaranteed that the
 		// record is in the map and will not be removed.
-		return rec
+		return fp, attrs, rec
+	}
+
+	// Check for overflow after checking for the original
+	// attribute set.  Note this means we are performing
+	// two map lookups for overflowing attributes and only
+	// one lookup if the attribute set was preexisting.
+	if !*overflow && uint32(len(inst.current)) >= inst.performance.InstrumentCardinalityLimit-1 {
+		// Use the overflow attributes, repeat.
+		attrs = pipeline.OverflowAttributes
+		fp = overflowAttributesFingerprint
+		*overflow = true
 	}
 
-	return nil
+	return fp, attrs, nil
 }
 
 // acquireUninitialized gets or creates a `*record` corresponding to
@@ -459,7 +492,10 @@ func acquireRead(inst *Observer, fp uint64, attrs []attribute.KeyValue) *record
 func acquireUninitialized[N number.Any](inst *Observer, attrs []attribute.KeyValue) *record {
 	fp := fingerprintAttributes(attrs)
 
-	if rec := acquireRead(inst, fp, attrs); rec != nil {
+	// acquireRead may replace fp and attrs when there is overflow.
+	var rec *record
+	fp, attrs, rec = acquireRead(inst, fp, attrs)
+	if rec != nil {
 		return rec
 	}
 
diff --git a/lightstep/sdk/metric/internal/viewstate/base_instrument.go b/lightstep/sdk/metric/internal/viewstate/base_instrument.go
index 9590878..fdc6beb 100644
--- a/lightstep/sdk/metric/internal/viewstate/base_instrument.go
+++ b/lightstep/sdk/metric/internal/viewstate/base_instrument.go
@@ -23,12 +23,17 @@ import (
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/aggregator/aggregation"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/data"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/internal/doevery"
+	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/internal/pipeline"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/number"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/sdkinstrument"
 	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/attribute"
 )
 
+var overflowAttributeSet = pipeline.OverflowAttributeSet
+
+var errInternalOverflowError = fmt.Errorf("internal overflow error condition")
+
 // storageHolder is a generic struct for holding one storage and one
 // auxiliary field.  Storage will be one of the aggregators.  The
 // auxiliary type depends on whether synchronous or asynchronous.
@@ -139,6 +144,40 @@ func (metric *instrumentBase[N, Storage, Auxiliary, Methods]) getOrCreateEntry(k
 	if has {
 		return entry
 	}
+	// Special case at one less than the limit -- is there already
+	// an overflow attribute set?
+	sz := len(metric.data)
+	lim := int(metric.acfg.CardinalityLimit)
+
+	if sz == lim {
+		// Second lookup is required and it *must* succeed or
+		// there is an internal error condition.
+		if entry, has = metric.data[overflowAttributeSet]; has {
+			return entry
+		}
+		// The boundary condtions in the branch below ensures
+		// this won't happen, but fall through to create an
+		// overflow entry above the limit to avoid panic.
+		doevery.TimePeriod(time.Minute, func() {
+			otel.Handle(fmt.Errorf("limit passed %d: %w", len(metric.data), errInternalOverflowError))
+		})
+	} else if sz == lim-1 {
+		// If this is not the overflow set, check whether the
+		// overflow aggregator already exists.  If it already
+		// exists, allow this attribute set to be created,
+		// otherwise force creation of the overflow attribute
+		// set.
+		if kvs != overflowAttributeSet {
+			if _, overflowed := metric.data[overflowAttributeSet]; !overflowed {
+				// First overflow event.
+				kvs = overflowAttributeSet
+			}
+			// If not overflowed, the overflow aggregator
+			// already exists, means we're creating the
+			// last aggregator until existing attribute
+			// sets fall out of use.
+		}
+	}
 
 	var methods Methods
 	entry = &storageHolder[Storage, Auxiliary]{}
diff --git a/lightstep/sdk/metric/internal/viewstate/collectors.go b/lightstep/sdk/metric/internal/viewstate/collectors.go
index 070822b..97642bd 100644
--- a/lightstep/sdk/metric/internal/viewstate/collectors.go
+++ b/lightstep/sdk/metric/internal/viewstate/collectors.go
@@ -20,6 +20,7 @@ import (
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/aggregator"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/aggregator/aggregation"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/data"
+	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/internal/pipeline"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/number"
 	"go.opentelemetry.io/otel/attribute"
 )
@@ -87,7 +88,6 @@ func (p *statelessSyncInstrument[N, Storage, Methods]) Collect(seq data.Sequence
 		if numRefs == 0 {
 			delete(p.data, set)
 		}
-
 	}
 }
 
@@ -137,9 +137,14 @@ func (p *statefulAsyncInstrument[N, Storage, Methods]) Collect(seq data.Sequence
 
 	ioutput := p.appendInstrument(output)
 
+	var ofe *storageHolder[Storage, notUsed]
 	for set, entry := range p.data {
 		// Compute the difference.
 		pval, has := p.prior[set]
+
+		if set == pipeline.OverflowAttributeSet {
+			ofe = entry
+		}
 		if has {
 			// This does `*pval := *storage - *pval`
 			methods.SubtractSwap(&pval.storage, &entry.storage)
@@ -161,4 +166,14 @@ func (p *statefulAsyncInstrument[N, Storage, Methods]) Collect(seq data.Sequence
 	// Copy the current to the prior and reset.
 	p.prior = p.data
 	p.data = map[attribute.Set]*storageHolder[Storage, notUsed]{}
+
+	// Note: the overflow attribute set is synthesized from a
+	// number of inputs which are presumed cumulative.  To maintain this
+	// illusion, copy its current cumulative value into the next data set.
+	if ofe != nil {
+		cpy := &storageHolder[Storage, notUsed]{}
+		methods.Copy(&ofe.storage, &cpy.storage)
+
+		p.data[pipeline.OverflowAttributeSet] = cpy
+	}
 }
diff --git a/lightstep/sdk/metric/internal/viewstate/viewstate.go b/lightstep/sdk/metric/internal/viewstate/viewstate.go
index 4164f89..f4e9ab2 100644
--- a/lightstep/sdk/metric/internal/viewstate/viewstate.go
+++ b/lightstep/sdk/metric/internal/viewstate/viewstate.go
@@ -20,6 +20,7 @@ import (
 	"strings"
 	"sync"
 
+	histostruct "github.com/lightstep/go-expohisto/structure"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/aggregator"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/aggregator/aggregation"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/aggregator/gauge"
@@ -42,20 +43,20 @@ import (
 // Information flows through the Compiler as follows:
 //
 // When new instruments are created:
-// - The Compiler.Compile() method returns an Instrument value and possible
-//   duplicate or semantic conflict error.
+//   - The Compiler.Compile() method returns an Instrument value and possible
+//     duplicate or semantic conflict error.
 //
 // When instruments are used:
 // - The Instrument.NewAccumulator() method returns an Accumulator value for each attribute.Set used
 // - The Accumulator.Update() aggregates one value for each measurement.
 //
 // During collection:
-// - The Accumulator.SnapshotAndProcess() method captures the current value
-//   and conveys it to the output storage
-// - The Compiler.Collectors() interface returns one Collector per output
-//   Metric in the Meter (duplicate definitions included).
-// - The Collector.Collect() method outputs one Point for each attribute.Set
-//   in the result.
+//   - The Accumulator.SnapshotAndProcess() method captures the current value
+//     and conveys it to the output storage
+//   - The Compiler.Collectors() interface returns one Collector per output
+//     Metric in the Meter (duplicate definitions included).
+//   - The Collector.Collect() method outputs one Point for each attribute.Set
+//     in the result.
 type Compiler struct {
 	// views is the configuration of this compiler.
 	views *view.Views
@@ -177,6 +178,7 @@ type singleBehavior struct {
 
 // New returns a compiler for library given configured views.
 func New(library instrumentation.Library, views *view.Views) *Compiler {
+	views, _ = view.Validate(views)
 	return &Compiler{
 		library: library,
 		views:   views,
@@ -193,24 +195,25 @@ func (v *Compiler) Collectors() []data.Collector {
 // tryToApplyHint looks for a Lightstep-specified hint structure
 // encoded as JSON in the description.  If valid, returns the modified
 // configuration, otherwise returns the default for the instrument.
-func (v *Compiler) tryToApplyHint(instrument sdkinstrument.Descriptor) (_ sdkinstrument.Descriptor, akind aggregation.Kind, acfg aggregator.Config, hinted bool) {
+func (v *Compiler) tryToApplyHint(instrument sdkinstrument.Descriptor) (_ sdkinstrument.Descriptor, akind aggregation.Kind, acfg, defCfg aggregator.Config, hinted bool) {
 	// These are the default behaviors, we'll use them unless there's a valid hint.
 	akind = v.views.Defaults.Aggregation(instrument.Kind)
-	acfg = v.views.Defaults.AggregationConfig(
+	defCfg = v.views.Defaults.AggregationConfig(
 		instrument.Kind,
 		instrument.NumberKind,
 	)
+	acfg = defCfg
 
 	// Check for required JSON symbols, empty strings, ...
 	if !strings.Contains(instrument.Description, "{") {
-		return instrument, akind, acfg, hinted
+		return instrument, akind, acfg, defCfg, hinted
 	}
 
 	var hint view.Hint
 	if err := json.Unmarshal([]byte(instrument.Description), &hint); err != nil {
 		// This could be noisy if valid descriptions contain spurious '{' chars.
 		otel.Handle(fmt.Errorf("hint parse error: %w", err))
-		return instrument, akind, acfg, hinted
+		return instrument, akind, acfg, defCfg, hinted
 	}
 
 	// Replace the hint input with its embedded description.
@@ -229,16 +232,19 @@ func (v *Compiler) tryToApplyHint(instrument sdkinstrument.Descriptor) (_ sdkins
 		}
 	}
 
-	if hint.Config != (aggregator.JSONConfig{}) {
-		cfg := hint.Config.ToConfig()
+	if hint.Config.Histogram.MaxSize != 0 {
+		cfg := histostruct.NewConfig(histostruct.WithMaxSize(hint.Config.Histogram.MaxSize))
 		cfg, err := cfg.Validate()
 		if err != nil {
-			otel.Handle(fmt.Errorf("hint invalid aggregator config: %w", err))
+			otel.Handle(err)
 		}
-		acfg = cfg
+		acfg.Histogram = cfg
+	}
+	if hint.Config.CardinalityLimit != 0 {
+		acfg.CardinalityLimit = hint.Config.CardinalityLimit
 	}
 
-	return instrument, akind, acfg, hinted
+	return instrument, akind, acfg, defCfg, hinted
 }
 
 // Compile is called during NewInstrument by the Meter
@@ -261,7 +267,7 @@ func (v *Compiler) Compile(instrument sdkinstrument.Descriptor) (Instrument, Vie
 			continue
 		}
 
-		modified, hintAkind, hintAcfg, hinted := v.tryToApplyHint(instrument)
+		modified, hintAkind, hintAcfg, defCfg, hinted := v.tryToApplyHint(instrument)
 		instrument = modified // the hint erases itself from the description
 
 		if akind == aggregation.UndefinedKind {
@@ -272,7 +278,7 @@ func (v *Compiler) Compile(instrument sdkinstrument.Descriptor) (Instrument, Vie
 			fromName: instrument.Name,
 			desc:     viewDescriptor(instrument, view),
 			kind:     akind,
-			acfg:     pickAggConfig(hintAcfg, view.AggregatorConfig()),
+			acfg:     pickAggConfig(hintAcfg, defCfg, view.AggregatorConfig()),
 			tempo:    v.views.Defaults.Temporality(instrument.Kind),
 			hinted:   hinted,
 		}
@@ -287,7 +293,7 @@ func (v *Compiler) Compile(instrument sdkinstrument.Descriptor) (Instrument, Vie
 
 	// If there were no matching views, set the default aggregation.
 	if len(matches) == 0 {
-		modified, akind, acfg, hinted := v.tryToApplyHint(instrument)
+		modified, akind, acfg, _, hinted := v.tryToApplyHint(instrument)
 		instrument = modified // the hint erases itself from the description
 
 		if akind != aggregation.DropKind {
@@ -406,6 +412,7 @@ func newSyncView[
 	// is being copied before the new object is returned to the
 	// user, and the extra allocation cost here would be
 	// noticeable.
+
 	metric := instrumentBase[N, Storage, int64, Methods]{
 		fromName:   behavior.fromName,
 		desc:       behavior.desc,
@@ -603,13 +610,13 @@ func equalConfigs(a, b aggregator.Config) bool {
 	return a == b
 }
 
-// pickAggConfig returns the aggregator configuration prescribed by a view clause
-// if it is not empty, otherwise the default value.
-func pickAggConfig(def, vcfg aggregator.Config) aggregator.Config {
-	if vcfg != (aggregator.Config{}) {
-		return vcfg
+// pickAggConfig returns the aggregator configuration prescribed by a
+// view clause when it not the default value, otherwise the hinted config.
+func pickAggConfig(hintCfg, defCfg, viewCfg aggregator.Config) aggregator.Config {
+	if viewCfg != defCfg {
+		return viewCfg
 	}
-	return def
+	return hintCfg
 }
 
 // checkSemanticCompatibility checks whether an instrument /
diff --git a/lightstep/sdk/metric/provider.go b/lightstep/sdk/metric/provider.go
index d0f0c04..3b9076d 100644
--- a/lightstep/sdk/metric/provider.go
+++ b/lightstep/sdk/metric/provider.go
@@ -23,6 +23,8 @@ import (
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/internal/pipeline"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/internal/viewstate"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/sdkinstrument"
+	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/view"
+	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/metric"
 	"go.opentelemetry.io/otel/sdk/instrumentation"
 	"go.opentelemetry.io/otel/sdk/resource"
@@ -38,6 +40,7 @@ type MeterProvider struct {
 	startTime time.Time
 	lock      sync.Mutex
 	ordered   []*meter
+	views     []*view.Views
 	meters    map[instrumentation.Library]*meter
 }
 
@@ -60,13 +63,22 @@ func NewMeterProvider(options ...Option) *MeterProvider {
 		cfg = option.apply(cfg)
 	}
 	cfg.performance = cfg.performance.Validate()
+
 	p := &MeterProvider{
 		cfg:       cfg,
 		startTime: time.Now(),
 		meters:    map[instrumentation.Library]*meter{},
 	}
 	for pipe := 0; pipe < len(cfg.readers); pipe++ {
-		cfg.readers[pipe].Register(p.producerFor(pipe))
+		r := cfg.readers[pipe]
+
+		v, err := view.Validate(view.New(r.String(), cfg.performance, cfg.vopts[pipe]...))
+		if err != nil {
+			otel.Handle(err)
+		}
+		p.views = append(p.views, v)
+
+		r.Register(p.producerFor(pipe))
 	}
 	return p
 }
@@ -106,7 +118,7 @@ func (mp *MeterProvider) Meter(name string, options ...metric.MeterOption) metri
 		compilers: pipeline.NewRegister[*viewstate.Compiler](len(mp.cfg.readers)),
 	}
 	for pipe := range m.compilers {
-		m.compilers[pipe] = viewstate.New(lib, mp.cfg.views[pipe])
+		m.compilers[pipe] = viewstate.New(lib, mp.views[pipe])
 	}
 	mp.ordered = append(mp.ordered, m)
 	mp.meters[lib] = m
diff --git a/lightstep/sdk/metric/sdkinstrument/performance.go b/lightstep/sdk/metric/sdkinstrument/performance.go
index e37495c..5ec397c 100644
--- a/lightstep/sdk/metric/sdkinstrument/performance.go
+++ b/lightstep/sdk/metric/sdkinstrument/performance.go
@@ -18,6 +18,15 @@ package sdkinstrument
 // delay before removing records from memory.
 const DefaultInactiveCollectionPeriods = 10
 
+// DefaultAggregatorCardinalityLimit is a hard limit on the number of
+// aggregators that can be emitted in a single period.
+const DefaultAggregatorCardinalityLimit = 2000
+
+// DefaultInstrumentCardinalityLimit is a hard limit on the number of
+// aggregators that can be accumulated in intermediate state belonging
+// to the instrument.
+const DefaultInstrumentCardinalityLimit = 3000
+
 // Performace configures features that allow the user to control
 // performance.
 type Performance struct {
@@ -30,6 +39,15 @@ type Performance struct {
 	// collection periods having no updates before the record is
 	// removed from memory.
 	InactiveCollectionPeriods uint32
+
+	// InstrumentCardinalityLimit is the point at which the
+	// SDK's emergency overflow breaker begins dropping attributes
+	// to avoid memory buildup at intermediate pipeline stages.
+	InstrumentCardinalityLimit uint32
+
+	// AggregatorCardinalityLimit is a hard limit on output
+	// cardinality for all aggregators in the SDK.
+	AggregatorCardinalityLimit uint32
 }
 
 // Validate returns a Performance object with 0 values replaced by
@@ -41,5 +59,12 @@ func (p Performance) Validate() Performance {
 	if p.InactiveCollectionPeriods == 0 {
 		p.InactiveCollectionPeriods = DefaultInactiveCollectionPeriods
 	}
+	if p.InstrumentCardinalityLimit == 0 {
+		p.InstrumentCardinalityLimit = DefaultInstrumentCardinalityLimit
+	}
+	if p.AggregatorCardinalityLimit == 0 {
+		p.AggregatorCardinalityLimit = DefaultAggregatorCardinalityLimit
+	}
+
 	return p
 }
diff --git a/lightstep/sdk/metric/view/standard.go b/lightstep/sdk/metric/view/standard.go
index 6ec43c8..3b54914 100644
--- a/lightstep/sdk/metric/view/standard.go
+++ b/lightstep/sdk/metric/view/standard.go
@@ -54,7 +54,16 @@ func DeltaPreferredTemporality(ik sdkinstrument.Kind) aggregation.Temporality {
 	}
 }
 
-// StandardConfig returns a function that configures two default aggregator.Configs.
-func StandardConfig(ik sdkinstrument.Kind) (ints, floats aggregator.Config) {
-	return aggregator.Config{}, aggregator.Config{}
+// StandardConfigForPerformance returns a function that configures two
+// default aggregator.Configs using the specified performance
+// defaults.
+func StandardConfigForPerformance(perf sdkinstrument.Performance) func(ik sdkinstrument.Kind) (ints, floats aggregator.Config) {
+	perf = perf.Validate()
+	return func(ik sdkinstrument.Kind) (ints, floats aggregator.Config) {
+		return aggregator.Config{
+				CardinalityLimit: perf.AggregatorCardinalityLimit,
+			}, aggregator.Config{
+				CardinalityLimit: perf.AggregatorCardinalityLimit,
+			}
+	}
 }
diff --git a/lightstep/sdk/metric/view/view.go b/lightstep/sdk/metric/view/view.go
index 9d6b0c6..0517eeb 100644
--- a/lightstep/sdk/metric/view/view.go
+++ b/lightstep/sdk/metric/view/view.go
@@ -108,7 +108,9 @@ func WithDefaultAggregationTemporalitySelector(d aggregation.TemporalitySelector
 func WithDefaultAggregationConfigSelector(d aggregator.ConfigSelector) Option {
 	return optionFunction(func(cfg Config) Config {
 		for k := sdkinstrument.Kind(0); k < sdkinstrument.NumKinds; k++ {
-			cfg.Defaults.ByInstrumentKind[k].Int64, cfg.Defaults.ByInstrumentKind[k].Float64 = d(k)
+			ic, fc := d(k)
+			cfg.Defaults.ByInstrumentKind[k].Int64 = ic
+			cfg.Defaults.ByInstrumentKind[k].Float64 = fc
 		}
 		return cfg
 	})
@@ -128,11 +130,11 @@ func (of optionFunction) apply(in Config) Config {
 }
 
 // NewConfig returns a new and configured view Config.
-func NewConfig(options ...Option) Config {
+func NewConfig(perf sdkinstrument.Performance, options ...Option) Config {
 	standard := []Option{
 		WithDefaultAggregationKindSelector(StandardAggregationKind),
 		WithDefaultAggregationTemporalitySelector(StandardTemporality),
-		WithDefaultAggregationConfigSelector(StandardConfig),
+		WithDefaultAggregationConfigSelector(StandardConfigForPerformance(perf)),
 	}
 	var cfg Config
 	for _, option := range append(standard, options...) {
diff --git a/lightstep/sdk/metric/view/views.go b/lightstep/sdk/metric/view/views.go
index e06460d..3f89e7a 100644
--- a/lightstep/sdk/metric/view/views.go
+++ b/lightstep/sdk/metric/view/views.go
@@ -30,17 +30,22 @@ type Views struct {
 
 	// Config is the configuration for these views.
 	Config
+
+	// Performance defaults used in these views.
+	sdkinstrument.Performance
 }
 
 // New configures the clauses and default settings of a Views.
-func New(name string, opts ...Option) *Views {
+func New(name string, perf sdkinstrument.Performance, opts ...Option) *Views {
+	perf = perf.Validate()
 	return &Views{
-		Name:   name,
-		Config: NewConfig(opts...),
+		Name:        name,
+		Config:      NewConfig(perf, opts...),
+		Performance: perf,
 	}
 }
 
-func checkAggregation(err error, agg *aggregation.Kind, def aggregation.Kind) error {
+func (v *Views) checkAggregation(err error, agg *aggregation.Kind, def aggregation.Kind) error {
 	if !agg.Valid() {
 		err = multierr.Append(err, fmt.Errorf("invalid aggregation: %v", *agg))
 		*agg = def
@@ -48,7 +53,7 @@ func checkAggregation(err error, agg *aggregation.Kind, def aggregation.Kind) er
 	return err
 }
 
-func checkTemporality(err error, tempo *aggregation.Temporality, def aggregation.Temporality) error {
+func (v *Views) checkTemporality(err error, tempo *aggregation.Temporality, def aggregation.Temporality) error {
 	if !tempo.Valid() {
 		err = multierr.Append(err, fmt.Errorf("invalid temporality: %v", *tempo))
 		*tempo = def
@@ -56,8 +61,14 @@ func checkTemporality(err error, tempo *aggregation.Temporality, def aggregation
 	return err
 }
 
-func checkAggConfig(err error, acfg *aggregator.Config) error {
+func (v *Views) checkAggConfig(err error, acfg *aggregator.Config) error {
 	var newErr error
+	// Use performance-specific defaults.
+	if acfg.CardinalityLimit == 0 {
+		acfg.CardinalityLimit = v.AggregatorCardinalityLimit
+	}
+	// TODO: Use a Performance setting for default histogram size.
+	// the call to Validate below fills in the hard-coded default.
 	*acfg, newErr = acfg.Validate()
 	if newErr != nil {
 		err = multierr.Append(err, newErr)
@@ -86,10 +97,10 @@ func Validate(v *Views) (*Views, error) {
 	for i := range valid.Defaults.ByInstrumentKind {
 		kind := sdkinstrument.Kind(i)
 
-		err = checkAggregation(err, &valid.Defaults.ByInstrumentKind[i].Aggregation, StandardAggregationKind(kind))
-		err = checkTemporality(err, &valid.Defaults.ByInstrumentKind[i].Temporality, StandardTemporality(kind))
-		err = checkAggConfig(err, &valid.Defaults.ByInstrumentKind[i].Int64)
-		err = checkAggConfig(err, &valid.Defaults.ByInstrumentKind[i].Float64)
+		err = v.checkAggregation(err, &valid.Defaults.ByInstrumentKind[i].Aggregation, StandardAggregationKind(kind))
+		err = v.checkTemporality(err, &valid.Defaults.ByInstrumentKind[i].Temporality, StandardTemporality(kind))
+		err = v.checkAggConfig(err, &valid.Defaults.ByInstrumentKind[i].Int64)
+		err = v.checkAggConfig(err, &valid.Defaults.ByInstrumentKind[i].Float64)
 	}
 
 	for i := range valid.Clauses {
@@ -100,8 +111,8 @@ func Validate(v *Views) (*Views, error) {
 			err = multierr.Append(err, fmt.Errorf("multi-instrument view specifies a single name"))
 		}
 
-		err = checkAggregation(err, &clause.aggregation, aggregation.UndefinedKind)
-		err = checkAggConfig(err, &clause.acfg)
+		err = v.checkAggregation(err, &clause.aggregation, aggregation.UndefinedKind)
+		err = v.checkAggConfig(err, &clause.acfg)
 
 		if clause.instrumentName != "" && clause.instrumentNameRegexp != nil {
 			err = multierr.Append(err, fmt.Errorf("view has instrument name and regexp matches"))
diff --git a/pipelines/go.mod b/pipelines/go.mod
index b33ea23..21c506f 100644
--- a/pipelines/go.mod
+++ b/pipelines/go.mod
@@ -43,16 +43,16 @@ require (
 	go.opentelemetry.io/proto/otlp v0.19.0
 	go.uber.org/atomic v1.7.0 // indirect
 	go.uber.org/multierr v1.9.0 // indirect
-	golang.org/x/net v0.4.0 // indirect
-	golang.org/x/sys v0.4.0 // indirect
-	golang.org/x/text v0.5.0 // indirect
+	golang.org/x/net v0.7.0 // indirect
+	golang.org/x/sys v0.5.0 // indirect
+	golang.org/x/text v0.7.0 // indirect
 	google.golang.org/genproto v0.0.0-20221118155620-16455021b5e6 // indirect
 	google.golang.org/protobuf v1.28.1
 )
 
 require (
-	github.com/lightstep/otel-launcher-go/lightstep/instrumentation v1.13.4
-	github.com/lightstep/otel-launcher-go/lightstep/sdk/metric v1.13.4
+	github.com/lightstep/otel-launcher-go/lightstep/instrumentation v1.14.0
+	github.com/lightstep/otel-launcher-go/lightstep/sdk/metric v1.14.0
 	go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v0.35.0
 )
 
diff --git a/pipelines/go.sum b/pipelines/go.sum
index a340780..75f8aa8 100644
--- a/pipelines/go.sum
+++ b/pipelines/go.sum
@@ -285,8 +285,8 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU=
-golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
+golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 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=
@@ -333,8 +333,9 @@ golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
 golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -342,8 +343,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM=
-golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
diff --git a/tools/go.mod b/tools/go.mod
index ed9d904..75304d7 100644
--- a/tools/go.mod
+++ b/tools/go.mod
@@ -4,14 +4,15 @@ go 1.18
 
 require (
 	github.com/client9/misspell v0.3.4
-	github.com/golangci/golangci-lint v1.50.1
-	github.com/itchyny/gojq v0.12.10
-	golang.org/x/tools v0.3.0
+	github.com/golangci/golangci-lint v1.51.2
+	github.com/itchyny/gojq v0.12.12
+	golang.org/x/tools v0.7.0
 )
 
 require (
-	4d63.com/gochecknoglobals v0.1.0 // indirect
-	github.com/Abirdcfly/dupword v0.0.7 // indirect
+	4d63.com/gocheckcompilerdirectives v1.2.1 // indirect
+	4d63.com/gochecknoglobals v0.2.1 // indirect
+	github.com/Abirdcfly/dupword v0.0.9 // indirect
 	github.com/Antonboom/errname v0.1.7 // indirect
 	github.com/Antonboom/nilnil v0.1.1 // indirect
 	github.com/BurntSushi/toml v1.2.1 // indirect
@@ -21,38 +22,38 @@ require (
 	github.com/OpenPeeDeeP/depguard v1.1.1 // indirect
 	github.com/alexkohler/prealloc v1.0.0 // indirect
 	github.com/alingse/asasalint v0.0.11 // indirect
-	github.com/ashanbrown/forbidigo v1.3.0 // indirect
+	github.com/ashanbrown/forbidigo v1.4.0 // indirect
 	github.com/ashanbrown/makezero v1.1.1 // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bkielbasa/cyclop v1.2.0 // indirect
 	github.com/blizzy78/varnamelen v0.8.0 // indirect
-	github.com/bombsimon/wsl/v3 v3.3.0 // indirect
+	github.com/bombsimon/wsl/v3 v3.4.0 // indirect
 	github.com/breml/bidichk v0.2.3 // indirect
 	github.com/breml/errchkjson v0.3.0 // indirect
 	github.com/butuzov/ireturn v0.1.1 // indirect
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
 	github.com/charithe/durationcheck v0.0.9 // indirect
-	github.com/chavacava/garif v0.0.0-20220630083739-93517212f375 // indirect
+	github.com/chavacava/garif v0.0.0-20221024190013-b3ef35877348 // indirect
 	github.com/curioswitch/go-reassign v0.2.0 // indirect
-	github.com/daixiang0/gci v0.8.1 // indirect
+	github.com/daixiang0/gci v0.9.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/denis-tingaikin/go-header v0.4.3 // indirect
 	github.com/esimonov/ifshort v1.0.4 // indirect
 	github.com/ettle/strcase v0.1.1 // indirect
-	github.com/fatih/color v1.13.0 // indirect
+	github.com/fatih/color v1.14.1 // indirect
 	github.com/fatih/structtag v1.2.0 // indirect
 	github.com/firefart/nonamedreturns v1.0.4 // indirect
 	github.com/fsnotify/fsnotify v1.5.4 // indirect
 	github.com/fzipp/gocyclo v0.6.0 // indirect
-	github.com/go-critic/go-critic v0.6.5 // indirect
-	github.com/go-toolsmith/astcast v1.0.0 // indirect
-	github.com/go-toolsmith/astcopy v1.0.2 // indirect
-	github.com/go-toolsmith/astequal v1.0.3 // indirect
-	github.com/go-toolsmith/astfmt v1.0.0 // indirect
-	github.com/go-toolsmith/astp v1.0.0 // indirect
-	github.com/go-toolsmith/strparse v1.0.0 // indirect
-	github.com/go-toolsmith/typep v1.0.2 // indirect
-	github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b // indirect
+	github.com/go-critic/go-critic v0.6.7 // indirect
+	github.com/go-toolsmith/astcast v1.1.0 // indirect
+	github.com/go-toolsmith/astcopy v1.0.3 // indirect
+	github.com/go-toolsmith/astequal v1.1.0 // indirect
+	github.com/go-toolsmith/astfmt v1.1.0 // indirect
+	github.com/go-toolsmith/astp v1.1.0 // indirect
+	github.com/go-toolsmith/strparse v1.1.0 // indirect
+	github.com/go-toolsmith/typep v1.1.0 // indirect
+	github.com/go-xmlfmt/xmlfmt v1.1.2 // indirect
 	github.com/gobwas/glob v0.2.3 // indirect
 	github.com/gofrs/flock v0.8.1 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
@@ -62,11 +63,11 @@ require (
 	github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 // indirect
 	github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 // indirect
 	github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca // indirect
-	github.com/golangci/misspell v0.3.5 // indirect
+	github.com/golangci/misspell v0.4.0 // indirect
 	github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 // indirect
 	github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 // indirect
 	github.com/google/go-cmp v0.5.9 // indirect
-	github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 // indirect
+	github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 // indirect
 	github.com/gostaticanalysis/analysisutil v0.7.1 // indirect
 	github.com/gostaticanalysis/comment v1.4.2 // indirect
 	github.com/gostaticanalysis/forcetypeassert v0.1.0 // indirect
@@ -82,65 +83,66 @@ require (
 	github.com/jingyugao/rowserrcheck v1.1.1 // indirect
 	github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af // indirect
 	github.com/julz/importas v0.1.0 // indirect
-	github.com/kisielk/errcheck v1.6.2 // indirect
+	github.com/junk1tm/musttag v0.4.5 // indirect
+	github.com/kisielk/errcheck v1.6.3 // indirect
 	github.com/kisielk/gotool v1.0.0 // indirect
 	github.com/kkHAIKE/contextcheck v1.1.3 // indirect
 	github.com/kulti/thelper v0.6.3 // indirect
 	github.com/kunwardeep/paralleltest v1.0.6 // indirect
-	github.com/kyoh86/exportloopref v0.1.8 // indirect
+	github.com/kyoh86/exportloopref v0.1.11 // indirect
 	github.com/ldez/gomoddirectives v0.2.3 // indirect
-	github.com/ldez/tagliatelle v0.3.1 // indirect
-	github.com/leonklingele/grouper v1.1.0 // indirect
+	github.com/ldez/tagliatelle v0.4.0 // indirect
+	github.com/leonklingele/grouper v1.1.1 // indirect
 	github.com/lufeee/execinquery v1.2.1 // indirect
 	github.com/magiconair/properties v1.8.6 // indirect
 	github.com/maratori/testableexamples v1.0.0 // indirect
 	github.com/maratori/testpackage v1.1.0 // indirect
 	github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect
 	github.com/mattn/go-colorable v0.1.13 // indirect
-	github.com/mattn/go-isatty v0.0.16 // indirect
+	github.com/mattn/go-isatty v0.0.17 // indirect
 	github.com/mattn/go-runewidth v0.0.14 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
 	github.com/mbilski/exhaustivestruct v1.2.0 // indirect
-	github.com/mgechev/revive v1.2.4 // indirect
+	github.com/mgechev/revive v1.2.5 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/moricho/tparallel v0.2.1 // indirect
 	github.com/nakabonne/nestif v0.3.1 // indirect
 	github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 // indirect
-	github.com/nishanths/exhaustive v0.8.3 // indirect
+	github.com/nishanths/exhaustive v0.9.5 // indirect
 	github.com/nishanths/predeclared v0.2.2 // indirect
+	github.com/nunnatsa/ginkgolinter v0.8.1 // indirect
 	github.com/olekukonko/tablewriter v0.0.5 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pelletier/go-toml/v2 v2.0.5 // indirect
-	github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
-	github.com/polyfloyd/go-errorlint v1.0.5 // indirect
+	github.com/polyfloyd/go-errorlint v1.1.0 // indirect
 	github.com/prometheus/client_golang v1.12.1 // indirect
 	github.com/prometheus/client_model v0.2.0 // indirect
 	github.com/prometheus/common v0.32.1 // indirect
 	github.com/prometheus/procfs v0.7.3 // indirect
-	github.com/quasilyte/go-ruleguard v0.3.18 // indirect
-	github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f // indirect
+	github.com/quasilyte/go-ruleguard v0.3.19 // indirect
+	github.com/quasilyte/gogrep v0.5.0 // indirect
 	github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 // indirect
 	github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 // indirect
-	github.com/rivo/uniseg v0.2.0 // indirect
-	github.com/ryancurrah/gomodguard v1.2.4 // indirect
-	github.com/ryanrolds/sqlclosecheck v0.3.0 // indirect
-	github.com/sanposhiho/wastedassign/v2 v2.0.6 // indirect
+	github.com/rivo/uniseg v0.4.4 // indirect
+	github.com/ryancurrah/gomodguard v1.3.0 // indirect
+	github.com/ryanrolds/sqlclosecheck v0.4.0 // indirect
+	github.com/sanposhiho/wastedassign/v2 v2.0.7 // indirect
 	github.com/sashamelentyev/interfacebloat v1.1.0 // indirect
-	github.com/sashamelentyev/usestdlibvars v1.20.0 // indirect
-	github.com/securego/gosec/v2 v2.13.1 // indirect
+	github.com/sashamelentyev/usestdlibvars v1.23.0 // indirect
+	github.com/securego/gosec/v2 v2.15.0 // indirect
 	github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c // indirect
 	github.com/sirupsen/logrus v1.9.0 // indirect
 	github.com/sivchari/containedctx v1.0.2 // indirect
 	github.com/sivchari/nosnakecase v1.7.0 // indirect
-	github.com/sivchari/tenv v1.7.0 // indirect
+	github.com/sivchari/tenv v1.7.1 // indirect
 	github.com/sonatard/noctx v0.0.1 // indirect
-	github.com/sourcegraph/go-diff v0.6.1 // indirect
+	github.com/sourcegraph/go-diff v0.7.0 // indirect
 	github.com/spf13/afero v1.8.2 // indirect
 	github.com/spf13/cast v1.5.0 // indirect
-	github.com/spf13/cobra v1.6.0 // indirect
+	github.com/spf13/cobra v1.6.1 // indirect
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/spf13/viper v1.13.0 // indirect
@@ -149,11 +151,12 @@ require (
 	github.com/stretchr/objx v0.5.0 // indirect
 	github.com/stretchr/testify v1.8.1 // indirect
 	github.com/subosito/gotenv v1.4.1 // indirect
+	github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c // indirect
 	github.com/tdakkota/asciicheck v0.1.1 // indirect
 	github.com/tetafro/godot v1.4.11 // indirect
-	github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 // indirect
+	github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e // indirect
 	github.com/timonwong/loggercheck v0.9.3 // indirect
-	github.com/tomarrell/wrapcheck/v2 v2.7.0 // indirect
+	github.com/tomarrell/wrapcheck/v2 v2.8.0 // indirect
 	github.com/tommy-muehle/go-mnd/v2 v2.5.1 // indirect
 	github.com/ultraware/funlen v0.0.3 // indirect
 	github.com/ultraware/whitespace v0.0.5 // indirect
@@ -165,19 +168,19 @@ require (
 	go.uber.org/multierr v1.8.0 // indirect
 	go.uber.org/zap v1.17.0 // indirect
 	golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
-	golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 // indirect
-	golang.org/x/mod v0.7.0 // indirect
+	golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9 // indirect
+	golang.org/x/mod v0.9.0 // indirect
 	golang.org/x/sync v0.1.0 // indirect
-	golang.org/x/sys v0.2.0 // indirect
-	golang.org/x/text v0.4.0 // indirect
+	golang.org/x/sys v0.6.0 // indirect
+	golang.org/x/text v0.6.0 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect
-	honnef.co/go/tools v0.3.3 // indirect
+	honnef.co/go/tools v0.4.2 // indirect
 	mvdan.cc/gofumpt v0.4.0 // indirect
 	mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed // indirect
 	mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b // indirect
-	mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 // indirect
+	mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d // indirect
 )
diff --git a/tools/go.sum b/tools/go.sum
index 93b86ad..31936ad 100644
--- a/tools/go.sum
+++ b/tools/go.sum
@@ -1,5 +1,7 @@
-4d63.com/gochecknoglobals v0.1.0 h1:zeZSRqj5yCg28tCkIV/z/lWbwvNm5qnKVS15PI8nhD0=
-4d63.com/gochecknoglobals v0.1.0/go.mod h1:wfdC5ZjKSPr7CybKEcgJhUOgeAQW1+7WcyK8OvUilfo=
+4d63.com/gocheckcompilerdirectives v1.2.1 h1:AHcMYuw56NPjq/2y615IGg2kYkBdTvOaojYCBcRE7MA=
+4d63.com/gocheckcompilerdirectives v1.2.1/go.mod h1:yjDJSxmDTtIHHCqX0ufRYZDL6vQtMG7tJdKVeWwsqvs=
+4d63.com/gochecknoglobals v0.2.1 h1:1eiorGsgHOFOuoOiJDy2psSrQbRdIHrlge0IJIkUgDc=
+4d63.com/gochecknoglobals v0.2.1/go.mod h1:KRE8wtJB3CXCsb1xy421JfTHIIbmT3U5ruxw2Qu8fSU=
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
@@ -38,8 +40,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
-github.com/Abirdcfly/dupword v0.0.7 h1:z14n0yytA3wNO2gpCD/jVtp/acEXPGmYu0esewpBt6Q=
-github.com/Abirdcfly/dupword v0.0.7/go.mod h1:K/4M1kj+Zh39d2aotRwypvasonOyAMH1c/IZJzE0dmk=
+github.com/Abirdcfly/dupword v0.0.9 h1:MxprGjKq3yDBICXDgEEsyGirIXfMYXkLNT/agPsE1tk=
+github.com/Abirdcfly/dupword v0.0.9/go.mod h1:PzmHVLLZ27MvHSzV7eFmMXSFArWXZPZmfuuziuUrf2g=
 github.com/Antonboom/errname v0.1.7 h1:mBBDKvEYwPl4WFFNwec1CZO096G6vzK9vvDQzAwkako=
 github.com/Antonboom/errname v0.1.7/go.mod h1:g0ONh16msHIPgJSGsecu1G/dcF2hlYR/0SddnIAGavU=
 github.com/Antonboom/nilnil v0.1.1 h1:PHhrh5ANKFWRBh7TdYmyyq2gyT2lotnvFvvFbylF81Q=
@@ -65,8 +67,8 @@ github.com/alexkohler/prealloc v1.0.0 h1:Hbq0/3fJPQhNkN0dR95AVrr6R7tou91y0uHG5pO
 github.com/alexkohler/prealloc v1.0.0/go.mod h1:VetnK3dIgFBBKmg0YnD9F9x6Icjd+9cvfHR56wJVlKE=
 github.com/alingse/asasalint v0.0.11 h1:SFwnQXJ49Kx/1GghOFz1XGqHYKp21Kq1nHad/0WQRnw=
 github.com/alingse/asasalint v0.0.11/go.mod h1:nCaoMhw7a9kSJObvQyVzNTPBDbNpdocqrSP7t/cW5+I=
-github.com/ashanbrown/forbidigo v1.3.0 h1:VkYIwb/xxdireGAdJNZoo24O4lmnEWkactplBlWTShc=
-github.com/ashanbrown/forbidigo v1.3.0/go.mod h1:vVW7PEdqEFqapJe95xHkTfB1+XvZXBFg8t0sG2FIxmI=
+github.com/ashanbrown/forbidigo v1.4.0 h1:spdPbupaSqtWORq1Q4eHBoPBmHtwVyLKwaedbSLc5Sw=
+github.com/ashanbrown/forbidigo v1.4.0/go.mod h1:IvgwB5Y4fzqSAj/WVXKWigoTkB0dzI2FBbpKWuh7ph8=
 github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s=
 github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
@@ -77,8 +79,8 @@ github.com/bkielbasa/cyclop v1.2.0 h1:7Jmnh0yL2DjKfw28p86YTd/B4lRGcNuu12sKE35sM7
 github.com/bkielbasa/cyclop v1.2.0/go.mod h1:qOI0yy6A7dYC4Zgsa72Ppm9kONl0RoIlPbzot9mhmeI=
 github.com/blizzy78/varnamelen v0.8.0 h1:oqSblyuQvFsW1hbBHh1zfwrKe3kcSj0rnXkKzsQ089M=
 github.com/blizzy78/varnamelen v0.8.0/go.mod h1:V9TzQZ4fLJ1DSrjVDfl89H7aMnTvKkApdHeyESmyR7k=
-github.com/bombsimon/wsl/v3 v3.3.0 h1:Mka/+kRLoQJq7g2rggtgQsjuI/K5Efd87WX96EWFxjM=
-github.com/bombsimon/wsl/v3 v3.3.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc=
+github.com/bombsimon/wsl/v3 v3.4.0 h1:RkSxjT3tmlptwfgEgTgU+KYKLI35p/tviNXNXiL2aNU=
+github.com/bombsimon/wsl/v3 v3.4.0/go.mod h1:KkIB+TXkqy6MvK9BDZVbZxKNYsE1/oLRJbIFtf14qqo=
 github.com/breml/bidichk v0.2.3 h1:qe6ggxpTfA8E75hdjWPZ581sY3a2lnl0IRxLQFelECI=
 github.com/breml/bidichk v0.2.3/go.mod h1:8u2C6DnAy0g2cEq+k/A2+tr9O1s+vHGxWn0LTc70T2A=
 github.com/breml/errchkjson v0.3.0 h1:YdDqhfqMT+I1vIxPSas44P+9Z9HzJwCeAzjB8PxP1xw=
@@ -91,8 +93,8 @@ github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cb
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/charithe/durationcheck v0.0.9 h1:mPP4ucLrf/rKZiIG/a9IPXHGlh8p4CzgpyTy6EEutYk=
 github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg=
-github.com/chavacava/garif v0.0.0-20220630083739-93517212f375 h1:E7LT642ysztPWE0dfz43cWOvMiF42DyTRC+eZIaO4yI=
-github.com/chavacava/garif v0.0.0-20220630083739-93517212f375/go.mod h1:4m1Rv7xfuwWPNKXlThldNuJvutYM6J95wNuuVmn55To=
+github.com/chavacava/garif v0.0.0-20221024190013-b3ef35877348 h1:cy5GCEZLUCshCGCRRUjxHrDUqkB4l5cuUt3ShEckQEo=
+github.com/chavacava/garif v0.0.0-20221024190013-b3ef35877348/go.mod h1:f/miWtG3SSuTxKsNK3o58H1xl+XV6ZIfbC6p7lPPB8U=
 github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
@@ -102,12 +104,10 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
 github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
-github.com/cristalhq/acmd v0.8.1/go.mod h1:LG5oa43pE/BbxtfMoImHCQN++0Su7dzipdgBjMCBVDQ=
 github.com/curioswitch/go-reassign v0.2.0 h1:G9UZyOcpk/d7Gd6mqYgd8XYWFMw/znxwGDUstnC9DIo=
 github.com/curioswitch/go-reassign v0.2.0/go.mod h1:x6OpXuWvgfQaMGks2BZybTngWjT84hqJfKoO8Tt/Roc=
-github.com/daixiang0/gci v0.8.1 h1:T4xpSC+hmsi4CSyuYfIJdMZAr9o7xZmHpQVygMghGZ4=
-github.com/daixiang0/gci v0.8.1/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c=
+github.com/daixiang0/gci v0.9.1 h1:jBrwBmBZTDsGsXiaCTLIe9diotp1X4X64zodFrh7l+c=
+github.com/daixiang0/gci v0.9.1/go.mod h1:EpVfrztufwVgQRXjnX4zuNinEpLj5OmMjtu/+MB0V0c=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -123,8 +123,8 @@ github.com/esimonov/ifshort v1.0.4 h1:6SID4yGWfRae/M7hkVDVVyppy8q/v9OuxNdmjLQStB
 github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcHcfgNWTk0=
 github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw=
 github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY=
-github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
-github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
+github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
+github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
 github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
 github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
 github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y=
@@ -134,8 +134,8 @@ github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwV
 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
 github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo=
 github.com/fzipp/gocyclo v0.6.0/go.mod h1:rXPyn8fnlpa0R2csP/31uerbiVBugk5whMdlyaLkLoA=
-github.com/go-critic/go-critic v0.6.5 h1:fDaR/5GWURljXwF8Eh31T2GZNz9X4jeboS912mWF8Uo=
-github.com/go-critic/go-critic v0.6.5/go.mod h1:ezfP/Lh7MA6dBNn4c6ab5ALv3sKnZVLx37tr00uuaOY=
+github.com/go-critic/go-critic v0.6.7 h1:1evPrElnLQ2LZtJfmNDzlieDhjnq36SLgNzisx06oPM=
+github.com/go-critic/go-critic v0.6.7/go.mod h1:fYZUijFdcnxgx6wPjQA2QEjIRaNCT0gO8bhexy6/QmE=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -145,28 +145,28 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
-github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/go-toolsmith/astcast v1.0.0 h1:JojxlmI6STnFVG9yOImLeGREv8W2ocNUM+iOhR6jE7g=
-github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
-github.com/go-toolsmith/astcopy v1.0.2 h1:YnWf5Rnh1hUudj11kei53kI57quN/VH6Hp1n+erozn0=
-github.com/go-toolsmith/astcopy v1.0.2/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y=
-github.com/go-toolsmith/astequal v1.0.0/go.mod h1:H+xSiq0+LtiDC11+h1G32h7Of5O3CYFJ99GVbS5lDKY=
+github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8=
+github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU=
+github.com/go-toolsmith/astcopy v1.0.3 h1:r0bgSRlMOAgO+BdQnVAcpMSMkrQCnV6ZJmIkrJgcJj0=
+github.com/go-toolsmith/astcopy v1.0.3/go.mod h1:4TcEdbElGc9twQEYpVo/aieIXfHhiuLh4aLAck6dO7Y=
 github.com/go-toolsmith/astequal v1.0.2/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
-github.com/go-toolsmith/astequal v1.0.3 h1:+LVdyRatFS+XO78SGV4I3TCEA0AC7fKEGma+fH+674o=
 github.com/go-toolsmith/astequal v1.0.3/go.mod h1:9Ai4UglvtR+4up+bAD4+hCj7iTo4m/OXVTSLnCyTAx4=
-github.com/go-toolsmith/astfmt v1.0.0 h1:A0vDDXt+vsvLEdbMFJAUBI/uTbRw1ffOPnxsILnFL6k=
-github.com/go-toolsmith/astfmt v1.0.0/go.mod h1:cnWmsOAuq4jJY6Ct5YWlVLmcmLMn1JUPuQIHCY7CJDw=
-github.com/go-toolsmith/astp v1.0.0 h1:alXE75TXgcmupDsMK1fRAy0YUzLzqPVvBKoyWV+KPXg=
-github.com/go-toolsmith/astp v1.0.0/go.mod h1:RSyrtpVlfTFGDYRbrjyWP1pYu//tSFcvdYrA8meBmLI=
+github.com/go-toolsmith/astequal v1.1.0 h1:kHKm1AWqClYn15R0K1KKE4RG614D46n+nqUQ06E1dTw=
+github.com/go-toolsmith/astequal v1.1.0/go.mod h1:sedf7VIdCL22LD8qIvv7Nn9MuWJruQA/ysswh64lffQ=
+github.com/go-toolsmith/astfmt v1.1.0 h1:iJVPDPp6/7AaeLJEruMsBUlOYCmvg0MoCfJprsOmcco=
+github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlNMV634mhwuQ4=
+github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA=
+github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA=
 github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5 h1:eD9POs68PHkwrx7hAB78z1cb6PfGq/jyWn3wJywsH1o=
-github.com/go-toolsmith/pkgload v1.0.2-0.20220101231613-e814995d17c5/go.mod h1:3NAwwmD4uY/yggRxoEjk/S00MIV3A+H7rrE3i87eYxM=
-github.com/go-toolsmith/strparse v1.0.0 h1:Vcw78DnpCAKlM20kSbAyO4mPfJn/lyYA4BJUDxe2Jb4=
 github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8=
-github.com/go-toolsmith/typep v1.0.2 h1:8xdsa1+FSIH/RhEkgnD1j2CJOy5mNllW1Q9tRiYwvlk=
-github.com/go-toolsmith/typep v1.0.2/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU=
-github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b h1:khEcpUM4yFcxg4/FHQWkvVRmgijNXRfzkIDHh23ggEo=
-github.com/go-xmlfmt/xmlfmt v0.0.0-20191208150333-d5b6f63a941b/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
+github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw=
+github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ=
+github.com/go-toolsmith/typep v1.1.0 h1:fIRYDyF+JywLfqzyhdiHzRop/GQDxxNhLGQ6gFUNHus=
+github.com/go-toolsmith/typep v1.1.0/go.mod h1:fVIw+7zjdsMxDA3ITWnH1yOiw1rnTQKCsF/sk2H/qig=
+github.com/go-xmlfmt/xmlfmt v1.1.2 h1:Nea7b4icn8s57fTx1M5AI4qQT5HEM3rVUO8MuE6g80U=
+github.com/go-xmlfmt/xmlfmt v1.1.2/go.mod h1:aUCEOzzezBEjDBbFBoSiya/gduyIiWYRP6CnSFIV8AM=
 github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
 github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
 github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
@@ -208,14 +208,14 @@ github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe h1:6RGUuS7EGotKx6
 github.com/golangci/go-misc v0.0.0-20220329215616-d24fe342adfe/go.mod h1:gjqyPShc/m8pEMpk0a3SeagVb0kaqvhscv+i9jI5ZhQ=
 github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2 h1:amWTbTGqOZ71ruzrdA+Nx5WA3tV1N0goTspwmKCQvBY=
 github.com/golangci/gofmt v0.0.0-20220901101216-f2edd75033f2/go.mod h1:9wOXstvyDRshQ9LggQuzBCGysxs3b6Uo/1MvYCR2NMs=
-github.com/golangci/golangci-lint v1.50.1 h1:C829clMcZXEORakZlwpk7M4iDw2XiwxxKaG504SZ9zY=
-github.com/golangci/golangci-lint v1.50.1/go.mod h1:AQjHBopYS//oB8xs0y0M/dtxdKHkdhl0RvmjUct0/4w=
+github.com/golangci/golangci-lint v1.51.2 h1:yIcsT1X9ZYHdSpeWXRT1ORC/FPGSqDHbHsu9uk4FK7M=
+github.com/golangci/golangci-lint v1.51.2/go.mod h1:KH9Q7/3glwpYSknxUgUyLlAv46A8fsSKo1hH2wDvkr8=
 github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0 h1:MfyDlzVjl1hoaPzPD4Gpb/QgoRfSBR0jdhwGyAWwMSA=
 github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
 github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca h1:kNY3/svz5T29MYHubXix4aDDuE3RWHkPvopM/EDv/MA=
 github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
-github.com/golangci/misspell v0.3.5 h1:pLzmVdl3VxTOncgzHcvLOKirdvcx/TydsClUQXTehjo=
-github.com/golangci/misspell v0.3.5/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA=
+github.com/golangci/misspell v0.4.0 h1:KtVB/hTK4bbL/S6bs64rYyk8adjmh1BygbBiaAiX+a0=
+github.com/golangci/misspell v0.4.0/go.mod h1:W6O/bwV6lGDxUCChm2ykw9NQdd5bYd1Xkjo88UcWyJc=
 github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6 h1:DIPQnGy2Gv2FSA4B/hh8Q7xx3B7AIDk3DAMeHclH1vQ=
 github.com/golangci/revgrep v0.0.0-20220804021717-745bb2f7c2e6/go.mod h1:0AKcRCkMoKvUvlf89F6O7H2LYdhr1zBh736mBItOdRs=
 github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4 h1:zwtduBRr5SSWhqsYNgcuWO2kFlpdOZbP0+yRjmvPGys=
@@ -254,9 +254,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
 github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
-github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8 h1:PVRE9d4AQKmbelZ7emNig1+NT27DUmKZn5qXxfio54U=
-github.com/gordonklaus/ineffassign v0.0.0-20210914165742-4cc7213b9bc8/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
-github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
+github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28 h1:9alfqbrhuD+9fLZ4iaAVwhlp5PEhmnBt7yvK2Oy5C1U=
+github.com/gordonklaus/ineffassign v0.0.0-20230107090616-13ace0543b28/go.mod h1:Qcp2HIAYhR7mNUVSIxZww3Guk4it82ghYcEXIAk+QT0=
 github.com/gostaticanalysis/analysisutil v0.0.3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE=
 github.com/gostaticanalysis/analysisutil v0.1.0/go.mod h1:dMhHRU9KTiDcuLGdy87/2gTR8WruwYZrKdRq9m1O6uw=
 github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk=
@@ -288,8 +287,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
 github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
-github.com/itchyny/gojq v0.12.10 h1:6TcS0VYWS6wgntpF/4tnrzwdCMjiTxRAxIqZWfDsDQU=
-github.com/itchyny/gojq v0.12.10/go.mod h1:o3FT8Gkbg/geT4pLI0tF3hvip5F3Y/uskjRz9OYa38g=
+github.com/itchyny/gojq v0.12.12 h1:x+xGI9BXqKoJQZkr95ibpe3cdrTbY8D9lonrK433rcA=
+github.com/itchyny/gojq v0.12.12/go.mod h1:j+3sVkjxwd7A7Z5jrbKibgOLn0ZfLWkV+Awxr/pyzJE=
 github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE=
 github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8=
 github.com/jgautheron/goconst v1.5.1 h1:HxVbL1MhydKs8R8n/HE5NPvzfaYmQJA3o879lE4+WcM=
@@ -298,7 +297,6 @@ github.com/jingyugao/rowserrcheck v1.1.1 h1:zibz55j/MJtLsjP1OF4bSdgXxwL1b+Vn7Tjz
 github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
 github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af h1:KA9BjwUk7KlCh6S9EAGWBt1oExIUv9WyNCiRz5amv48=
 github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
-github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -310,8 +308,10 @@ github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7V
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
 github.com/julz/importas v0.1.0 h1:F78HnrsjY3cR7j0etXy5+TU1Zuy7Xt08X/1aJnH5xXY=
 github.com/julz/importas v0.1.0/go.mod h1:oSFU2R4XK/P7kNBrnL/FEQlDGN1/6WoxXEjSSXO0DV0=
-github.com/kisielk/errcheck v1.6.2 h1:uGQ9xI8/pgc9iOoCe7kWQgRE6SBTrCGmTSf0LrEtY7c=
-github.com/kisielk/errcheck v1.6.2/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw=
+github.com/junk1tm/musttag v0.4.5 h1:d+mpJ1vn6WFEVKHwkgJiIedis1u/EawKOuUTygAUtCo=
+github.com/junk1tm/musttag v0.4.5/go.mod h1:XkcL/9O6RmD88JBXb+I15nYRl9W4ExhgQeCBEhfMC8U=
+github.com/kisielk/errcheck v1.6.3 h1:dEKh+GLHcWm2oN34nMvDzn1sqI0i0WxPvrgiJA5JuM8=
+github.com/kisielk/errcheck v1.6.3/go.mod h1:nXw/i/MfnvRHqXa7XXmQMUB0oNFGuBrNI8d8NLy0LPw=
 github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/kkHAIKE/contextcheck v1.1.3 h1:l4pNvrb8JSwRd51ojtcOxOeHJzHek+MtOyXbaR0uvmw=
@@ -326,20 +326,18 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs=
 github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I=
 github.com/kunwardeep/paralleltest v1.0.6 h1:FCKYMF1OF2+RveWlABsdnmsvJrei5aoyZoaGS+Ugg8g=
 github.com/kunwardeep/paralleltest v1.0.6/go.mod h1:Y0Y0XISdZM5IKm3TREQMZ6iteqn1YuwCsJO/0kL9Zes=
-github.com/kyoh86/exportloopref v0.1.8 h1:5Ry/at+eFdkX9Vsdw3qU4YkvGtzuVfzT4X7S77LoN/M=
-github.com/kyoh86/exportloopref v0.1.8/go.mod h1:1tUcJeiioIs7VWe5gcOObrux3lb66+sBqGZrRkMwPgg=
+github.com/kyoh86/exportloopref v0.1.11 h1:1Z0bcmTypkL3Q4k+IDHMWTcnCliEZcaPiIe0/ymEyhQ=
+github.com/kyoh86/exportloopref v0.1.11/go.mod h1:qkV4UF1zGl6EkF1ox8L5t9SwyeBAZ3qLMd6up458uqA=
 github.com/ldez/gomoddirectives v0.2.3 h1:y7MBaisZVDYmKvt9/l1mjNCiSA1BVn34U0ObUcJwlhA=
 github.com/ldez/gomoddirectives v0.2.3/go.mod h1:cpgBogWITnCfRq2qGoDkKMEVSaarhdBr6g8G04uz6d0=
-github.com/ldez/tagliatelle v0.3.1 h1:3BqVVlReVUZwafJUwQ+oxbx2BEX2vUG4Yu/NOfMiKiM=
-github.com/ldez/tagliatelle v0.3.1/go.mod h1:8s6WJQwEYHbKZDsp/LjArytKOG8qaMrKQQ3mFukHs88=
-github.com/leonklingele/grouper v1.1.0 h1:tC2y/ygPbMFSBOs3DcyaEMKnnwH7eYKzohOtRrf0SAg=
-github.com/leonklingele/grouper v1.1.0/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY=
-github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/ldez/tagliatelle v0.4.0 h1:sylp7d9kh6AdXN2DpVGHBRb5guTVAgOxqNGhbqc4b1c=
+github.com/ldez/tagliatelle v0.4.0/go.mod h1:mNtTfrHy2haaBAw+VT7IBV6VXBThS7TCreYWbBcJ87I=
+github.com/leonklingele/grouper v1.1.1 h1:suWXRU57D4/Enn6pXR0QVqqWWrnJ9Osrz+5rjt8ivzU=
+github.com/leonklingele/grouper v1.1.1/go.mod h1:uk3I3uDfi9B6PeUjsCKi6ndcf63Uy7snXgR4yDYQVDY=
 github.com/lufeee/execinquery v1.2.1 h1:hf0Ems4SHcUGBxpGN7Jz78z1ppVkP/837ZlETPCEtOM=
 github.com/lufeee/execinquery v1.2.1/go.mod h1:EC7DrEKView09ocscGHC+apXMIaorh4xqSxS/dy8SbM=
 github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
@@ -352,23 +350,20 @@ github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 h1:pWxk9e//NbPwfxat7
 github.com/matoous/godox v0.0.0-20210227103229-6504466cf951/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
 github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
 github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
-github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
 github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
 github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
+github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
 github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
 github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/mbilski/exhaustivestruct v1.2.0 h1:wCBmUnSYufAHO6J4AVWY6ff+oxWxsVFrwgOdMUQePUo=
 github.com/mbilski/exhaustivestruct v1.2.0/go.mod h1:OeTBVxQWoEmB2J2JCHmXWPJ0aksxSUOUy+nvtVEfzXc=
-github.com/mgechev/revive v1.2.4 h1:+2Hd/S8oO2H0Ikq2+egtNwQsVhAeELHjxjIUFX5ajLI=
-github.com/mgechev/revive v1.2.4/go.mod h1:iAWlQishqCuj4yhV24FTnKSXGpbAA+0SckXB8GQMX/Q=
+github.com/mgechev/revive v1.2.5 h1:UF9AR8pOAuwNmhXj2odp4mxv9Nx2qUIwVz8ZsU+Mbec=
+github.com/mgechev/revive v1.2.5/go.mod h1:nFOXent79jMTISAfOAasKfy0Z2Ejq0WX7Qn/KAdYopI=
 github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
@@ -386,15 +381,16 @@ github.com/nakabonne/nestif v0.3.1 h1:wm28nZjhQY5HyYPx+weN3Q65k6ilSBxDb8v5S81B81
 github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4Ngq6aY7OE=
 github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA=
 github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/nishanths/exhaustive v0.8.3 h1:pw5O09vwg8ZaditDp/nQRqVnrMczSJDxRDJMowvhsrM=
-github.com/nishanths/exhaustive v0.8.3/go.mod h1:qj+zJJUgJ76tR92+25+03oYUhzF4R7/2Wk7fGTfCHmg=
+github.com/nishanths/exhaustive v0.9.5 h1:TzssWan6orBiLYVqewCG8faud9qlFntJE30ACpzmGME=
+github.com/nishanths/exhaustive v0.9.5/go.mod h1:IbwrGdVMizvDcIxPYGVdQn5BqWJaOwpCvg4RGb8r/TA=
 github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk=
 github.com/nishanths/predeclared v0.2.2/go.mod h1:RROzoN6TnGQupbC+lqggsOlcgysk3LMK/HI84Mp280c=
+github.com/nunnatsa/ginkgolinter v0.8.1 h1:/y4o/0hV+ruUHj4xXh89xlFjoaitnI4LnkpuYs02q1c=
+github.com/nunnatsa/ginkgolinter v0.8.1/go.mod h1:FYYLtszIdmzCH8XMaMPyxPVXZ7VCaIm55bA+gugx+14=
 github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
 github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
-github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
-github.com/onsi/gomega v1.20.0 h1:8W0cWlwFkflGPLltQvLRB7ZVD5HuP6ng320w2IS245Q=
+github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI=
+github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q=
 github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k=
 github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
 github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
@@ -405,8 +401,6 @@ github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3v
 github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
 github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg=
 github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
-github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d h1:CdDQnGF8Nq9ocOS/xlSptM1N3BbrA6/kmaep5ggwaIA=
-github.com/phayes/checkstyle v0.0.0-20170904204023-bfd46e6a821d/go.mod h1:3OzsM7FXDQlpCiw2j81fOmAwQLnZnLGXVKUzeKQXIAw=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -414,8 +408,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/polyfloyd/go-errorlint v1.0.5 h1:AHB5JRCjlmelh9RrLxT9sgzpalIwwq4hqE8EkwIwKdY=
-github.com/polyfloyd/go-errorlint v1.0.5/go.mod h1:APVvOesVSAnne5SClsPxPdfvZTVDojXh1/G3qb5wjGI=
+github.com/polyfloyd/go-errorlint v1.1.0 h1:VKoEFg5yxSgJ2yFPVhxW7oGz+f8/OVcuMeNvcPIi6Eg=
+github.com/polyfloyd/go-errorlint v1.1.0/go.mod h1:Uss7Bc/izYG0leCMRx3WVlrpqWedSZk7V/FUQW6VJ6U=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
 github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
 github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
@@ -438,36 +432,32 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
 github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
 github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
 github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
-github.com/quasilyte/go-ruleguard v0.3.1-0.20210203134552-1b5a410e1cc8/go.mod h1:KsAh3x0e7Fkpgs+Q9pNLS5XpFSvYCEVl5gP9Pp1xp30=
-github.com/quasilyte/go-ruleguard v0.3.18 h1:sd+abO1PEI9fkYennwzHn9kl3nqP6M5vE7FiOzZ+5CE=
-github.com/quasilyte/go-ruleguard v0.3.18/go.mod h1:lOIzcYlgxrQ2sGJ735EHXmf/e9MJ516j16K/Ifcttvs=
-github.com/quasilyte/go-ruleguard/dsl v0.3.0/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
-github.com/quasilyte/go-ruleguard/dsl v0.3.21/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU=
-github.com/quasilyte/go-ruleguard/rules v0.0.0-20201231183845-9e62ed36efe1/go.mod h1:7JTjp89EGyU1d6XfBiXihJNG37wB2VRkd125Q1u7Plc=
-github.com/quasilyte/go-ruleguard/rules v0.0.0-20211022131956-028d6511ab71/go.mod h1:4cgAphtvu7Ftv7vOT2ZOYhC6CvBxZixcasr8qIOTA50=
-github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f h1:6Gtn2i04RD0gVyYf2/IUMTIs+qYleBt4zxDqkLTcu4U=
-github.com/quasilyte/gogrep v0.0.0-20220828223005-86e4605de09f/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng=
+github.com/quasilyte/go-ruleguard v0.3.19 h1:tfMnabXle/HzOb5Xe9CUZYWXKfkS1KwRmZyPmD9nVcc=
+github.com/quasilyte/go-ruleguard v0.3.19/go.mod h1:lHSn69Scl48I7Gt9cX3VrbsZYvYiBYszZOZW4A+oTEw=
+github.com/quasilyte/gogrep v0.5.0 h1:eTKODPXbI8ffJMN+W2aE0+oL0z/nh8/5eNdiO34SOAo=
+github.com/quasilyte/gogrep v0.5.0/go.mod h1:Cm9lpz9NZjEoL1tgZ2OgeUKPIxL1meE7eo60Z6Sk+Ng=
 github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95 h1:L8QM9bvf68pVdQ3bCFZMDmnt9yqcMBro1pC7F+IPYMY=
 github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
 github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4lu7Gd+PU1fV2/qnDNfzT635KRSObncs=
 github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
 github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
+github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/ryancurrah/gomodguard v1.2.4 h1:CpMSDKan0LtNGGhPrvupAoLeObRFjND8/tU1rEOtBp4=
-github.com/ryancurrah/gomodguard v1.2.4/go.mod h1:+Kem4VjWwvFpUJRJSwa16s1tBJe+vbv02+naTow2f6M=
-github.com/ryanrolds/sqlclosecheck v0.3.0 h1:AZx+Bixh8zdUBxUA1NxbxVAS78vTPq4rCb8OUZI9xFw=
-github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA=
-github.com/sanposhiho/wastedassign/v2 v2.0.6 h1:+6/hQIHKNJAUixEj6EmOngGIisyeI+T3335lYTyxRoA=
-github.com/sanposhiho/wastedassign/v2 v2.0.6/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
+github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw=
+github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50=
+github.com/ryanrolds/sqlclosecheck v0.4.0 h1:i8SX60Rppc1wRuyQjMciLqIzV3xnoHB7/tXbr6RGYNI=
+github.com/ryanrolds/sqlclosecheck v0.4.0/go.mod h1:TBRRjzL31JONc9i4XMinicuo+s+E8yKZ5FN8X3G6CKQ=
+github.com/sanposhiho/wastedassign/v2 v2.0.7 h1:J+6nrY4VW+gC9xFzUc+XjPD3g3wF3je/NsJFwFK7Uxc=
+github.com/sanposhiho/wastedassign/v2 v2.0.7/go.mod h1:KyZ0MWTwxxBmfwn33zh3k1dmsbF2ud9pAAGfoLfjhtI=
 github.com/sashamelentyev/interfacebloat v1.1.0 h1:xdRdJp0irL086OyW1H/RTZTr1h/tMEOsumirXcOJqAw=
 github.com/sashamelentyev/interfacebloat v1.1.0/go.mod h1:+Y9yU5YdTkrNvoX0xHc84dxiN1iBi9+G8zZIhPVoNjQ=
-github.com/sashamelentyev/usestdlibvars v1.20.0 h1:K6CXjqqtSYSsuyRDDC7Sjn6vTMLiSJa4ZmDkiokoqtw=
-github.com/sashamelentyev/usestdlibvars v1.20.0/go.mod h1:0GaP+ecfZMXShS0A94CJn6aEuPRILv8h/VuWI9n1ygg=
-github.com/securego/gosec/v2 v2.13.1 h1:7mU32qn2dyC81MH9L2kefnQyRMUarfDER3iQyMHcjYM=
-github.com/securego/gosec/v2 v2.13.1/go.mod h1:EO1sImBMBWFjOTFzMWfTRrZW6M15gm60ljzrmy/wtHo=
+github.com/sashamelentyev/usestdlibvars v1.23.0 h1:01h+/2Kd+NblNItNeux0veSL5cBF1jbEOPrEhDzGYq0=
+github.com/sashamelentyev/usestdlibvars v1.23.0/go.mod h1:YPwr/Y1LATzHI93CqoPUN/2BzGQ/6N/cl/KwgR0B/aU=
+github.com/securego/gosec/v2 v2.15.0 h1:v4Ym7FF58/jlykYmmhZ7mTm7FQvN/setNm++0fgIAtw=
+github.com/securego/gosec/v2 v2.15.0/go.mod h1:VOjTrZOkUtSDt2QLSJmQBMWnvwiQPEjg0l+5juIqGk8=
 github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c h1:W65qqJCIOVP4jpqPQ0YvHYKwcMEMVWIzWC5iNQQfBTU=
 github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
 github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
@@ -481,18 +471,18 @@ github.com/sivchari/containedctx v1.0.2 h1:0hLQKpgC53OVF1VT7CeoFHk9YKstur1XOgfYI
 github.com/sivchari/containedctx v1.0.2/go.mod h1:PwZOeqm4/DLoJOqMSIJs3aKqXRX4YO+uXww087KZ7Bw=
 github.com/sivchari/nosnakecase v1.7.0 h1:7QkpWIRMe8x25gckkFd2A5Pi6Ymo0qgr4JrhGt95do8=
 github.com/sivchari/nosnakecase v1.7.0/go.mod h1:CwDzrzPea40/GB6uynrNLiorAlgFRvRbFSgJx2Gs+QY=
-github.com/sivchari/tenv v1.7.0 h1:d4laZMBK6jpe5PWepxlV9S+LC0yXqvYHiq8E6ceoVVE=
-github.com/sivchari/tenv v1.7.0/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg=
+github.com/sivchari/tenv v1.7.1 h1:PSpuD4bu6fSmtWMxSGWcvqUUgIn7k3yOJhOIzVWn8Ak=
+github.com/sivchari/tenv v1.7.1/go.mod h1:64yStXKSOxDfX47NlhVwND4dHwfZDdbp2Lyl018Icvg=
 github.com/sonatard/noctx v0.0.1 h1:VC1Qhl6Oxx9vvWo3UDgrGXYCeKCe3Wbw7qAWL6FrmTY=
 github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI=
-github.com/sourcegraph/go-diff v0.6.1 h1:hmA1LzxW0n1c3Q4YbrFgg4P99GSnebYa3x8gr0HZqLQ=
-github.com/sourcegraph/go-diff v0.6.1/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
+github.com/sourcegraph/go-diff v0.7.0 h1:9uLlrd5T46OXs5qpp8L/MTltk0zikUGi0sNNyCpA8G0=
+github.com/sourcegraph/go-diff v0.7.0/go.mod h1:iBszgVvyxdc8SFZ7gm69go2KDdt3ag071iBaWPF6cjs=
 github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo=
 github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo=
 github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
 github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
-github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI=
-github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
+github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
+github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
 github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
 github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
 github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -520,6 +510,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs
 github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
 github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
+github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c h1:+aPplBwWcHBo6q9xrfWdMrT9o4kltkmmvpemgIjep/8=
+github.com/t-yuki/gocover-cobertura v0.0.0-20180217150009-aaee18c8195c/go.mod h1:SbErYREK7xXdsRiigaQiQkI9McGRzYMvlKYaP3Nimdk=
 github.com/tdakkota/asciicheck v0.1.1 h1:PKzG7JUTUmVspQTDqtkX9eSiLGossXTybutHwTXuO0A=
 github.com/tdakkota/asciicheck v0.1.1/go.mod h1:yHp0ai0Z9gUljN3o0xMhYJnH/IcvkdTBOX2fmJ93JEM=
 github.com/tenntenn/modver v1.0.1 h1:2klLppGhDgzJrScMpkj9Ujy3rXPUspSjAcev9tSEBgA=
@@ -528,12 +520,12 @@ github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3 h1:f+jULpR
 github.com/tenntenn/text/transform v0.0.0-20200319021203-7eef512accb3/go.mod h1:ON8b8w4BN/kE1EOhwT0o+d62W65a6aPw1nouo9LMgyY=
 github.com/tetafro/godot v1.4.11 h1:BVoBIqAf/2QdbFmSwAWnaIqDivZdOV0ZRwEm6jivLKw=
 github.com/tetafro/godot v1.4.11/go.mod h1:LR3CJpxDVGlYOWn3ZZg1PgNZdTUvzsZWu8xaEohUpn8=
-github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144 h1:kl4KhGNsJIbDHS9/4U9yQo1UcPQM0kOMJHn29EoH/Ro=
-github.com/timakin/bodyclose v0.0.0-20210704033933-f49887972144/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
+github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e h1:MV6KaVu/hzByHP0UvJ4HcMGE/8a6A4Rggc/0wx2AvJo=
+github.com/timakin/bodyclose v0.0.0-20221125081123-e39cf3fc478e/go.mod h1:27bSVNWSBOHm+qRp1T9qzaIpsWEP6TbUnei/43HK+PQ=
 github.com/timonwong/loggercheck v0.9.3 h1:ecACo9fNiHxX4/Bc02rW2+kaJIAMAes7qJ7JKxt0EZI=
 github.com/timonwong/loggercheck v0.9.3/go.mod h1:wUqnk9yAOIKtGA39l1KLE9Iz0QiTocu/YZoOf+OzFdw=
-github.com/tomarrell/wrapcheck/v2 v2.7.0 h1:J/F8DbSKJC83bAvC6FoZaRjZiZ/iKoueSdrEkmGeacA=
-github.com/tomarrell/wrapcheck/v2 v2.7.0/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg=
+github.com/tomarrell/wrapcheck/v2 v2.8.0 h1:qDzbir0xmoE+aNxGCPrn+rUSxAX+nG6vREgbbXAR81I=
+github.com/tomarrell/wrapcheck/v2 v2.8.0/go.mod h1:ao7l5p0aOlUNJKI0qVwB4Yjlqutd0IvAB9Rdwyilxvg=
 github.com/tommy-muehle/go-mnd/v2 v2.5.1 h1:NowYhSdyE/1zwK9QCLeRb6USWdoif80Ie+v+yU8u1Zw=
 github.com/tommy-muehle/go-mnd/v2 v2.5.1/go.mod h1:WsUAkMJMYww6l/ufffCD3m+P7LEvr8TnZn9lwVDlgzw=
 github.com/ultraware/funlen v0.0.3 h1:5ylVWm8wsNwH5aWo9438pwvsK0QiqVuUrt9bn7S/iLA=
@@ -577,6 +569,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -590,8 +583,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e h1:+WEEuIdZHnUeJJmEUjyYC2gfUMj69yZXw17EnHg/otA=
 golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e/go.mod h1:Kr81I6Kryrl9sr8s2FK3vxD90NdsKWRuOIl2O4CvYbA=
 golang.org/x/exp/typeparams v0.0.0-20220428152302-39d4317da171/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
-golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91 h1:Ic/qN6TEifvObMGQy72k0n1LlJr7DjWWEi+MOsDOiSk=
-golang.org/x/exp/typeparams v0.0.0-20220827204233-334a2380cb91/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
+golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9 h1:6WHiuFL9FNjg8RljAaT7FNUuKDbvMqS1i5cr2OE2sLQ=
+golang.org/x/exp/typeparams v0.0.0-20230203172020-98cc5a0785f9/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -619,8 +612,10 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
+golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
 golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
+golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -658,7 +653,11 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
+golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
+golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
+golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
+golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
+golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
 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=
@@ -700,7 +699,6 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -729,7 +727,6 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -739,10 +736,18 @@ golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 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.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
+golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
+golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/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=
@@ -751,8 +756,10 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
 golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
+golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -766,7 +773,6 @@ golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3
 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190321232350-e250d351ecad/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
 golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
@@ -776,7 +782,6 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
 golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20190916130336-e45ffcd953cc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -805,24 +810,19 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
 golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200624225443-88f3c62a19ff/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
-golang.org/x/tools v0.0.0-20200812195022-5ae4c3c160a0/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200820010801-b793a1359eac/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200831203904-5a2aa26beb65/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
 golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
 golang.org/x/tools v0.0.0-20201001104356-43ebab892c4c/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
-golang.org/x/tools v0.0.0-20201002184944-ecd9fd270d5d/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
 golang.org/x/tools v0.0.0-20201023174141-c8cfbd0f21e6/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.0.0-20201230224404-63754364767c/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
 golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
@@ -830,13 +830,16 @@ golang.org/x/tools v0.1.1-0.20210205202024-ef80cdb6ec6d/go.mod h1:9bzcO0MWcOuT0t
 golang.org/x/tools v0.1.1-0.20210302220138-2ac05c832e1a/go.mod h1:9bzcO0MWcOuT0tm1iBGzDVPshzfwoVvREIui8C+MHqU=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.9-0.20211228192929-ee1ca4ffc4da/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
 golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.3.0 h1:SrNbZl6ECOS1qFzgTdQfWXZM9XBkiA6tkFrH9YSTPHM=
+golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
 golang.org/x/tools v0.3.0/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k=
+golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
+golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k=
+golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
+golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
 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=
@@ -937,7 +940,6 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@@ -962,16 +964,16 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
-honnef.co/go/tools v0.3.3 h1:oDx7VAwstgpYpb3wv0oxiZlxY+foCpRAwY7Vk6XpAgA=
-honnef.co/go/tools v0.3.3/go.mod h1:jzwdWgg7Jdq75wlfblQxO4neNaFFSvgc1tD5Wv8U0Yw=
+honnef.co/go/tools v0.4.2 h1:6qXr+R5w+ktL5UkwEbPp+fEvfyoMPche6GkOpGHZcLc=
+honnef.co/go/tools v0.4.2/go.mod h1:36ZgoUOrqOk1GxwHhyryEkq8FQWkUO2xGuSMhUCcdvA=
 mvdan.cc/gofumpt v0.4.0 h1:JVf4NN1mIpHogBj7ABpgOyZc65/UUOkKQFkoURsz4MM=
 mvdan.cc/gofumpt v0.4.0/go.mod h1:PljLOHDeZqgS8opHRKLzp2It2VBuSdteAgqUfzMTxlQ=
 mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed h1:WX1yoOaKQfddO/mLzdV4wptyWgoH/6hwLs7QHTixo0I=
 mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
 mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b h1:DxJ5nJdkhDlLok9K6qO+5290kphDJbHOQO1DFFFTeBo=
 mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
-mvdan.cc/unparam v0.0.0-20220706161116-678bad134442 h1:seuXWbRB1qPrS3NQnHmFKLJLtskWyueeIzmLXghMGgk=
-mvdan.cc/unparam v0.0.0-20220706161116-678bad134442/go.mod h1:F/Cxw/6mVrNKqrR2YjFf5CaW0Bw4RL8RfbEf4GRggJk=
+mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d h1:3rvTIIM22r9pvXk+q3swxUQAQOxksVMGK7sml4nG57w=
+mvdan.cc/unparam v0.0.0-20221223090309-7455f1af531d/go.mod h1:IeHQjmn6TOD+e4Z3RFiZMMsLVL+A96Nvptar8Fj71is=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=


Test patch:
diff --git a/lightstep/sdk/metric/internal/asyncstate/async_test.go b/lightstep/sdk/metric/internal/asyncstate/async_test.go
index 630cdfc..8aa64f0 100644
--- a/lightstep/sdk/metric/internal/asyncstate/async_test.go
+++ b/lightstep/sdk/metric/internal/asyncstate/async_test.go
@@ -79,8 +79,8 @@ func (tsdk *testSDK) compile(desc sdkinstrument.Descriptor) pipeline.Register[vi
 func testAsync(name string, opts ...view.Option) *testSDK {
 	return &testSDK{
 		compilers: []*viewstate.Compiler{
-			viewstate.New(testLibrary, view.New(name, opts...)),
-			viewstate.New(testLibrary, view.New(name, opts...)),
+			viewstate.New(testLibrary, view.New(name, ignorePerf, opts...)),
+			viewstate.New(testLibrary, view.New(name, ignorePerf, opts...)),
 		},
 	}
 }
@@ -88,8 +88,8 @@ func testAsync(name string, opts ...view.Option) *testSDK {
 func testAsync2(name string, opts1, opts2 []view.Option) *testSDK {
 	return &testSDK{
 		compilers: []*viewstate.Compiler{
-			viewstate.New(testLibrary, view.New(name, opts1...)),
-			viewstate.New(testLibrary, view.New(name, opts2...)),
+			viewstate.New(testLibrary, view.New(name, ignorePerf, opts1...)),
+			viewstate.New(testLibrary, view.New(name, ignorePerf, opts2...)),
 		},
 	}
 }
diff --git a/lightstep/sdk/metric/internal/syncstate/sync_test.go b/lightstep/sdk/metric/internal/syncstate/sync_test.go
index 2c44d18..a67f5b8 100644
--- a/lightstep/sdk/metric/internal/syncstate/sync_test.go
+++ b/lightstep/sdk/metric/internal/syncstate/sync_test.go
@@ -144,7 +144,7 @@ func testSyncStateConcurrencyWithPerf[N number.Any, Traits number.Traits[N]](t *
 	}
 	vcs := make([]*viewstate.Compiler, numReaders)
 	for vci := range vcs {
-		vcs[vci] = viewstate.New(lib, view.New("test", vopts...))
+		vcs[vci] = viewstate.New(lib, view.New("test", safePerf, vopts...))
 	}
 	attrs := make([]attribute.KeyValue, numAttrs)
 	for i := range attrs {
@@ -245,8 +245,8 @@ func TestSyncStatePartialNoopInstrument(t *testing.T) {
 		Name: "testlib",
 	}
 	vcs := make([]*viewstate.Compiler, 2)
-	vcs[0] = viewstate.New(lib, view.New("dropper", vopts...))
-	vcs[1] = viewstate.New(lib, view.New("keeper"))
+	vcs[0] = viewstate.New(lib, view.New("dropper", safePerf, vopts...))
+	vcs[1] = viewstate.New(lib, view.New("keeper", safePerf))
 
 	desc := test.Descriptor("dropme", sdkinstrument.SyncHistogram, number.Float64Kind)
 
@@ -313,8 +313,8 @@ func TestSyncStateFullNoopInstrument(t *testing.T) {
 		Name: "testlib",
 	}
 	vcs := make([]*viewstate.Compiler, 2)
-	vcs[0] = viewstate.New(lib, view.New("dropper", vopts...))
-	vcs[1] = viewstate.New(lib, view.New("keeper", vopts...))
+	vcs[0] = viewstate.New(lib, view.New("dropper", safePerf, vopts...))
+	vcs[1] = viewstate.New(lib, view.New("keeper", safePerf, vopts...))
 
 	desc := test.Descriptor("dropme", sdkinstrument.SyncHistogram, number.Float64Kind)
 
@@ -353,7 +353,7 @@ func TestOutOfRangeValues(t *testing.T) {
 			Name: "testlib",
 		}
 		vcs := make([]*viewstate.Compiler, 1)
-		vcs[0] = viewstate.New(lib, view.New("test"))
+		vcs[0] = viewstate.New(lib, view.New("test", safePerf))
 
 		pipes := make(pipeline.Register[viewstate.Instrument], 1)
 		pipes[0], _ = vcs[0].Compile(desc)
@@ -432,6 +432,7 @@ func TestSyncGaugeDeltaInstrument(t *testing.T) {
 	vcs := make([]*viewstate.Compiler, 2)
 	vcs[0] = viewstate.New(lib, view.New(
 		"test",
+		safePerf,
 		deltaSelector,
 		view.WithClause(
 			view.WithKeys([]attribute.Key{"A", "C"}),
@@ -731,6 +732,7 @@ func TestDuplicateFingerprintSafety(t *testing.T) {
 	vcs := make([]*viewstate.Compiler, 2)
 	vcs[0] = viewstate.New(lib, view.New(
 		"test",
+		safePerf,
 		deltaSelector,
 		view.WithClause(
 			view.WithKeys([]attribute.Key{fpKey}),
@@ -738,6 +740,7 @@ func TestDuplicateFingerprintSafety(t *testing.T) {
 	))
 	vcs[1] = viewstate.New(lib, view.New(
 		"test",
+		safePerf,
 		deltaSelector,
 		view.WithClause(
 			view.WithKeys([]attribute.Key{}),
@@ -928,6 +931,7 @@ func TestDuplicateFingerprintCollisionIgnored(t *testing.T) {
 	vcs := make([]*viewstate.Compiler, 1)
 	vcs[0] = viewstate.New(lib, view.New(
 		"test",
+		safePerf,
 		deltaSelector,
 	))
 
@@ -1025,6 +1029,7 @@ func TestRecordInactivity(t *testing.T) {
 			vcs := make([]*viewstate.Compiler, 1)
 			vcs[0] = viewstate.New(lib, view.New(
 				"test",
+				safePerf,
 				deltaSelector,
 			))
 
@@ -1122,3 +1127,244 @@ func TestRecordInactivity(t *testing.T) {
 		})
 	}
 }
+
+func TestCardinalityOverflowCumulative(t *testing.T) {
+	const total = 300
+	const limit = 133
+
+	ctx := context.Background()
+	lib := instrumentation.Library{
+		Name: "testlib",
+	}
+	perf := sdkinstrument.Performance{
+		InstrumentCardinalityLimit: limit,
+	}
+	vcs := make([]*viewstate.Compiler, 1)
+	vcs[0] = viewstate.New(lib, view.New("test", perf))
+
+	desc := test.Descriptor("c", sdkinstrument.SyncCounter, number.Float64Kind)
+
+	pipes := make(pipeline.Register[viewstate.Instrument], 1)
+	pipes[0], _ = vcs[0].Compile(desc)
+
+	inst := New(desc, perf, nil, pipes)
+	require.NotNil(t, inst)
+
+	var expectPoints []data.Point
+	var oflow int
+
+	for i := 0; i < total; i++ {
+		inst.ObserveFloat64(ctx, 1, attribute.Int("i", i))
+
+		if i < int(perf.InstrumentCardinalityLimit)-1 {
+			expectPoints = append(expectPoints, test.Point(
+				startTime, endTime,
+				sum.NewMonotonicFloat64(1),
+				aggregation.CumulativeTemporality,
+				attribute.Int("i", i),
+			))
+		} else {
+			oflow++
+		}
+	}
+	require.Equal(t, total-limit+1, oflow)
+	expectPoints = append(expectPoints, test.Point(
+		startTime, endTime,
+		sum.NewMonotonicFloat64(float64(oflow)),
+		aggregation.CumulativeTemporality,
+		attribute.Bool("otel.metric.overflow", true),
+	))
+
+	inst.SnapshotAndProcess()
+
+	test.RequireEqualMetrics(
+		t,
+		test.CollectScope(
+			t,
+			vcs[0].Collectors(),
+			testSequence,
+		),
+		test.Instrument(
+			desc,
+			expectPoints...,
+		),
+	)
+
+	// Repeat with all new attributes; since this is cumulative,
+	// the original set is retained an this goes entirely to overflow.
+	for i := 0; i < total; i++ {
+		inst.ObserveFloat64(ctx, 1, attribute.Int("i", total+i))
+		oflow++
+	}
+	// Replace the overflow value
+	expectPoints = expectPoints[:len(expectPoints)-1]
+	expectPoints = append(expectPoints, test.Point(
+		startTime, endTime,
+		sum.NewMonotonicFloat64(float64(oflow)),
+		aggregation.CumulativeTemporality,
+		attribute.Bool("otel.metric.overflow", true),
+	))
+
+	inst.SnapshotAndProcess()
+
+	test.RequireEqualMetrics(
+		t,
+		test.CollectScope(
+			t,
+			vcs[0].Collectors(),
+			testSequence,
+		),
+		test.Instrument(
+			desc,
+			expectPoints...,
+		),
+	)
+}
+
+func TestCardinalityOverflowAvoidedDelta(t *testing.T) {
+	const limit = 100 // has to be even
+
+	ctx := context.Background()
+	lib := instrumentation.Library{
+		Name: "testlib",
+	}
+	perf := sdkinstrument.Performance{
+		InstrumentCardinalityLimit: limit,
+		InactiveCollectionPeriods:  1,
+	}
+	vcs := make([]*viewstate.Compiler, 1)
+	vcs[0] = viewstate.New(lib, view.New("test", perf, deltaSelector))
+
+	desc := test.Descriptor("c", sdkinstrument.SyncUpDownCounter, number.Int64Kind)
+
+	pipes := make(pipeline.Register[viewstate.Instrument], 1)
+	pipes[0], _ = vcs[0].Compile(desc)
+
+	inst := New(desc, perf, nil, pipes)
+	require.NotNil(t, inst)
+
+	uniq := 0
+	for reps := 0; reps < 4; reps++ {
+
+		var expectPoints []data.Point
+
+		// we expect to create half the limit less on every
+		// iteration and never overflow.
+		for i := 0; i < limit/2-1; i++ {
+			// attr is unique on every iteration
+			attr := attribute.String("s", fmt.Sprint(uniq))
+			uniq++
+			inst.ObserveInt64(ctx, 1, attr)
+
+			expectPoints = append(expectPoints, test.Point(
+				middleTime, endTime,
+				sum.NewNonMonotonicInt64(1),
+				aggregation.DeltaTemporality,
+				attr,
+			))
+		}
+
+		inst.SnapshotAndProcess()
+
+		test.RequireEqualMetrics(
+			t,
+			test.CollectScope(
+				t,
+				vcs[0].Collectors(),
+				testSequence,
+			),
+			test.Instrument(
+				desc,
+				expectPoints...,
+			),
+		)
+	}
+}
+
+func TestCardinalityOverflowOscillationDelta(t *testing.T) {
+	// Note this tests a fairly bad behavior; it can be improved
+	// upon, but at least this validates the current mechanism.
+	// If more than half of the available aggregators are not
+	// re-used an oscillation develops.
+	//
+	// TODO improve this logic and replace this test.
+	const total = 8
+	const limit = 4
+
+	ctx := context.Background()
+	lib := instrumentation.Library{
+		Name: "testlib",
+	}
+	perf := sdkinstrument.Performance{
+		InstrumentCardinalityLimit: limit,
+		InactiveCollectionPeriods:  1,
+	}
+	vcs := make([]*viewstate.Compiler, 1)
+	vcs[0] = viewstate.New(lib, view.New("test", perf, deltaSelector))
+
+	desc := test.Descriptor("c", sdkinstrument.SyncCounter, number.Float64Kind)
+
+	pipes := make(pipeline.Register[viewstate.Instrument], 1)
+	pipes[0], _ = vcs[0].Compile(desc)
+
+	inst := New(desc, perf, nil, pipes)
+	require.NotNil(t, inst)
+
+	uniq := 0
+
+	for reps := 0; reps < 10; reps++ {
+		var expectPoints []data.Point
+		var oflow int
+
+		for i := 0; i < total; i++ {
+			inst.ObserveFloat64(ctx, 1, attribute.Int("uniq", uniq))
+
+			// Note: on even intervals, the overflow will
+			// be as we expect, and in odd intervals, the
+			// entire batch will overflow.
+			if reps%2 == 0 {
+				normal := int(perf.InstrumentCardinalityLimit) - 1
+				if reps > 0 {
+					// Except the first round there's one
+					// overflow element already used so one
+					// less normal "new" attribute set.
+					normal--
+				}
+				if i < normal {
+					expectPoints = append(expectPoints, test.Point(
+						middleTime, endTime,
+						sum.NewMonotonicFloat64(1),
+						aggregation.DeltaTemporality,
+						attribute.Int("uniq", uniq),
+					))
+				} else {
+					oflow++
+				}
+			} else {
+				oflow++
+			}
+			uniq++
+		}
+		expectPoints = append(expectPoints, test.Point(
+			middleTime, endTime,
+			sum.NewMonotonicFloat64(float64(oflow)),
+			aggregation.DeltaTemporality,
+			attribute.Bool("otel.metric.overflow", true),
+		))
+
+		inst.SnapshotAndProcess()
+
+		test.RequireEqualMetrics(
+			t,
+			test.CollectScope(
+				t,
+				vcs[0].Collectors(),
+				testSequence,
+			),
+			test.Instrument(
+				desc,
+				expectPoints...,
+			),
+		)
+	}
+}
diff --git a/lightstep/sdk/metric/internal/test/test.go b/lightstep/sdk/metric/internal/test/test.go
index 346dc03..375c13c 100644
--- a/lightstep/sdk/metric/internal/test/test.go
+++ b/lightstep/sdk/metric/internal/test/test.go
@@ -101,7 +101,7 @@ func CollectScopeReuse(t *testing.T, collectors []data.Collector, seq data.Seque
 func RequireEqualPoints(t *testing.T, output []data.Point, expected ...data.Point) {
 	t.Helper()
 
-	require.Equal(t, len(output), len(expected), "points have different length")
+	require.Equal(t, len(expected), len(output), "points have different length")
 
 	cpy := make([]data.Point, len(expected))
 	copy(cpy, expected)
diff --git a/lightstep/sdk/metric/internal/viewstate/errors_test.go b/lightstep/sdk/metric/internal/viewstate/errors_test.go
index 23d6377..eedd926 100644
--- a/lightstep/sdk/metric/internal/viewstate/errors_test.go
+++ b/lightstep/sdk/metric/internal/viewstate/errors_test.go
@@ -28,6 +28,8 @@ import (
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/view"
 )
 
+var safePerf sdkinstrument.Performance
+
 var oneConflict = Conflict{
 	Semantic: SemanticError{
 		Instrument:  sdkinstrument.SyncCounter,
@@ -113,6 +115,7 @@ func TestConflictCombine(t *testing.T) {
 func TestConflictError(t *testing.T) {
 	views := view.New(
 		"problem",
+		safePerf,
 		view.WithDefaultAggregationKindSelector(func(k sdkinstrument.Kind) aggregation.Kind {
 			return aggregation.GaugeKind
 		}),
diff --git a/lightstep/sdk/metric/internal/viewstate/viewstate_test.go b/lightstep/sdk/metric/internal/viewstate/viewstate_test.go
index 50ae135..6f6594e 100644
--- a/lightstep/sdk/metric/internal/viewstate/viewstate_test.go
+++ b/lightstep/sdk/metric/internal/viewstate/viewstate_test.go
@@ -31,6 +31,7 @@ import (
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/aggregator/minmaxsumcount"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/aggregator/sum"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/data"
+	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/internal/pipeline"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/internal/test"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/number"
 	"github.com/lightstep/otel-launcher-go/lightstep/sdk/metric/sdkinstrument"
@@ -144,7 +145,7 @@ func testCollectSequenceReuse(t *testing.T, vc *Compiler, seq data.Sequence, out
 // TestDeduplicateNoConflict verifies that two identical instruments
 // have the same collector.
 func TestDeduplicateNoConflict(t *testing.T) {
-	vc := New(testLib, view.New("test"))
+	vc := New(testLib, view.New("test", safePerf))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncCounter, number.Int64Kind)
 	require.NoError(t, err1)
@@ -160,7 +161,7 @@ func TestDeduplicateNoConflict(t *testing.T) {
 // TestDeduplicateRenameNoConflict verifies that one instrument can be renamed
 // such that it becomes identical to another, so no conflict.
 func TestDeduplicateRenameNoConflict(t *testing.T) {
-	vc := New(testLib, view.New("test", fooToBarView))
+	vc := New(testLib, view.New("test", safePerf, fooToBarView))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncCounter, number.Int64Kind)
 	require.NoError(t, err1)
@@ -176,7 +177,7 @@ func TestDeduplicateRenameNoConflict(t *testing.T) {
 // TestNoRenameNoConflict verifies that one instrument does not
 // conflict with another differently-named instrument.
 func TestNoRenameNoConflict(t *testing.T) {
-	vc := New(testLib, view.New("test"))
+	vc := New(testLib, view.New("test", safePerf))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncCounter, number.Int64Kind)
 	require.NoError(t, err1)
@@ -192,7 +193,7 @@ func TestNoRenameNoConflict(t *testing.T) {
 // TestDuplicateNumberConflict verifies that two same instruments
 // except different number kind conflict.
 func TestDuplicateNumberConflict(t *testing.T) {
-	vc := New(testLib, view.New("test"))
+	vc := New(testLib, view.New("test", safePerf))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncCounter, number.Int64Kind)
 	require.NoError(t, err1)
@@ -212,7 +213,7 @@ func TestDuplicateNumberConflict(t *testing.T) {
 // TestDuplicateSyncAsyncConflict verifies that two same instruments
 // except one synchonous, one asynchronous conflict.
 func TestDuplicateSyncAsyncConflict(t *testing.T) {
-	vc := New(testLib, view.New("test"))
+	vc := New(testLib, view.New("test", safePerf))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncCounter, number.Float64Kind)
 	require.NoError(t, err1)
@@ -229,7 +230,7 @@ func TestDuplicateSyncAsyncConflict(t *testing.T) {
 // TestDuplicateUnitConflict verifies that two same instruments
 // except different units conflict.
 func TestDuplicateUnitConflict(t *testing.T) {
-	vc := New(testLib, view.New("test"))
+	vc := New(testLib, view.New("test", safePerf))
 
 	inst1, err1 := testCompileDescUnit(vc, "foo", sdkinstrument.SyncCounter, number.Float64Kind, "", "gal_us")
 	require.NoError(t, err1)
@@ -247,7 +248,7 @@ func TestDuplicateUnitConflict(t *testing.T) {
 // TestDuplicateMonotonicConflict verifies that two same instruments
 // except different monotonic values.
 func TestDuplicateMonotonicConflict(t *testing.T) {
-	vc := New(testLib, view.New("test"))
+	vc := New(testLib, view.New("test", safePerf))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncCounter, number.Float64Kind)
 	require.NoError(t, err1)
@@ -265,7 +266,7 @@ func TestDuplicateMonotonicConflict(t *testing.T) {
 // TestDuplicateAggregatorConfigConflict verifies that two same instruments
 // except different aggregator.Config values.
 func TestDuplicateAggregatorConfigConflict(t *testing.T) {
-	vc := New(testLib, view.New("test", fooToBarAltHistView))
+	vc := New(testLib, view.New("test", safePerf, fooToBarAltHistView))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncHistogram, number.Float64Kind)
 	require.NoError(t, err1)
@@ -287,6 +288,7 @@ func TestDuplicateAggregatorConfigNoConflict(t *testing.T) {
 		t.Run(nk.String(), func(t *testing.T) {
 			views := view.New(
 				"test",
+				safePerf,
 				view.WithDefaultAggregationConfigSelector(
 					func(_ sdkinstrument.Kind) (int64Config, float64Config aggregator.Config) {
 						if nk == number.Int64Kind {
@@ -316,7 +318,7 @@ func TestDuplicateAggregatorConfigNoConflict(t *testing.T) {
 // TestDuplicateAggregationKindConflict verifies that two instruments
 // with different aggregation kinds conflict.
 func TestDuplicateAggregationKindConflict(t *testing.T) {
-	vc := New(testLib, view.New("test", fooToBarView))
+	vc := New(testLib, view.New("test", safePerf, fooToBarView))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncHistogram, number.Int64Kind)
 	require.NoError(t, err1)
@@ -335,7 +337,7 @@ func TestDuplicateAggregationKindConflict(t *testing.T) {
 // instruments with different aggregation kinds do not conflict when
 // the view drops one of the instruments.
 func TestDuplicateAggregationKindNoConflict(t *testing.T) {
-	vc := New(testLib, view.New("test", dropHistInstView))
+	vc := New(testLib, view.New("test", safePerf, dropHistInstView))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncHistogram, number.Int64Kind)
 	require.NoError(t, err1)
@@ -349,7 +351,7 @@ func TestDuplicateAggregationKindNoConflict(t *testing.T) {
 // TestDuplicateMultipleConflicts verifies that multiple duplicate
 // instrument conflicts include sufficient explanatory information.
 func TestDuplicateMultipleConflicts(t *testing.T) {
-	vc := New(testLib, view.New("test"))
+	vc := New(testLib, view.New("test", safePerf))
 
 	inst1, err1 := testCompile(vc, "foo", instrumentKinds[0], number.Float64Kind)
 	require.NoError(t, err1)
@@ -380,7 +382,7 @@ func TestDuplicateFilterConflicts(t *testing.T) {
 		fooToBarDifferentFiltersViews,
 	} {
 		t.Run(fmt.Sprint(idx), func(t *testing.T) {
-			vc := New(testLib, view.New("test", vws...))
+			vc := New(testLib, view.New("test", safePerf, vws...))
 
 			inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncCounter, number.Int64Kind)
 			require.NoError(t, err1)
@@ -400,7 +402,7 @@ func TestDuplicateFilterConflicts(t *testing.T) {
 // renamed to match another exactly, including filters, they are not
 // in conflict.
 func TestDeduplicateSameFilters(t *testing.T) {
-	vc := New(testLib, view.New("test", fooToBarSameFiltersViews...))
+	vc := New(testLib, view.New("test", safePerf, fooToBarSameFiltersViews...))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncCounter, number.Int64Kind)
 	require.NoError(t, err1)
@@ -415,7 +417,7 @@ func TestDeduplicateSameFilters(t *testing.T) {
 
 // TestDuplicatesMergeDescriptor ensures that the longest description string is used.
 func TestDuplicatesMergeDescriptor(t *testing.T) {
-	vc := New(testLib, view.New("test", fooToBarSameFiltersViews...))
+	vc := New(testLib, view.New("test", safePerf, fooToBarSameFiltersViews...))
 
 	inst1, err1 := testCompile(vc, "foo", sdkinstrument.SyncCounter, number.Int64Kind)
 	require.NoError(t, err1)
@@ -451,6 +453,7 @@ func TestDuplicatesMergeDescriptor(t *testing.T) {
 func TestViewDescription(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(
 			view.MatchInstrumentName("foo"),
 			view.WithDescription("something helpful"),
@@ -492,7 +495,7 @@ func TestViewDescription(t *testing.T) {
 // TestKeyFilters verifies that keys are filtred and metrics are
 // correctly aggregated.
 func TestKeyFilters(t *testing.T) {
-	views := view.New("test",
+	views := view.New("test", safePerf,
 		view.WithClause(view.WithKeys([]attribute.Key{"a", "b"})),
 	)
 
@@ -532,6 +535,7 @@ func TestKeyFilters(t *testing.T) {
 func TestTwoViewsOneInt64Instrument(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(
 			view.MatchInstrumentName("foo"),
 			view.WithName("foo_a"),
@@ -600,6 +604,7 @@ func TestTwoViewsOneInt64Instrument(t *testing.T) {
 func TestHistogramTwoAggregations(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(
 			view.MatchInstrumentName("foo"),
 			view.WithName("foo_sum"),
@@ -648,6 +653,7 @@ func TestHistogramTwoAggregations(t *testing.T) {
 func TestAllKeysFilter(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(view.WithKeys([]attribute.Key{})),
 	)
 
@@ -682,6 +688,7 @@ func TestAllKeysFilter(t *testing.T) {
 func TestAnySumAggregation(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(view.WithAggregation(aggregation.AnySumKind)),
 	)
 
@@ -746,7 +753,7 @@ func TestAnySumAggregation(t *testing.T) {
 // instrument accumulators keep only the last observed value, while
 // synchronous instruments correctly snapshotAndProcess them all.
 func TestDuplicateAsyncMeasurementsIngored(t *testing.T) {
-	vc := New(testLib, view.New("test"))
+	vc := New(testLib, view.New("test", safePerf))
 
 	inst1, err := testCompile(vc, "async", sdkinstrument.AsyncCounter, number.Float64Kind)
 	require.NoError(t, err)
@@ -788,6 +795,7 @@ func TestDuplicateAsyncMeasurementsIngored(t *testing.T) {
 func TestCumulativeTemporality(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(
 			// Dropping all keys
 			view.WithKeys([]attribute.Key{}),
@@ -841,6 +849,7 @@ func TestCumulativeTemporality(t *testing.T) {
 func TestDeltaTemporalityCounter(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(
 			// Dropping all keys
 			view.WithKeys([]attribute.Key{}),
@@ -902,6 +911,7 @@ func TestDeltaTemporalityCounter(t *testing.T) {
 func TestDeltaTemporalityAsyncCounter(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithDefaultAggregationTemporalitySelector(view.DeltaPreferredTemporality),
 	)
 
@@ -1008,6 +1018,7 @@ func TestDeltaTemporalityAsyncCounter(t *testing.T) {
 func TestDeltaTemporalityAsyncGauge(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithDefaultAggregationTemporalitySelector(view.DeltaPreferredTemporality),
 	)
 
@@ -1095,6 +1106,7 @@ func TestDeltaTemporalityAsyncGauge(t *testing.T) {
 func TestDeltaTemporalitySyncGauge(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithDefaultAggregationTemporalitySelector(
 			func(ik sdkinstrument.Kind) aggregation.Temporality {
 				return aggregation.DeltaTemporality
@@ -1255,6 +1267,7 @@ func TestDeltaTemporalitySyncGauge(t *testing.T) {
 func TestSyncDeltaTemporalityCounter(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithDefaultAggregationTemporalitySelector(
 			func(ik sdkinstrument.Kind) aggregation.Temporality {
 				return aggregation.DeltaTemporality // Always delta
@@ -1359,6 +1372,7 @@ func TestSyncDeltaTemporalityCounter(t *testing.T) {
 func TestSyncDeltaTemporalityMapDeletion(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithDefaultAggregationTemporalitySelector(
 			func(ik sdkinstrument.Kind) aggregation.Temporality {
 				return aggregation.DeltaTemporality // Always delta
@@ -1407,12 +1421,12 @@ func TestSyncDeltaTemporalityMapDeletion(t *testing.T) {
 	)
 
 	require.Equal(t, 0, len(inst.(*statelessSyncInstrument[float64, sum.MonotonicFloat64, sum.MonotonicFloat64Methods]).data))
-
 }
 
 func TestRegexpMatch(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(
 			view.MatchInstrumentNameRegexp(regexp.MustCompile(".*_rate")),
 			view.WithAggregation(aggregation.DropKind),
@@ -1436,6 +1450,7 @@ func TestRegexpMatch(t *testing.T) {
 func TestSingleInstrumentWarning(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(
 			view.MatchInstrumentNameRegexp(regexp.MustCompile(".*_rate")),
 			view.WithName("fixed"),
@@ -1450,6 +1465,7 @@ func TestSingleInstrumentWarning(t *testing.T) {
 func TestDeltaTemporalityMinMaxSumCount(t *testing.T) {
 	views := view.New(
 		"test",
+		safePerf,
 		view.WithClause(
 			view.MatchInstrumentKind(sdkinstrument.SyncHistogram),
 			view.WithAggregation(aggregation.MinMaxSumCountKind),
@@ -1505,7 +1521,7 @@ func TestDeltaTemporalityMinMaxSumCount(t *testing.T) {
 }
 
 func TestViewHints(t *testing.T) {
-	views := view.New("test")
+	views := view.New("test", safePerf)
 	vc := New(testLib, views)
 	otelErrs := test.OTelErrors()
 
@@ -1589,7 +1605,7 @@ func TestViewHints(t *testing.T) {
 }
 
 func TestViewHintErrors(t *testing.T) {
-	views := view.New("test")
+	views := view.New("test", safePerf)
 	vc := New(testLib, views)
 	otelErrs := test.OTelErrors()
 
@@ -1645,11 +1661,11 @@ func TestViewHintErrors(t *testing.T) {
 	require.Contains(t, (*otelErrs)[0].Error(), "invalid character")
 	require.Contains(t, (*otelErrs)[1].Error(), "looking for beginning")
 	require.Contains(t, (*otelErrs)[2].Error(), "invalid aggregation")
-	require.Contains(t, (*otelErrs)[3].Error(), "invalid aggregator config")
+	require.Contains(t, (*otelErrs)[3].Error(), "invalid histogram size: -3")
 }
 
 func TestViewHintNoOverrideEmpty(t *testing.T) {
-	views := view.New("test",
+	views := view.New("test", safePerf,
 		view.WithDefaultAggregationConfigSelector(
 			func(_ sdkinstrument.Kind) (int64Config, float64Config aggregator.Config) {
 				cfg := aggregator.Config{
@@ -1703,7 +1719,7 @@ func TestViewHintNoOverrideEmpty(t *testing.T) {
 
 // TestEmptyKeyFilter ensures no empty keys are used (w/o view config).
 func TestEmptyKeyFilter(t *testing.T) {
-	views := view.New("test")
+	views := view.New("test", safePerf)
 
 	vc := New(testLib, views)
 
@@ -1743,7 +1759,7 @@ func TestEmptyKeyFilter(t *testing.T) {
 
 // TestEmptyKeyFilterAndView ensures no empty keys are used (with a view config).
 func TestEmptyKeyFilterAndView(t *testing.T) {
-	views := view.New("test",
+	views := view.New("test", safePerf,
 		view.WithClause(
 			view.WithKeys([]attribute.Key{"a"}),
 		),
@@ -1773,3 +1789,369 @@ func TestEmptyKeyFilterAndView(t *testing.T) {
 		),
 	)
 }
+
+// TestOverflowSyncCumulative tests that all synchronous cumulative
+// respect thier configured cardinality limit and that the limit can
+// be set three ways.
+func TestOverflowSyncCumulative(t *testing.T) {
+	const limitA = 10
+	const limitB = 20
+	const limitC = 30
+	views := view.New(
+		"test",
+		sdkinstrument.Performance{
+			AggregatorCardinalityLimit: limitC,
+		},
+		view.WithClause(
+			view.MatchInstrumentName("B"),
+			view.WithAggregatorConfig(aggregator.Config{
+				CardinalityLimit: limitB,
+			}),
+		),
+	)
+	views, err := view.Validate(views)
+	require.NoError(t, err)
+
+	vc := New(testLib, views)
+
+	descA := fmt.Sprintf(`{
+  "config": {
+    "cardinality_limit": %d
+  }
+}`, limitA)
+
+	instA, err := testCompileDescUnit(vc, "A", sdkinstrument.SyncCounter, number.Float64Kind, descA, "")
+	require.NoError(t, err)
+
+	instB, err := testCompile(vc, "B", sdkinstrument.SyncUpDownCounter, number.Float64Kind)
+	require.NoError(t, err)
+
+	instC, err := testCompile(vc, "C", sdkinstrument.SyncHistogram, number.Float64Kind)
+	require.NoError(t, err)
+
+	var expA []data.Point
+	var expB []data.Point
+	var expC []data.Point
+	var oflowA, oflowB, oflowC float64
+
+	for i := 0; i < 1000; i++ {
+		acc1 := instA.NewAccumulator(attribute.NewSet(attribute.Int("a", i)))
+		acc1.(Updater[float64]).Update(1)
+		acc1.SnapshotAndProcess(true)
+
+		if i < limitA-1 {
+			expA = append(expA,
+				test.Point(
+					startTime, endTime, sum.NewMonotonicFloat64(1), cumulative, attribute.Int("a", i),
+				))
+		} else {
+			oflowA++
+		}
+
+		acc2 := instB.NewAccumulator(attribute.NewSet(attribute.Int("b", i)))
+		acc2.(Updater[float64]).Update(1)
+		acc2.SnapshotAndProcess(true)
+
+		if i < limitB-1 {
+			expB = append(expB,
+				test.Point(
+					startTime, endTime, sum.NewNonMonotonicFloat64(1), cumulative, attribute.Int("b", i),
+				))
+		} else {
+			oflowB++
+		}
+
+		acc3 := instC.NewAccumulator(attribute.NewSet(attribute.Int("c", i)))
+		acc3.(Updater[float64]).Update(1)
+		acc3.SnapshotAndProcess(true)
+
+		if i < limitC-1 {
+			expC = append(expC,
+				test.Point(
+					startTime, endTime, histogram.NewFloat64(histogram.Config{}, 1), cumulative, attribute.Int("c", i),
+				))
+		} else {
+			oflowC++
+		}
+	}
+
+	expA = append(expA,
+		test.Point(
+			startTime, endTime, sum.NewMonotonicFloat64(oflowA), cumulative, attribute.Bool("otel.metric.overflow", true),
+		))
+	expB = append(expB,
+		test.Point(
+			startTime, endTime, sum.NewNonMonotonicFloat64(oflowB), cumulative, attribute.Bool("otel.metric.overflow", true),
+		))
+
+	var many []float64
+	for i := 0.0; i < oflowC; i++ {
+		many = append(many, 1.0)
+	}
+
+	expC = append(expC,
+		test.Point(
+			startTime, endTime, histogram.NewFloat64(histogram.Config{}, many...), cumulative, attribute.Bool("otel.metric.overflow", true),
+		))
+
+	test.RequireEqualMetrics(
+		t,
+		testCollect(t, vc),
+		test.Instrument(
+			test.Descriptor("A", sdkinstrument.SyncCounter, number.Float64Kind),
+			expA...,
+		),
+		test.Instrument(
+			test.Descriptor("B", sdkinstrument.SyncUpDownCounter, number.Float64Kind),
+			expB...,
+		),
+		test.Instrument(
+			test.Descriptor("C", sdkinstrument.SyncHistogram, number.Float64Kind),
+			expC...,
+		),
+	)
+}
+
+// TestOverflowAsync is a cursory test of the cumulative async
+// behavior. This is a weak test because the asyncstate package
+// uses map iteration, making the results unpredictable.
+//
+// TODO: Fix the asyncstate behavior in a separate change, then
+// strengthen this test.
+func TestOverflowAsyncCumulative(t *testing.T) {
+	const limitA = 10
+	const limitB = 20
+	const limitC = 30
+	const count = 1000
+	views := view.New(
+		"test",
+		sdkinstrument.Performance{
+			AggregatorCardinalityLimit: limitC,
+		},
+		view.WithClause(
+			view.MatchInstrumentName("B"),
+			view.WithAggregatorConfig(aggregator.Config{
+				CardinalityLimit: limitB,
+			}),
+		),
+	)
+	views, err := view.Validate(views)
+	require.NoError(t, err)
+
+	vc := New(testLib, views)
+
+	descA := fmt.Sprintf(`{
+  "config": {
+    "cardinality_limit": %d
+  }
+}`, limitA)
+
+	instA, err := testCompileDescUnit(vc, "A", sdkinstrument.AsyncCounter, number.Int64Kind, descA, "")
+	require.NoError(t, err)
+
+	instB, err := testCompile(vc, "B", sdkinstrument.AsyncUpDownCounter, number.Int64Kind)
+	require.NoError(t, err)
+
+	instC, err := testCompile(vc, "C", sdkinstrument.AsyncGauge, number.Int64Kind)
+	require.NoError(t, err)
+
+	for reps := 0; reps < 10; reps++ {
+		for i := 0; i < count; i++ {
+			acc1 := instA.NewAccumulator(attribute.NewSet(attribute.Int("a", i)))
+			acc1.(Updater[int64]).Update(1)
+			acc1.SnapshotAndProcess(true)
+
+			acc2 := instB.NewAccumulator(attribute.NewSet(attribute.Int("b", i)))
+			acc2.(Updater[int64]).Update(1)
+			acc2.SnapshotAndProcess(true)
+
+			acc3 := instC.NewAccumulator(attribute.NewSet(attribute.Int("c", i)))
+			acc3.(Updater[int64]).Update(1)
+			acc3.SnapshotAndProcess(true)
+		}
+
+		collected := testCollect(t, vc)
+
+		require.Equal(t, limitA, len(collected[0].Points))
+		require.Equal(t, limitB, len(collected[1].Points))
+		require.Equal(t, limitC, len(collected[2].Points))
+
+		// Each point list has one overflow.
+		for idx, data := range collected {
+			oflow := 0
+			sum := int64(0)
+			for _, pt := range data.Points {
+				if pt.Attributes == pipeline.OverflowAttributeSet {
+					oflow++
+				}
+				if idx < 2 {
+					sum += number.ToInt64(pt.Aggregation.(aggregation.Sum).Sum())
+				} else {
+					sum += number.ToInt64(pt.Aggregation.(aggregation.Gauge).Gauge())
+				}
+			}
+			require.Equal(t, 1, oflow)
+			if idx < 2 {
+				require.Equal(t, int64(count), sum)
+			} else {
+				require.Equal(t, int64(limitC), sum)
+			}
+		}
+	}
+}
+
+// TestOneViewOverflowsOneDoesNot tests that views can independently
+// repair an overflow problem.
+func TestOneViewOverflowsOneDoesNot(t *testing.T) {
+	const limit = 10
+	const count = 20
+	views := view.New(
+		"test",
+		sdkinstrument.Performance{
+			AggregatorCardinalityLimit: limit,
+		},
+		view.WithClause(
+			view.WithName("filtered"),
+			view.MatchInstrumentName("input"),
+			view.WithKeys([]attribute.Key{"stable"}),
+		),
+		view.WithClause(
+			view.WithName("unfiltered"),
+			view.MatchInstrumentName("input"),
+		),
+	)
+	views, err := view.Validate(views)
+	require.NoError(t, err)
+
+	vc := New(testLib, views)
+
+	inst, err := testCompile(vc, "input", sdkinstrument.SyncCounter, number.Float64Kind)
+	require.NoError(t, err)
+
+	sattr := attribute.String("stable", "constant")
+	var expNF []data.Point
+
+	for i := 0; i < count; i++ {
+		vattr := attribute.Int("varies", i)
+		acc := inst.NewAccumulator(attribute.NewSet(
+			sattr,
+			vattr,
+		))
+		acc.(Updater[float64]).Update(1)
+		acc.SnapshotAndProcess(true)
+
+		if i < limit-1 {
+			expNF = append(expNF,
+				test.Point(
+					startTime, endTime, sum.NewMonotonicFloat64(1), cumulative, sattr, vattr,
+				))
+		}
+	}
+	expNF = append(expNF,
+		test.Point(
+			startTime, endTime, sum.NewMonotonicFloat64(count-limit+1), cumulative, attribute.Bool("otel.metric.overflow", true),
+		))
+
+	test.RequireEqualMetrics(
+		t,
+		testCollect(t, vc),
+		test.Instrument(
+			test.Descriptor("filtered", sdkinstrument.SyncCounter, number.Float64Kind),
+			test.Point(
+				startTime, endTime, sum.NewMonotonicFloat64(count), cumulative, sattr,
+			),
+		),
+		test.Instrument(
+			test.Descriptor("unfiltered", sdkinstrument.SyncCounter, number.Float64Kind),
+			expNF...,
+		),
+	)
+}
+
+// TestInstrumentOverflowCombined tests that the aggregator limit is a
+// hard limit even when the instrument-level limit was reached early.
+func TestInstrumentOverflowCombined(t *testing.T) {
+	const aggLimit = 10
+	const instLimit = 2 * aggLimit
+	const count = 5 * instLimit
+	views := view.New(
+		"test",
+		sdkinstrument.Performance{
+			InactiveCollectionPeriods:  1,
+			AggregatorCardinalityLimit: aggLimit,
+			InstrumentCardinalityLimit: instLimit,
+		},
+		view.WithDefaultAggregationTemporalitySelector(view.DeltaPreferredTemporality),
+	)
+	views, err := view.Validate(views)
+	require.NoError(t, err)
+
+	vc := New(testLib, views)
+
+	instS, err := testCompile(vc, "S", sdkinstrument.SyncCounter, number.Float64Kind)
+	require.NoError(t, err)
+
+	instA, err := testCompile(vc, "A", sdkinstrument.AsyncCounter, number.Int64Kind)
+	require.NoError(t, err)
+
+	totalS := float64(0)
+	totalA := int64(0)
+
+	for reps := 0; reps < 10; reps++ {
+		for i := 0; i < count; i++ {
+			attr := attribute.Int("RCi", reps*count+i)
+			aset := attribute.NewSet(attr)
+
+			accS := instS.NewAccumulator(aset)
+			accS.(Updater[float64]).Update(1)
+			accS.SnapshotAndProcess(true)
+
+			accA := instA.NewAccumulator(aset)
+			accA.(Updater[int64]).Update(1)
+			accA.SnapshotAndProcess(true)
+		}
+
+		// Both experience overflow; neither exceeds its limit
+		data := testCollect(t, vc)
+		require.Equal(t, test.Descriptor("S", sdkinstrument.SyncCounter, number.Float64Kind), data[0].Descriptor)
+		require.Equal(t, test.Descriptor("A", sdkinstrument.AsyncCounter, number.Int64Kind), data[1].Descriptor)
+
+		// As tested in syncstate, there is an oscillation that
+		// develops when a delta temporality experiences major
+		// overflow.  We're not testing the form of the overflow here,
+		// just that the sum is correct.
+		oflowSCnt := 0
+		sumS := 0.0
+		for _, pt := range data[0].Points {
+			if pt.Attributes == pipeline.OverflowAttributeSet {
+				oflowSCnt++
+			}
+			sumS += number.ToFloat64(pt.Aggregation.(aggregation.Sum).Sum())
+		}
+		if reps == 0 {
+			require.Equal(t, 1, oflowSCnt)
+			require.Equal(t, float64(count), sumS)
+		}
+		totalS += sumS
+		require.Equal(t, float64((reps+1)*count), totalS, "rep %d", reps)
+
+		// Note that because the attribute set is new every
+		// time, we expect a new sum in every round equal to count.
+		// See the special case treatment of overflow in the async
+		// delta-temporality aggregator.
+		oflowACnt := 0
+		sumA := int64(0)
+		for _, pt := range data[1].Points {
+			if pt.Attributes == pipeline.OverflowAttributeSet {
+				oflowACnt++
+			}
+			sumA += number.ToInt64(pt.Aggregation.(aggregation.Sum).Sum())
+		}
+		if reps == 0 {
+			require.Equal(t, 1, oflowACnt)
+			require.Equal(t, int64(count), sumA)
+		}
+		totalA += sumA
+		require.Equal(t, int64((reps+1)*count), totalA, "rep %d", reps)
+	}
+}
diff --git a/lightstep/sdk/metric/view/views_test.go b/lightstep/sdk/metric/view/views_test.go
index fec99e6..6099990 100644
--- a/lightstep/sdk/metric/view/views_test.go
+++ b/lightstep/sdk/metric/view/views_test.go
@@ -29,6 +29,8 @@ import (
 	"go.opentelemetry.io/otel/sdk/instrumentation"
 )
 
+var safePerf sdkinstrument.Performance
+
 func TestClauseMatches(t *testing.T) {
 	re := regexp.MustCompile("s.+")
 	lib0 := instrumentation.Library{
@@ -39,6 +41,7 @@ func TestClauseMatches(t *testing.T) {
 		Version: "vF.G.H",
 	}
 	views := New("test",
+		sdkinstrument.Performance{},
 		WithClause(MatchInstrumentName("single")),
 		WithClause(MatchInstrumentNameRegexp(re)),
 		WithClause(MatchInstrumentKind(sdkinstrument.AsyncCounter)),
@@ -101,6 +104,9 @@ func TestClauseMatches(t *testing.T) {
 
 func TestClauseProperties(t *testing.T) {
 	views := New("test",
+		sdkinstrument.Performance{
+			AggregatorCardinalityLimit: 1777,
+		},
 		WithClause(WithName("longname"), MatchInstrumentName("single")),
 		WithClause(WithDescription("very interesting")),
 		WithClause(WithKeys(nil)),
@@ -118,11 +124,14 @@ func TestClauseProperties(t *testing.T) {
 	require.Equal(t, []attribute.Key(nil), views.Clauses[2].Keys())
 	require.Equal(t, []attribute.Key{}, views.Clauses[3].Keys())
 	require.Equal(t, aggregation.DropKind, views.Clauses[4].Aggregation())
-	require.Equal(t, aggregator.Config{Histogram: histogram.NewConfig(histogram.WithMaxSize(177))}, views.Clauses[5].AggregatorConfig())
+	require.Equal(t, aggregator.Config{
+		Histogram:        histogram.NewConfig(histogram.WithMaxSize(177)),
+		CardinalityLimit: 1777,
+	}, views.Clauses[5].AggregatorConfig())
 }
 
 func TestNameAndRegexp(t *testing.T) {
-	views := New("test", WithClause(
+	views := New("test", safePerf, WithClause(
 		MatchInstrumentName("yes"),
 		MatchInstrumentNameRegexp(regexp.MustCompile("no")),
 	))
@@ -134,7 +143,7 @@ func TestNameAndRegexp(t *testing.T) {
 }
 
 func TestEmptyKeyString(t *testing.T) {
-	views := New("test", WithClause(
+	views := New("test", safePerf, WithClause(
 		WithKeys([]attribute.Key{
 			attribute.Key(""),
 		}),
@@ -147,7 +156,7 @@ func TestEmptyKeyString(t *testing.T) {
 }
 
 func TestSingleNameConflict(t *testing.T) {
-	views := New("test", WithClause(
+	views := New("test", safePerf, WithClause(
 		WithName("aha"),
 	))
 
@@ -158,7 +167,7 @@ func TestSingleNameConflict(t *testing.T) {
 }
 
 func TestStandardTemporality(t *testing.T) {
-	views := New("test",
+	views := New("test", safePerf,
 		WithDefaultAggregationTemporalitySelector(StandardTemporality),
 	)
 	expectStandardTemporality(t, views)
@@ -171,7 +180,7 @@ func expectStandardTemporality(t *testing.T, v *Views) {
 }
 
 func TestDeltaPreferredTemporality(t *testing.T) {
-	views := New("test",
+	views := New("test", safePerf,
 		WithDefaultAggregationTemporalitySelector(DeltaPreferredTemporality),
 	)
 	for i := sdkinstrument.Kind(0); i < sdkinstrument.NumKinds; i++ {
@@ -185,7 +194,7 @@ func TestDeltaPreferredTemporality(t *testing.T) {
 }
 
 func TestStandardAggregation(t *testing.T) {
-	views := New("test",
+	views := New("test", safePerf,
 		WithDefaultAggregationKindSelector(StandardAggregationKind),
 	)
 	expectStandardAggregation(t, views)
@@ -209,7 +218,7 @@ func expectStandardAggregation(t *testing.T, v *Views) {
 }
 
 func TestInvalidViewDefaults(t *testing.T) {
-	views := New("",
+	views := New("", safePerf,
 		WithDefaultAggregationKindSelector(func(_ sdkinstrument.Kind) aggregation.Kind {
 			return 1999
 		}),