Repository: knative-sandbox/eventing-kafka-broker
Pull request #2008 (2022-03-16 09:47:53)

[release-1.3] Implement new trigger filters experimental feature (SubscriptionsAPI Filters)
This is an automated cherry-pick of #1922

```release-note
- 🎁 Add new `new-trigger-filters` experimental feature. When enabled, Triggers support a new `filters` field that conforms to the filters API field defined in the [`CloudEvents Subscriptions API`](https://github.com/cloudevents/spec/blob/main/subscriptions/spec.md#324-filters). It allows you to specify a set of powerful filter expressions, where each expression evaluates to either true or false for each event.
```

knative-prow-robot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative-sandbox/eventing-kafka-broker/pull/2008#" title="Author self-approved">knative-prow-robot</a>*
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **devguyio** after the PR has been reviewed.
You can assign the PR to them by writing `/assign @devguyio` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative-sandbox%2Feventing-kafka-broker).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/knative-sandbox/eventing-kafka-broker/blob/release-1.3/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["devguyio"]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/knative-sandbox/eventing-kafka-broker/pull/2008?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) Report
> :exclamation: No coverage uploaded for pull request base (`release-1.3@c2d5ac8`). [Click here to learn what that means](https://docs.codecov.io/docs/error-reference?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#section-missing-base-commit).
> The diff coverage is `n/a`.

```diff
@@              Coverage Diff               @@
##             release-1.3    #2008   +/-   ##
==============================================
  Coverage               ?   60.25%           
==============================================
  Files                  ?       69           
  Lines                  ?     4547           
  Branches               ?        0           
==============================================
  Hits                   ?     2740           
  Misses                 ?     1531           
  Partials               ?      276           
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/knative-sandbox/eventing-kafka-broker/pull/2008?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/knative-sandbox/eventing-kafka-broker/pull/2008?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox). Last update [c2d5ac8...116523c](https://codecov.io/gh/knative-sandbox/eventing-kafka-broker/pull/2008?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox).

knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative-sandbox/eventing-kafka-broker/pull/2008#" title="Author self-approved">knative-prow-robot</a>*, *<a href="https://github.com/knative-sandbox/eventing-kafka-broker/pull/2008#pullrequestreview-911360298" title="Approved">pierDipi</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative-sandbox%2Feventing-kafka-broker).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/knative-sandbox/eventing-kafka-broker/blob/release-1.3/OWNERS)~~ [pierDipi]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
devguyio: ```
        --- FAIL: TestKafkaSourceAssureIsOperational/0/with_overrides_plain-v1beta1 (32.97s)
```

pierDipi: unrelated
```
operation.go:130: Failed while waiting for 1 endpoints in service subscriber: did not reach the desired number of endpoints, got: 0: endpoints "subscriber" not found
            knative.dev/eventing/test/lib.(*Client).WaitForServiceEndpointsOrFail
            	/home/runner/work/eventing-kafka-broker/eventing-kafka-broker/src/knative.dev/eventing-kafka-broker/vendor/knative.dev/eventing/test/lib/operation.go:130
            knative.dev/eventing/test/lib/recordevents.DeployEventRecordOrFail
            	/home/runner/work/eventing-kafka-broker/eventing-kafka-broker/src/knative.dev/eventing-kafka-broker/vendor/knative.dev/eventing/test/lib/recordevents/resources.go:62
            knative.dev/eventing/test/lib/recordevents.StartEventRecordOrFail
            	/home/runner/work/eventing-kafka-broker/eventing-kafka-broker/src/knative.dev/eventing-kafka-broker/vendor/knative.dev/eventing/test/lib/recordevents/event_info_store.go:[45](https://github.com/knative-sandbox/eventing-kafka-broker/runs/5567802225?check_suite_focus=true#step:11:45)
            knative.dev/eventing-kafka-broker/test/e2e.brokerAuth.func1
            	/home/runner/work/eventing-kafka-broker/eventing-kafka-broker/src/knative.dev/eventing-kafka-broker/test/e2e/broker_sasl_ssl_test.go:122
            testing.tRunner
            	/opt/hostedtoolcache/go/1.17.7/x64/src/testing/testing.go:1259
            runtime.goexit
            	/opt/hostedtoolcache/go/1.17.7/x64/src/runtime/asm_amd64.s:1581
```

```
creation.go:121: Failed to update v1beta1 KafkaSource "e2e-kafka-source-change-sink": Internal error occurred: failed calling webhook "defaulting.webhook.kafka.eventing.knative.dev": failed to call webhook: Post "[https://kafka-webhook-eventing.knative-eventing.svc:443/defaulting?timeout=2s](https://kafka-webhook-eventing.knative-eventing.svc/defaulting?timeout=2s)": dial tcp 10.96.124.33:443: connect: connection refused
```

/unhold

Patch:
diff --git a/control-plane/pkg/contract/contract.pb.go b/control-plane/pkg/contract/contract.pb.go
index 9c4c1a8fd..abdafb042 100644
--- a/control-plane/pkg/contract/contract.pb.go
+++ b/control-plane/pkg/contract/contract.pb.go
@@ -420,8 +420,7 @@ type Prefix struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Attribute string `protobuf:"bytes,1,opt,name=attribute,proto3" json:"attribute,omitempty"`
-	Prefix    string `protobuf:"bytes,2,opt,name=prefix,proto3" json:"prefix,omitempty"`
+	Attributes map[string]string `protobuf:"bytes,1,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 }
 
 func (x *Prefix) Reset() {
@@ -456,18 +455,11 @@ func (*Prefix) Descriptor() ([]byte, []int) {
 	return file_contract_proto_rawDescGZIP(), []int{2}
 }
 
-func (x *Prefix) GetAttribute() string {
-	if x != nil {
-		return x.Attribute
-	}
-	return ""
-}
-
-func (x *Prefix) GetPrefix() string {
+func (x *Prefix) GetAttributes() map[string]string {
 	if x != nil {
-		return x.Prefix
+		return x.Attributes
 	}
-	return ""
+	return nil
 }
 
 type Suffix struct {
@@ -475,8 +467,7 @@ type Suffix struct {
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
 
-	Attribute string `protobuf:"bytes,1,opt,name=attribute,proto3" json:"attribute,omitempty"`
-	Suffix    string `protobuf:"bytes,2,opt,name=suffix,proto3" json:"suffix,omitempty"`
+	Attributes map[string]string `protobuf:"bytes,1,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
 }
 
 func (x *Suffix) Reset() {
@@ -511,18 +502,11 @@ func (*Suffix) Descriptor() ([]byte, []int) {
 	return file_contract_proto_rawDescGZIP(), []int{3}
 }
 
-func (x *Suffix) GetAttribute() string {
-	if x != nil {
-		return x.Attribute
-	}
-	return ""
-}
-
-func (x *Suffix) GetSuffix() string {
+func (x *Suffix) GetAttributes() map[string]string {
 	if x != nil {
-		return x.Suffix
+		return x.Attributes
 	}
-	return ""
+	return nil
 }
 
 type All struct {
@@ -1854,206 +1838,214 @@ var file_contract_proto_rawDesc = []byte{
 	0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
 	0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
 	0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
-	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3e, 0x0a, 0x06, 0x50, 0x72, 0x65,
-	0x66, 0x69, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
-	0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x3e, 0x0a, 0x06, 0x53, 0x75, 0x66,
-	0x66, 0x69, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
-	0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x22, 0x31, 0x0a, 0x03, 0x41, 0x6c, 0x6c,
-	0x12, 0x2a, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
-	0x0b, 0x32, 0x10, 0x2e, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c,
-	0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x31, 0x0a, 0x03,
-	0x41, 0x6e, 0x79, 0x12, 0x2a, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x01,
-	0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64,
-	0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22,
-	0x2f, 0x0a, 0x03, 0x4e, 0x6f, 0x74, 0x12, 0x28, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74,
-	0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
-	0x22, 0x27, 0x0a, 0x05, 0x43, 0x45, 0x53, 0x51, 0x4c, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70,
-	0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65,
-	0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xef, 0x01, 0x0a, 0x0f, 0x44, 0x69,
-	0x61, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a,
-	0x05, 0x65, 0x78, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x45,
-	0x78, 0x61, 0x63, 0x74, 0x48, 0x00, 0x52, 0x05, 0x65, 0x78, 0x61, 0x63, 0x74, 0x12, 0x21, 0x0a,
-	0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e,
-	0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x48, 0x00, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78,
-	0x12, 0x21, 0x0a, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x07, 0x2e, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x48, 0x00, 0x52, 0x06, 0x73, 0x75, 0x66,
-	0x66, 0x69, 0x78, 0x12, 0x18, 0x0a, 0x03, 0x61, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x04, 0x2e, 0x41, 0x6c, 0x6c, 0x48, 0x00, 0x52, 0x03, 0x61, 0x6c, 0x6c, 0x12, 0x18, 0x0a,
-	0x03, 0x61, 0x6e, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x41, 0x6e, 0x79,
-	0x48, 0x00, 0x52, 0x03, 0x61, 0x6e, 0x79, 0x12, 0x18, 0x0a, 0x03, 0x6e, 0x6f, 0x74, 0x18, 0x06,
-	0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x4e, 0x6f, 0x74, 0x48, 0x00, 0x52, 0x03, 0x6e, 0x6f,
-	0x74, 0x12, 0x1e, 0x0a, 0x05, 0x63, 0x65, 0x73, 0x71, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x06, 0x2e, 0x43, 0x45, 0x53, 0x51, 0x4c, 0x48, 0x00, 0x52, 0x05, 0x63, 0x65, 0x73, 0x71,
-	0x6c, 0x42, 0x08, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x80, 0x01, 0x0a, 0x06,
-	0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62,
-	0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x46, 0x69, 0x6c,
-	0x74, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e,
-	0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a,
-	0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74,
-	0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb8,
-	0x01, 0x0a, 0x0c, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
-	0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x61, 0x64, 0x4c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20,
-	0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x61, 0x64, 0x4c, 0x65, 0x74, 0x74, 0x65, 0x72, 0x12,
-	0x14, 0x0a, 0x05, 0x72, 0x65, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x05,
-	0x72, 0x65, 0x74, 0x72, 0x79, 0x12, 0x34, 0x0a, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66,
-	0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x42,
-	0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x0d, 0x62, 0x61,
-	0x63, 0x6b, 0x6f, 0x66, 0x66, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x22, 0x0a, 0x0c, 0x62,
-	0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28,
-	0x04, 0x52, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x44, 0x65, 0x6c, 0x61, 0x79, 0x12,
-	0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04,
-	0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x91, 0x04, 0x0a, 0x06, 0x45, 0x67,
-	0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72,
-	0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e,
-	0x73, 0x75, 0x6d, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65,
-	0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x08,
-	0x72, 0x65, 0x70, 0x6c, 0x79, 0x55, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00,
-	0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x3c, 0x0a, 0x14, 0x72, 0x65,
-	0x70, 0x6c, 0x79, 0x54, 0x6f, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x70,
-	0x69, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
-	0x48, 0x00, 0x52, 0x14, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x4f, 0x72, 0x69, 0x67, 0x69,
-	0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2c, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x63,
-	0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06,
-	0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x0c, 0x64, 0x69, 0x73, 0x63, 0x61, 0x72,
-	0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
-	0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52,
-	0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x06,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x0c, 0x65, 0x67, 0x72,
-	0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x0d, 0x2e, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c,
-	0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x34, 0x0a, 0x0d,
-	0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20,
-	0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x4f, 0x72,
-	0x64, 0x65, 0x72, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64,
-	0x65, 0x72, 0x12, 0x22, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x18, 0x0a, 0x20,
-	0x01, 0x28, 0x0e, 0x32, 0x08, 0x2e, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x6b,
-	0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
-	0x6e, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x52, 0x65, 0x66, 0x65,
-	0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
-	0x12, 0x3a, 0x0a, 0x0f, 0x64, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c,
-	0x74, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x44, 0x69, 0x61, 0x6c,
-	0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x0f, 0x64, 0x69, 0x61,
-	0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x0f, 0x0a, 0x0d,
-	0x72, 0x65, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x22, 0x74, 0x0a,
-	0x07, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74,
-	0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e,
-	0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0b, 0x63, 0x6f, 0x6e,
-	0x74, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x14,
-	0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04,
-	0x68, 0x6f, 0x73, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x54,
-	0x79, 0x70, 0x65, 0x22, 0x6b, 0x0a, 0x09, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
-	0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
-	0x75, 0x75, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63,
-	0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
-	0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
-	0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
-	0x22, 0x7f, 0x0a, 0x0f, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65,
-	0x6e, 0x63, 0x65, 0x12, 0x28, 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
-	0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x42, 0x0a,
-	0x12, 0x6b, 0x65, 0x79, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
-	0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x4b, 0x65, 0x79, 0x46,
-	0x69, 0x65, 0x6c, 0x64, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x12, 0x6b,
-	0x65, 0x79, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
-	0x73, 0x22, 0x55, 0x0a, 0x11, 0x4b, 0x65, 0x79, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x65, 0x66,
-	0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74,
-	0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65,
-	0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x03, 0x20,
-	0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x65, 0x6c,
-	0x64, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x6f, 0x0a, 0x14, 0x4d, 0x75, 0x6c, 0x74,
-	0x69, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65,
-	0x12, 0x25, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01,
-	0x28, 0x0e, 0x32, 0x09, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x30, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72,
-	0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x53, 0x65,
-	0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x72,
-	0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x9a, 0x01, 0x0a, 0x13, 0x43, 0x6c,
+	0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x80, 0x01, 0x0a, 0x06, 0x50, 0x72,
+	0x65, 0x66, 0x69, 0x78, 0x12, 0x37, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74,
+	0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x50, 0x72, 0x65, 0x66, 0x69,
+	0x78, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x3d, 0x0a,
+	0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+	0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x80, 0x01, 0x0a,
+	0x06, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x12, 0x37, 0x0a, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69,
+	0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x53, 0x75,
+	0x66, 0x66, 0x69, 0x78, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45,
+	0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73,
+	0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x45, 0x6e,
+	0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22,
+	0x31, 0x0a, 0x03, 0x41, 0x6c, 0x6c, 0x12, 0x2a, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72,
+	0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63,
+	0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65,
+	0x72, 0x73, 0x22, 0x31, 0x0a, 0x03, 0x41, 0x6e, 0x79, 0x12, 0x2a, 0x0a, 0x07, 0x66, 0x69, 0x6c,
+	0x74, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x44, 0x69, 0x61,
+	0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69,
+	0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x2f, 0x0a, 0x03, 0x4e, 0x6f, 0x74, 0x12, 0x28, 0x0a, 0x06,
+	0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x44,
+	0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06,
+	0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x22, 0x27, 0x0a, 0x05, 0x43, 0x45, 0x53, 0x51, 0x4c, 0x12,
+	0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x22,
+	0xef, 0x01, 0x0a, 0x0f, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c,
+	0x74, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x05, 0x65, 0x78, 0x61, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x06, 0x2e, 0x45, 0x78, 0x61, 0x63, 0x74, 0x48, 0x00, 0x52, 0x05, 0x65, 0x78,
+	0x61, 0x63, 0x74, 0x12, 0x21, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x48, 0x00, 0x52, 0x06,
+	0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x21, 0x0a, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x53, 0x75, 0x66, 0x66, 0x69, 0x78, 0x48,
+	0x00, 0x52, 0x06, 0x73, 0x75, 0x66, 0x66, 0x69, 0x78, 0x12, 0x18, 0x0a, 0x03, 0x61, 0x6c, 0x6c,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x41, 0x6c, 0x6c, 0x48, 0x00, 0x52, 0x03,
+	0x61, 0x6c, 0x6c, 0x12, 0x18, 0x0a, 0x03, 0x61, 0x6e, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x04, 0x2e, 0x41, 0x6e, 0x79, 0x48, 0x00, 0x52, 0x03, 0x61, 0x6e, 0x79, 0x12, 0x18, 0x0a,
+	0x03, 0x6e, 0x6f, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x04, 0x2e, 0x4e, 0x6f, 0x74,
+	0x48, 0x00, 0x52, 0x03, 0x6e, 0x6f, 0x74, 0x12, 0x1e, 0x0a, 0x05, 0x63, 0x65, 0x73, 0x71, 0x6c,
+	0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x43, 0x45, 0x53, 0x51, 0x4c, 0x48, 0x00,
+	0x52, 0x05, 0x63, 0x65, 0x73, 0x71, 0x6c, 0x42, 0x08, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65,
+	0x72, 0x22, 0x80, 0x01, 0x0a, 0x06, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x37, 0x0a, 0x0a,
+	0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b,
+	0x32, 0x17, 0x2e, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2e, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62,
+	0x75, 0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x61, 0x74, 0x74, 0x72, 0x69,
+	0x62, 0x75, 0x74, 0x65, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x41, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75,
+	0x74, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
+	0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
+	0x3a, 0x02, 0x38, 0x01, 0x22, 0xb8, 0x01, 0x0a, 0x0c, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43,
+	0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x65, 0x61, 0x64, 0x4c, 0x65, 0x74,
+	0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x64, 0x65, 0x61, 0x64, 0x4c,
+	0x65, 0x74, 0x74, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x65, 0x74, 0x72, 0x79, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x0d, 0x52, 0x05, 0x72, 0x65, 0x74, 0x72, 0x79, 0x12, 0x34, 0x0a, 0x0d, 0x62,
+	0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x50, 0x6f, 0x6c, 0x69,
+	0x63, 0x79, 0x52, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x50, 0x6f, 0x6c, 0x69, 0x63,
+	0x79, 0x12, 0x22, 0x0a, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x44, 0x65, 0x6c, 0x61,
+	0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66,
+	0x44, 0x65, 0x6c, 0x61, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74,
+	0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22,
+	0x91, 0x04, 0x0a, 0x06, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x63, 0x6f,
+	0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70,
+	0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69,
+	0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x55, 0x72, 0x6c, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x08, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x55, 0x72, 0x6c,
+	0x12, 0x3c, 0x0a, 0x14, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x54, 0x6f, 0x4f, 0x72, 0x69, 0x67, 0x69,
+	0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06,
+	0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x14, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x54,
+	0x6f, 0x4f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x61, 0x6c, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x2c,
+	0x0a, 0x0c, 0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x09,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x0c,
+	0x64, 0x69, 0x73, 0x63, 0x61, 0x72, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x06,
+	0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x46,
+	0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x10, 0x0a,
+	0x03, 0x75, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12,
+	0x31, 0x0a, 0x0c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f,
+	0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66,
+	0x69, 0x67, 0x12, 0x34, 0x0a, 0x0d, 0x64, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x4f, 0x72,
+	0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0e, 0x2e, 0x44, 0x65, 0x6c, 0x69,
+	0x76, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x52, 0x0d, 0x64, 0x65, 0x6c, 0x69, 0x76,
+	0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x07, 0x6b, 0x65, 0x79, 0x54,
+	0x79, 0x70, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x08, 0x2e, 0x4b, 0x65, 0x79, 0x54,
+	0x79, 0x70, 0x65, 0x52, 0x07, 0x6b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x09,
+	0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x0a, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x66,
+	0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x3a, 0x0a, 0x0f, 0x64, 0x69, 0x61, 0x6c, 0x65, 0x63,
+	0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x10, 0x2e, 0x44, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74, 0x65,
+	0x72, 0x52, 0x0f, 0x64, 0x69, 0x61, 0x6c, 0x65, 0x63, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x74,
+	0x65, 0x72, 0x42, 0x0f, 0x0a, 0x0d, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x53, 0x74, 0x72, 0x61, 0x74,
+	0x65, 0x67, 0x79, 0x22, 0x74, 0x0a, 0x07, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2e,
+	0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64,
+	0x65, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x14,
+	0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04,
+	0x70, 0x61, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x42, 0x0d, 0x0a, 0x0b, 0x69, 0x6e,
+	0x67, 0x72, 0x65, 0x73, 0x73, 0x54, 0x79, 0x70, 0x65, 0x22, 0x6b, 0x0a, 0x09, 0x52, 0x65, 0x66,
+	0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61,
+	0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e,
+	0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07,
+	0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76,
+	0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x7f, 0x0a, 0x0f, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74,
+	0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x28, 0x0a, 0x09, 0x72, 0x65, 0x66,
+	0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x52,
+	0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65,
+	0x6e, 0x63, 0x65, 0x12, 0x42, 0x0a, 0x12, 0x6b, 0x65, 0x79, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52,
+	0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x12, 0x2e, 0x4b, 0x65, 0x79, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65,
+	0x6e, 0x63, 0x65, 0x52, 0x12, 0x6b, 0x65, 0x79, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x65, 0x66,
+	0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x55, 0x0a, 0x11, 0x4b, 0x65, 0x79, 0x46, 0x69,
+	0x65, 0x6c, 0x64, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09,
+	0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x22, 0x0a, 0x05, 0x66, 0x69,
+	0x65, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x53, 0x65, 0x63, 0x72,
+	0x65, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x22, 0x6f,
+	0x0a, 0x14, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x66,
+	0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63,
+	0x6f, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x09, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f,
+	0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x30, 0x0a,
+	0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x10, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65,
+	0x6e, 0x63, 0x65, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22,
+	0x9a, 0x01, 0x0a, 0x13, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x76,
+	0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e,
+	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x43, 0x6c,
 	0x6f, 0x75, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65,
-	0x73, 0x12, 0x44, 0x0a, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18,
-	0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x76, 0x65,
-	0x6e, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x2e, 0x45, 0x78, 0x74, 0x65,
-	0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x65, 0x78, 0x74,
-	0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3d, 0x0a, 0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e,
-	0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
-	0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
-	0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
-	0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf1, 0x03, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75,
-	0x72, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x18,
-	0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x70, 0x69, 0x63, 0x73, 0x12, 0x2a, 0x0a,
-	0x10, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72,
-	0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72,
-	0x61, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12, 0x22, 0x0a, 0x07, 0x69, 0x6e, 0x67,
-	0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x49, 0x6e, 0x67,
-	0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x12, 0x31, 0x0a,
-	0x0c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66,
-	0x69, 0x67, 0x52, 0x0c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
-	0x12, 0x23, 0x0a, 0x08, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03,
-	0x28, 0x0b, 0x32, 0x07, 0x2e, 0x45, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x08, 0x65, 0x67, 0x72,
-	0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0a, 0x61, 0x62, 0x73, 0x65, 0x6e, 0x74, 0x41,
-	0x75, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x2e, 0x45, 0x6d, 0x70, 0x74,
-	0x79, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x62, 0x73, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x12,
-	0x2c, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x08, 0x20,
-	0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x48,
-	0x00, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x41, 0x0a,
-	0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74,
-	0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x53, 0x65,
-	0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x48, 0x00, 0x52,
-	0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74,
-	0x12, 0x46, 0x0a, 0x13, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x76,
-	0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e,
-	0x43, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69,
-	0x64, 0x65, 0x73, 0x52, 0x13, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x4f,
-	0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x09, 0x72, 0x65, 0x66, 0x65,
-	0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x52, 0x65,
-	0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e,
-	0x63, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68, 0x22, 0x53, 0x0a, 0x08, 0x43, 0x6f,
-	0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x1e, 0x0a, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61,
-	0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x67, 0x65, 0x6e, 0x65,
-	0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
-	0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x52, 0x65, 0x73, 0x6f,
-	0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2a,
-	0x2c, 0x0a, 0x0d, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79,
-	0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x10,
-	0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x10, 0x01, 0x2a, 0x2b, 0x0a,
-	0x0d, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x4f, 0x72, 0x64, 0x65, 0x72, 0x12, 0x0d,
-	0x0a, 0x09, 0x55, 0x4e, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a,
-	0x07, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x45, 0x44, 0x10, 0x01, 0x2a, 0x3d, 0x0a, 0x07, 0x4b, 0x65,
-	0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x10,
-	0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x10, 0x01, 0x12, 0x0a,
-	0x0a, 0x06, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x42, 0x79,
-	0x74, 0x65, 0x41, 0x72, 0x72, 0x61, 0x79, 0x10, 0x03, 0x2a, 0x29, 0x0a, 0x0b, 0x43, 0x6f, 0x6e,
-	0x74, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41,
-	0x52, 0x59, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x54, 0x52, 0x55, 0x43, 0x54, 0x55, 0x52,
-	0x45, 0x44, 0x10, 0x01, 0x2a, 0x61, 0x0a, 0x0b, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69,
-	0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x41, 0x53, 0x4c, 0x5f, 0x4d, 0x45, 0x43, 0x48,
-	0x41, 0x4e, 0x49, 0x53, 0x4d, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x41, 0x5f, 0x43, 0x52,
-	0x54, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x43, 0x52, 0x54, 0x10,
-	0x02, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x03, 0x12,
-	0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x41, 0x53,
-	0x53, 0x57, 0x4f, 0x52, 0x44, 0x10, 0x05, 0x2a, 0x44, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f,
-	0x63, 0x6f, 0x6c, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x58, 0x54,
-	0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x41, 0x53, 0x4c, 0x5f, 0x50, 0x4c, 0x41, 0x49, 0x4e,
-	0x54, 0x45, 0x58, 0x54, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x53, 0x53, 0x4c, 0x10, 0x02, 0x12,
-	0x0c, 0x0a, 0x08, 0x53, 0x41, 0x53, 0x4c, 0x5f, 0x53, 0x53, 0x4c, 0x10, 0x03, 0x42, 0x5b, 0x0a,
-	0x2a, 0x64, 0x65, 0x76, 0x2e, 0x6b, 0x6e, 0x61, 0x74, 0x69, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65,
-	0x6e, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6b, 0x61, 0x66, 0x6b, 0x61, 0x2e, 0x62, 0x72, 0x6f, 0x6b,
-	0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x42, 0x11, 0x44, 0x61, 0x74,
-	0x61, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x5a, 0x1a,
-	0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2d, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x70, 0x6b,
-	0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
-	0x6f, 0x33,
+	0x73, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72,
+	0x79, 0x52, 0x0a, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x1a, 0x3d, 0x0a,
+	0x0f, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79,
+	0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
+	0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf1, 0x03, 0x0a,
+	0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x69, 0x64,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x69, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x74,
+	0x6f, 0x70, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x74, 0x6f, 0x70,
+	0x69, 0x63, 0x73, 0x12, 0x2a, 0x0a, 0x10, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70,
+	0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x62,
+	0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x12,
+	0x22, 0x0a, 0x07, 0x69, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
+	0x32, 0x08, 0x2e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x52, 0x07, 0x69, 0x6e, 0x67, 0x72,
+	0x65, 0x73, 0x73, 0x12, 0x31, 0x0a, 0x0c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x43, 0x6f, 0x6e,
+	0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x45, 0x67, 0x72, 0x65,
+	0x73, 0x73, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0c, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73,
+	0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x23, 0x0a, 0x08, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73,
+	0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x07, 0x2e, 0x45, 0x67, 0x72, 0x65, 0x73,
+	0x73, 0x52, 0x08, 0x65, 0x67, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x28, 0x0a, 0x0a, 0x61,
+	0x62, 0x73, 0x65, 0x6e, 0x74, 0x41, 0x75, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32,
+	0x06, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x62, 0x73, 0x65, 0x6e,
+	0x74, 0x41, 0x75, 0x74, 0x68, 0x12, 0x2c, 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63,
+	0x72, 0x65, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x52, 0x65, 0x66, 0x65,
+	0x72, 0x65, 0x6e, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x53, 0x65, 0x63,
+	0x72, 0x65, 0x74, 0x12, 0x41, 0x0a, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x41, 0x75, 0x74, 0x68,
+	0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x4d,
+	0x75, 0x6c, 0x74, 0x69, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65,
+	0x6e, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x41, 0x75, 0x74, 0x68,
+	0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x46, 0x0a, 0x13, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x45,
+	0x76, 0x65, 0x6e, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x18, 0x0a, 0x20,
+	0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74,
+	0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x52, 0x13, 0x63, 0x6c, 0x6f, 0x75, 0x64,
+	0x45, 0x76, 0x65, 0x6e, 0x74, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x73, 0x12, 0x28,
+	0x0a, 0x09, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28,
+	0x0b, 0x32, 0x0a, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, 0x72,
+	0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x41, 0x75, 0x74, 0x68,
+	0x22, 0x53, 0x0a, 0x08, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74, 0x12, 0x1e, 0x0a, 0x0a,
+	0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x0a, 0x67, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x09,
+	0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32,
+	0x09, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f,
+	0x75, 0x72, 0x63, 0x65, 0x73, 0x2a, 0x2c, 0x0a, 0x0d, 0x42, 0x61, 0x63, 0x6b, 0x6f, 0x66, 0x66,
+	0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x0f, 0x0a, 0x0b, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65,
+	0x6e, 0x74, 0x69, 0x61, 0x6c, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x69, 0x6e, 0x65, 0x61,
+	0x72, 0x10, 0x01, 0x2a, 0x2b, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x69, 0x76, 0x65, 0x72, 0x79, 0x4f,
+	0x72, 0x64, 0x65, 0x72, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x45,
+	0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x4f, 0x52, 0x44, 0x45, 0x52, 0x45, 0x44, 0x10, 0x01,
+	0x2a, 0x3d, 0x0a, 0x07, 0x4b, 0x65, 0x79, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x53,
+	0x74, 0x72, 0x69, 0x6e, 0x67, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x6e, 0x74, 0x65, 0x67,
+	0x65, 0x72, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x10, 0x02,
+	0x12, 0x0d, 0x0a, 0x09, 0x42, 0x79, 0x74, 0x65, 0x41, 0x72, 0x72, 0x61, 0x79, 0x10, 0x03, 0x2a,
+	0x29, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a,
+	0x0a, 0x06, 0x42, 0x49, 0x4e, 0x41, 0x52, 0x59, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x53, 0x54,
+	0x52, 0x55, 0x43, 0x54, 0x55, 0x52, 0x45, 0x44, 0x10, 0x01, 0x2a, 0x61, 0x0a, 0x0b, 0x53, 0x65,
+	0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x41, 0x53,
+	0x4c, 0x5f, 0x4d, 0x45, 0x43, 0x48, 0x41, 0x4e, 0x49, 0x53, 0x4d, 0x10, 0x00, 0x12, 0x0a, 0x0a,
+	0x06, 0x43, 0x41, 0x5f, 0x43, 0x52, 0x54, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45,
+	0x52, 0x5f, 0x43, 0x52, 0x54, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, 0x45, 0x52, 0x5f,
+	0x4b, 0x45, 0x59, 0x10, 0x03, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x04, 0x12,
+	0x0c, 0x0a, 0x08, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x10, 0x05, 0x2a, 0x44, 0x0a,
+	0x08, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x0d, 0x0a, 0x09, 0x50, 0x4c, 0x41,
+	0x49, 0x4e, 0x54, 0x45, 0x58, 0x54, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x53, 0x41, 0x53, 0x4c,
+	0x5f, 0x50, 0x4c, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x58, 0x54, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03,
+	0x53, 0x53, 0x4c, 0x10, 0x02, 0x12, 0x0c, 0x0a, 0x08, 0x53, 0x41, 0x53, 0x4c, 0x5f, 0x53, 0x53,
+	0x4c, 0x10, 0x03, 0x42, 0x5b, 0x0a, 0x2a, 0x64, 0x65, 0x76, 0x2e, 0x6b, 0x6e, 0x61, 0x74, 0x69,
+	0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x67, 0x2e, 0x6b, 0x61, 0x66, 0x6b,
+	0x61, 0x2e, 0x62, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63,
+	0x74, 0x42, 0x11, 0x44, 0x61, 0x74, 0x61, 0x50, 0x6c, 0x61, 0x6e, 0x65, 0x43, 0x6f, 0x6e, 0x74,
+	0x72, 0x61, 0x63, 0x74, 0x5a, 0x1a, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2d, 0x70, 0x6c,
+	0x61, 0x6e, 0x65, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x61, 0x63, 0x74,
+	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -2069,7 +2061,7 @@ func file_contract_proto_rawDescGZIP() []byte {
 }
 
 var file_contract_proto_enumTypes = make([]protoimpl.EnumInfo, 6)
-var file_contract_proto_msgTypes = make([]protoimpl.MessageInfo, 23)
+var file_contract_proto_msgTypes = make([]protoimpl.MessageInfo, 25)
 var file_contract_proto_goTypes = []interface{}{
 	(BackoffPolicy)(0),           // 0: BackoffPolicy
 	(DeliveryOrder)(0),           // 1: DeliveryOrder
@@ -2098,52 +2090,56 @@ var file_contract_proto_goTypes = []interface{}{
 	(*Resource)(nil),             // 24: Resource
 	(*Contract)(nil),             // 25: Contract
 	nil,                          // 26: Exact.AttributesEntry
-	nil,                          // 27: Filter.AttributesEntry
-	nil,                          // 28: CloudEventOverrides.ExtensionsEntry
+	nil,                          // 27: Prefix.AttributesEntry
+	nil,                          // 28: Suffix.AttributesEntry
+	nil,                          // 29: Filter.AttributesEntry
+	nil,                          // 30: CloudEventOverrides.ExtensionsEntry
 }
 var file_contract_proto_depIdxs = []int32{
 	26, // 0: Exact.attributes:type_name -> Exact.AttributesEntry
-	14, // 1: All.filters:type_name -> DialectedFilter
-	14, // 2: Any.filters:type_name -> DialectedFilter
-	14, // 3: Not.filter:type_name -> DialectedFilter
-	7,  // 4: DialectedFilter.exact:type_name -> Exact
-	8,  // 5: DialectedFilter.prefix:type_name -> Prefix
-	9,  // 6: DialectedFilter.suffix:type_name -> Suffix
-	10, // 7: DialectedFilter.all:type_name -> All
-	11, // 8: DialectedFilter.any:type_name -> Any
-	12, // 9: DialectedFilter.not:type_name -> Not
-	13, // 10: DialectedFilter.cesql:type_name -> CESQL
-	27, // 11: Filter.attributes:type_name -> Filter.AttributesEntry
-	0,  // 12: EgressConfig.backoffPolicy:type_name -> BackoffPolicy
-	6,  // 13: Egress.replyToOriginalTopic:type_name -> Empty
-	6,  // 14: Egress.discardReply:type_name -> Empty
-	15, // 15: Egress.filter:type_name -> Filter
-	16, // 16: Egress.egressConfig:type_name -> EgressConfig
-	1,  // 17: Egress.deliveryOrder:type_name -> DeliveryOrder
-	2,  // 18: Egress.keyType:type_name -> KeyType
-	19, // 19: Egress.reference:type_name -> Reference
-	14, // 20: Egress.dialectedFilter:type_name -> DialectedFilter
-	3,  // 21: Ingress.contentMode:type_name -> ContentMode
-	19, // 22: SecretReference.reference:type_name -> Reference
-	21, // 23: SecretReference.keyFieldReferences:type_name -> KeyFieldReference
-	4,  // 24: KeyFieldReference.field:type_name -> SecretField
-	5,  // 25: MultiSecretReference.protocol:type_name -> Protocol
-	20, // 26: MultiSecretReference.references:type_name -> SecretReference
-	28, // 27: CloudEventOverrides.extensions:type_name -> CloudEventOverrides.ExtensionsEntry
-	18, // 28: Resource.ingress:type_name -> Ingress
-	16, // 29: Resource.egressConfig:type_name -> EgressConfig
-	17, // 30: Resource.egresses:type_name -> Egress
-	6,  // 31: Resource.absentAuth:type_name -> Empty
-	19, // 32: Resource.authSecret:type_name -> Reference
-	22, // 33: Resource.multiAuthSecret:type_name -> MultiSecretReference
-	23, // 34: Resource.cloudEventOverrides:type_name -> CloudEventOverrides
-	19, // 35: Resource.reference:type_name -> Reference
-	24, // 36: Contract.resources:type_name -> Resource
-	37, // [37:37] is the sub-list for method output_type
-	37, // [37:37] is the sub-list for method input_type
-	37, // [37:37] is the sub-list for extension type_name
-	37, // [37:37] is the sub-list for extension extendee
-	0,  // [0:37] is the sub-list for field type_name
+	27, // 1: Prefix.attributes:type_name -> Prefix.AttributesEntry
+	28, // 2: Suffix.attributes:type_name -> Suffix.AttributesEntry
+	14, // 3: All.filters:type_name -> DialectedFilter
+	14, // 4: Any.filters:type_name -> DialectedFilter
+	14, // 5: Not.filter:type_name -> DialectedFilter
+	7,  // 6: DialectedFilter.exact:type_name -> Exact
+	8,  // 7: DialectedFilter.prefix:type_name -> Prefix
+	9,  // 8: DialectedFilter.suffix:type_name -> Suffix
+	10, // 9: DialectedFilter.all:type_name -> All
+	11, // 10: DialectedFilter.any:type_name -> Any
+	12, // 11: DialectedFilter.not:type_name -> Not
+	13, // 12: DialectedFilter.cesql:type_name -> CESQL
+	29, // 13: Filter.attributes:type_name -> Filter.AttributesEntry
+	0,  // 14: EgressConfig.backoffPolicy:type_name -> BackoffPolicy
+	6,  // 15: Egress.replyToOriginalTopic:type_name -> Empty
+	6,  // 16: Egress.discardReply:type_name -> Empty
+	15, // 17: Egress.filter:type_name -> Filter
+	16, // 18: Egress.egressConfig:type_name -> EgressConfig
+	1,  // 19: Egress.deliveryOrder:type_name -> DeliveryOrder
+	2,  // 20: Egress.keyType:type_name -> KeyType
+	19, // 21: Egress.reference:type_name -> Reference
+	14, // 22: Egress.dialectedFilter:type_name -> DialectedFilter
+	3,  // 23: Ingress.contentMode:type_name -> ContentMode
+	19, // 24: SecretReference.reference:type_name -> Reference
+	21, // 25: SecretReference.keyFieldReferences:type_name -> KeyFieldReference
+	4,  // 26: KeyFieldReference.field:type_name -> SecretField
+	5,  // 27: MultiSecretReference.protocol:type_name -> Protocol
+	20, // 28: MultiSecretReference.references:type_name -> SecretReference
+	30, // 29: CloudEventOverrides.extensions:type_name -> CloudEventOverrides.ExtensionsEntry
+	18, // 30: Resource.ingress:type_name -> Ingress
+	16, // 31: Resource.egressConfig:type_name -> EgressConfig
+	17, // 32: Resource.egresses:type_name -> Egress
+	6,  // 33: Resource.absentAuth:type_name -> Empty
+	19, // 34: Resource.authSecret:type_name -> Reference
+	22, // 35: Resource.multiAuthSecret:type_name -> MultiSecretReference
+	23, // 36: Resource.cloudEventOverrides:type_name -> CloudEventOverrides
+	19, // 37: Resource.reference:type_name -> Reference
+	24, // 38: Contract.resources:type_name -> Resource
+	39, // [39:39] is the sub-list for method output_type
+	39, // [39:39] is the sub-list for method input_type
+	39, // [39:39] is the sub-list for extension type_name
+	39, // [39:39] is the sub-list for extension extendee
+	0,  // [0:39] is the sub-list for field type_name
 }
 
 func init() { file_contract_proto_init() }
@@ -2422,7 +2418,7 @@ func file_contract_proto_init() {
 			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
 			RawDescriptor: file_contract_proto_rawDesc,
 			NumEnums:      6,
-			NumMessages:   23,
+			NumMessages:   25,
 			NumExtensions: 0,
 			NumServices:   0,
 		},
diff --git a/control-plane/pkg/contract/subscriptionsapi.go b/control-plane/pkg/contract/subscriptionsapi.go
new file mode 100644
index 000000000..32e3e2a25
--- /dev/null
+++ b/control-plane/pkg/contract/subscriptionsapi.go
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2022 The Knative 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 contract
+
+import v1 "knative.dev/eventing/pkg/apis/eventing/v1"
+
+// newExactFilter converts the SubscriptionsAPIFilter into the exact dialect of
+// the DialectedFilter as defined in CloudEvents Subscriptions API.
+//
+// Exact contains exactly one attribute where the key is the name of the CloudEvent
+// attribute and its value is the string value which must exactly match the value
+// of the CloudEvent attribute.
+//
+// See "CNCF CloudEvents Subscriptions API" > "3.2.4.1 Filters Dialects"
+// https://github.com/cloudevents/spec/blob/main/subscriptions/spec.md#all-filter-dialect
+func newExactFilter(f v1.SubscriptionsAPIFilter) *DialectedFilter {
+	return &DialectedFilter{
+		Filter: &DialectedFilter_Exact{
+			Exact: &Exact{
+				Attributes: f.Exact,
+			},
+		},
+	}
+}
+
+// newPrefixFilter converts the SubscriptionsAPIFilter into the suffix dialect of
+// the DialectedFilter as defined in CloudEvents Subscriptions API.
+//
+// Prefix contains exactly one attribute where the key is the name of the CloudEvent
+// attribute which value must start with the value specified.
+//
+// See "CNCF CloudEvents Subscriptions API" > "3.2.4.1 Filters Dialects"
+// https://github.com/cloudevents/spec/blob/main/subscriptions/spec.md#prefix-filter-dialect
+func newPrefixFilter(f v1.SubscriptionsAPIFilter) *DialectedFilter {
+	return &DialectedFilter{
+		Filter: &DialectedFilter_Prefix{
+			Prefix: &Prefix{
+				Attributes: f.Prefix,
+			},
+		},
+	}
+}
+
+// newSuffixFilter converts the SubscriptionsAPIFilter into the suffix dialect of
+// the DialectedFilter as defined in CloudEvents Subscriptions API.
+//
+// Suffix contains exactly one attribute where the key is the name of the CloudEvent
+// attribute which value must end with the value specified.
+//
+// See "CNCF CloudEvents Subscriptions API" > "3.2.4.1 Filters Dialects"
+// https://github.com/cloudevents/spec/blob/main/subscriptions/spec.md#suffix-filter-dialect
+func newSuffixFilter(f v1.SubscriptionsAPIFilter) *DialectedFilter {
+	return &DialectedFilter{
+		Filter: &DialectedFilter_Suffix{
+			Suffix: &Suffix{
+				Attributes: f.Suffix,
+			},
+		},
+	}
+}
+
+// newAllFilter converts the SubscriptionsAPIFilter into the all dialect of the
+// DialectedFilter as defined in CloudEvents Subscriptions API.
+//
+// All filter evaluates to true when all nested filters evaluate to true.
+//
+// See "CNCF CloudEvents Subscriptions API" > "3.2.4.1 Filters Dialects"
+// https://github.com/cloudevents/spec/blob/main/subscriptions/spec.md#all-filter-dialect
+func newAllFilter(filters []v1.SubscriptionsAPIFilter) *DialectedFilter {
+	all := make([]*DialectedFilter, 0, len(filters))
+
+	for _, f := range filters {
+		all = append(all, FromSubscriptionFilter(f))
+	}
+	return &DialectedFilter{
+		Filter: &DialectedFilter_All{
+			All: &All{Filters: all},
+		},
+	}
+}
+
+// newAnyFilter converts the SubscriptionsAPIFilter into the any dialect of the
+// DialectedFilter as defined in CloudEvents Subscriptions API.
+//
+// All filter evaluates to true when all nested filters evaluate to true.
+//
+// See "CNCF CloudEvents Subscriptions API" > "3.2.4.1 Filters Dialects"
+// https://github.com/cloudevents/spec/blob/main/subscriptions/spec.md#any-filter-dialect
+func newAnyFilter(filters []v1.SubscriptionsAPIFilter) *DialectedFilter {
+	any := make([]*DialectedFilter, 0, len(filters))
+	for _, f := range filters {
+		any = append(any, FromSubscriptionFilter(f))
+	}
+	return &DialectedFilter{
+		Filter: &DialectedFilter_Any{
+			Any: &Any{Filters: any},
+		},
+	}
+}
+
+// newNotFilter converts the SubscriptionsAPIFilter into the not dialect of the
+// DialectedFilter as defined in CloudEvents Subscriptions API.
+//
+// Not filter evaluates to true when the nested filter evaluates to false.
+//
+// See "CNCF CloudEvents Subscriptions API" > "3.2.4.1 Filters Dialects"
+// https://github.com/cloudevents/spec/blob/main/subscriptions/spec.md#not-filter-dialect
+func newNotFilter(f v1.SubscriptionsAPIFilter) *DialectedFilter {
+	return &DialectedFilter{
+		Filter: &DialectedFilter_Not{
+			Not: &Not{
+				Filter: FromSubscriptionFilter(f),
+			},
+		},
+	}
+}
+
+// newCESQLFilter converts the SubscriptionsAPIFilter into the sql dialect of the
+// DialectedFilter as defined in CloudEvents Subscriptions API.
+//
+// CESOL filter is a Cloud Events SQL Expression
+//
+// See "CNCF CloudEvents Subscriptions API" > "3.2.4.1 Filters Dialects"
+// https://github.com/cloudevents/spec/blob/main/subscriptions/sql.md#any-filter-dialect
+//
+// See "CNCF CloudEvents SQL Expression Language"
+// https://github.com/cloudevents/spec/blob/main/cesql/spec.md
+func newCESQLFilter(f v1.SubscriptionsAPIFilter) *DialectedFilter {
+	return &DialectedFilter{
+		Filter: &DialectedFilter_Cesql{
+			Cesql: &CESQL{
+				Expression: f.CESQL,
+			},
+		},
+	}
+}
+
+// FromSubscriptionFilter converts a SubscriptionsAPIFilter to the corresponding
+// DialectedFilter based on the property set in the SubscriptionsAPIFilter. If
+// the SubscriptionsAPIFilter has multiple dialects set, they will be wrapped inside
+// a Filter of the type DialectedFilter_All
+//
+// E.g a SubscriptionsAPIFilter with the Exact field set will be converted to a DialectedFilter
+// which Filter is of type DialectedFilter_Exact.
+func FromSubscriptionFilter(f v1.SubscriptionsAPIFilter) *DialectedFilter {
+	filters := make([]*DialectedFilter, 0)
+	if len(f.All) > 0 {
+		filters = append(filters, newAllFilter(f.All))
+	}
+	if len(f.Any) > 0 {
+		filters = append(filters, newAnyFilter(f.All))
+	}
+	if f.Not != nil {
+		filters = append(filters, newNotFilter(*f.Not))
+	}
+	if f.Exact != nil {
+		filters = append(filters, newExactFilter(f))
+	}
+	if f.Prefix != nil {
+		filters = append(filters, newPrefixFilter(f))
+	}
+	if f.Suffix != nil {
+		filters = append(filters, newSuffixFilter(f))
+	}
+	if f.CESQL != "" {
+		filters = append(filters, newCESQLFilter(f))
+	}
+	switch {
+	case len(filters) == 1:
+		return filters[0]
+	case len(filters) > 1:
+		return &DialectedFilter{
+			Filter: &DialectedFilter_All{
+				All: &All{
+					Filters: filters,
+				},
+			},
+		}
+	}
+	return &DialectedFilter{}
+}
diff --git a/control-plane/pkg/reconciler/trigger/controller.go b/control-plane/pkg/reconciler/trigger/controller.go
index 32a4b4775..851905f84 100644
--- a/control-plane/pkg/reconciler/trigger/controller.go
+++ b/control-plane/pkg/reconciler/trigger/controller.go
@@ -33,6 +33,7 @@ import (
 
 	apiseventing "knative.dev/eventing/pkg/apis/eventing"
 	eventing "knative.dev/eventing/pkg/apis/eventing/v1"
+	"knative.dev/eventing/pkg/apis/feature"
 	eventingclient "knative.dev/eventing/pkg/client/injection/client"
 	brokerinformer "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker"
 	triggerinformer "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/trigger"
@@ -50,7 +51,7 @@ const (
 	FinalizerName = "kafka.triggers.eventing.knative.dev"
 )
 
-func NewController(ctx context.Context, _ configmap.Watcher, configs *config.Env) *controller.Impl {
+func NewController(ctx context.Context, watcher configmap.Watcher, configs *config.Env) *controller.Impl {
 
 	logger := logging.FromContext(ctx).Desugar()
 
@@ -74,6 +75,7 @@ func NewController(ctx context.Context, _ configmap.Watcher, configs *config.Env
 		BrokerLister:   brokerInformer.Lister(),
 		EventingClient: eventingclient.Get(ctx),
 		Env:            configs,
+		Flags:          feature.Flags{},
 	}
 
 	impl := triggerreconciler.NewImpl(ctx, reconciler, func(impl *controller.Impl) controller.Options {
@@ -85,6 +87,22 @@ func NewController(ctx context.Context, _ configmap.Watcher, configs *config.Env
 		}
 	})
 
+	featureStore := feature.NewStore(
+		logging.FromContext(ctx).Named("feature-config-eventing-store"),
+		func(name string, value interface{}) {
+			flags, ok := value.(feature.Flags)
+			if !ok {
+				logger.Warn("Features ConfigMap " + name + " updated but we didn't get expected flags. Skipping updating cached features")
+			}
+			logger.Debug("Features ConfigMap " + name + " updated. Updating cached features.")
+			reconciler.FlagsLock.Lock()
+			defer reconciler.FlagsLock.Unlock()
+			reconciler.Flags = flags
+			impl.GlobalResync(triggerInformer.Informer())
+		},
+	)
+	featureStore.WatchConfigs(watcher)
+
 	reconciler.Resolver = resolver.NewURIResolverFromTracker(ctx, impl.Tracker)
 
 	triggerInformer.Informer().AddEventHandler(cache.FilteringResourceEventHandler{
diff --git a/control-plane/pkg/reconciler/trigger/trigger.go b/control-plane/pkg/reconciler/trigger/trigger.go
index 7d264c2ae..009517784 100644
--- a/control-plane/pkg/reconciler/trigger/trigger.go
+++ b/control-plane/pkg/reconciler/trigger/trigger.go
@@ -20,24 +20,26 @@ import (
 	"context"
 	"fmt"
 	"strings"
+	"sync"
 
 	"go.uber.org/zap"
 	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/client-go/util/retry"
-	eventing "knative.dev/eventing/pkg/apis/eventing/v1"
-	eventingclientset "knative.dev/eventing/pkg/client/clientset/versioned"
-	eventinglisters "knative.dev/eventing/pkg/client/listers/eventing/v1"
 	"knative.dev/pkg/controller"
 	"knative.dev/pkg/reconciler"
 	"knative.dev/pkg/resolver"
 
-	"knative.dev/eventing-kafka-broker/control-plane/pkg/contract"
-	"knative.dev/eventing-kafka-broker/control-plane/pkg/kafka"
+	eventing "knative.dev/eventing/pkg/apis/eventing/v1"
+	"knative.dev/eventing/pkg/apis/feature"
+	eventingclientset "knative.dev/eventing/pkg/client/clientset/versioned"
+	eventinglisters "knative.dev/eventing/pkg/client/listers/eventing/v1"
 
 	internals "knative.dev/eventing-kafka-broker/control-plane/pkg/apis/internals/kafka/eventing"
 	"knative.dev/eventing-kafka-broker/control-plane/pkg/config"
+	"knative.dev/eventing-kafka-broker/control-plane/pkg/contract"
 	coreconfig "knative.dev/eventing-kafka-broker/control-plane/pkg/core/config"
+	"knative.dev/eventing-kafka-broker/control-plane/pkg/kafka"
 	kafkalogging "knative.dev/eventing-kafka-broker/control-plane/pkg/logging"
 	"knative.dev/eventing-kafka-broker/control-plane/pkg/reconciler/base"
 )
@@ -53,7 +55,9 @@ type Reconciler struct {
 	EventingClient eventingclientset.Interface
 	Resolver       *resolver.URIResolver
 
-	Env *config.Env
+	Env       *config.Env
+	Flags     feature.Flags
+	FlagsLock sync.RWMutex
 }
 
 func (r *Reconciler) ReconcileKind(ctx context.Context, trigger *eventing.Trigger) reconciler.Event {
@@ -282,10 +286,23 @@ func (r *Reconciler) reconcileTriggerEgress(ctx context.Context, broker *eventin
 			Name:      trigger.GetName(),
 		},
 	}
-
-	if trigger.Spec.Filter != nil && trigger.Spec.Filter.Attributes != nil {
-		egress.Filter = &contract.Filter{
-			Attributes: trigger.Spec.Filter.Attributes,
+	newFiltersEnabled := func() bool {
+		r.FlagsLock.RLock()
+		defer r.FlagsLock.RUnlock()
+		return r.Flags.IsEnabled(feature.NewTriggerFilters)
+	}()
+
+	if newFiltersEnabled && len(trigger.Spec.Filters) > 0 {
+		dialectedFilters := make([]*contract.DialectedFilter, 0, len(trigger.Spec.Filters))
+		for _, f := range trigger.Spec.Filters {
+			dialectedFilters = append(dialectedFilters, contract.FromSubscriptionFilter(f))
+		}
+		egress.DialectedFilter = dialectedFilters
+	} else {
+		if trigger.Spec.Filter != nil && trigger.Spec.Filter.Attributes != nil {
+			egress.Filter = &contract.Filter{
+				Attributes: trigger.Spec.Filter.Attributes,
+			}
 		}
 	}
 
diff --git a/data-plane/contract/src/main/java/dev/knative/eventing/kafka/broker/contract/DataPlaneContract.java b/data-plane/contract/src/main/java/dev/knative/eventing/kafka/broker/contract/DataPlaneContract.java
index d4022b837..30eb88b9e 100644
--- a/data-plane/contract/src/main/java/dev/knative/eventing/kafka/broker/contract/DataPlaneContract.java
+++ b/data-plane/contract/src/main/java/dev/knative/eventing/kafka/broker/contract/DataPlaneContract.java
@@ -1939,28 +1939,38 @@ public final class DataPlaneContract {
       com.google.protobuf.MessageOrBuilder {
 
     /**
-     * <code>string attribute = 1;</code>
-     * @return The attribute.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
-    java.lang.String getAttribute();
+    int getAttributesCount();
     /**
-     * <code>string attribute = 1;</code>
-     * @return The bytes for attribute.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
-    com.google.protobuf.ByteString
-        getAttributeBytes();
-
+    boolean containsAttributes(
+        java.lang.String key);
     /**
-     * <code>string prefix = 2;</code>
-     * @return The prefix.
+     * Use {@link #getAttributesMap()} instead.
      */
-    java.lang.String getPrefix();
+    @java.lang.Deprecated
+    java.util.Map<java.lang.String, java.lang.String>
+    getAttributes();
     /**
-     * <code>string prefix = 2;</code>
-     * @return The bytes for prefix.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
-    com.google.protobuf.ByteString
-        getPrefixBytes();
+    java.util.Map<java.lang.String, java.lang.String>
+    getAttributesMap();
+    /**
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
+     */
+
+    java.lang.String getAttributesOrDefault(
+        java.lang.String key,
+        java.lang.String defaultValue);
+    /**
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
+     */
+
+    java.lang.String getAttributesOrThrow(
+        java.lang.String key);
   }
   /**
    * Protobuf type {@code Prefix}
@@ -1975,8 +1985,6 @@ public final class DataPlaneContract {
       super(builder);
     }
     private Prefix() {
-      attribute_ = "";
-      prefix_ = "";
     }
 
     @java.lang.Override
@@ -1999,6 +2007,7 @@ public final class DataPlaneContract {
       if (extensionRegistry == null) {
         throw new java.lang.NullPointerException();
       }
+      int mutable_bitField0_ = 0;
       com.google.protobuf.UnknownFieldSet.Builder unknownFields =
           com.google.protobuf.UnknownFieldSet.newBuilder();
       try {
@@ -2010,15 +2019,16 @@ public final class DataPlaneContract {
               done = true;
               break;
             case 10: {
-              java.lang.String s = input.readStringRequireUtf8();
-
-              attribute_ = s;
-              break;
-            }
-            case 18: {
-              java.lang.String s = input.readStringRequireUtf8();
-
-              prefix_ = s;
+              if (!((mutable_bitField0_ & 0x00000001) != 0)) {
+                attributes_ = com.google.protobuf.MapField.newMapField(
+                    AttributesDefaultEntryHolder.defaultEntry);
+                mutable_bitField0_ |= 0x00000001;
+              }
+              com.google.protobuf.MapEntry<java.lang.String, java.lang.String>
+              attributes__ = input.readMessage(
+                  AttributesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry);
+              attributes_.getMutableMap().put(
+                  attributes__.getKey(), attributes__.getValue());
               break;
             }
             default: {
@@ -2045,6 +2055,18 @@ public final class DataPlaneContract {
       return dev.knative.eventing.kafka.broker.contract.DataPlaneContract.internal_static_Prefix_descriptor;
     }
 
+    @SuppressWarnings({"rawtypes"})
+    @java.lang.Override
+    protected com.google.protobuf.MapField internalGetMapField(
+        int number) {
+      switch (number) {
+        case 1:
+          return internalGetAttributes();
+        default:
+          throw new RuntimeException(
+              "Invalid map field number: " + number);
+      }
+    }
     @java.lang.Override
     protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
         internalGetFieldAccessorTable() {
@@ -2053,80 +2075,85 @@ public final class DataPlaneContract {
               dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Prefix.class, dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Prefix.Builder.class);
     }
 
-    public static final int ATTRIBUTE_FIELD_NUMBER = 1;
-    private volatile java.lang.Object attribute_;
+    public static final int ATTRIBUTES_FIELD_NUMBER = 1;
+    private static final class AttributesDefaultEntryHolder {
+      static final com.google.protobuf.MapEntry<
+          java.lang.String, java.lang.String> defaultEntry =
+              com.google.protobuf.MapEntry
+              .<java.lang.String, java.lang.String>newDefaultInstance(
+                  dev.knative.eventing.kafka.broker.contract.DataPlaneContract.internal_static_Prefix_AttributesEntry_descriptor, 
+                  com.google.protobuf.WireFormat.FieldType.STRING,
+                  "",
+                  com.google.protobuf.WireFormat.FieldType.STRING,
+                  "");
+    }
+    private com.google.protobuf.MapField<
+        java.lang.String, java.lang.String> attributes_;
+    private com.google.protobuf.MapField<java.lang.String, java.lang.String>
+    internalGetAttributes() {
+      if (attributes_ == null) {
+        return com.google.protobuf.MapField.emptyMapField(
+            AttributesDefaultEntryHolder.defaultEntry);
+      }
+      return attributes_;
+    }
+
+    public int getAttributesCount() {
+      return internalGetAttributes().getMap().size();
+    }
     /**
-     * <code>string attribute = 1;</code>
-     * @return The attribute.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
+
     @java.lang.Override
-    public java.lang.String getAttribute() {
-      java.lang.Object ref = attribute_;
-      if (ref instanceof java.lang.String) {
-        return (java.lang.String) ref;
-      } else {
-        com.google.protobuf.ByteString bs = 
-            (com.google.protobuf.ByteString) ref;
-        java.lang.String s = bs.toStringUtf8();
-        attribute_ = s;
-        return s;
-      }
+    public boolean containsAttributes(
+        java.lang.String key) {
+      if (key == null) { throw new java.lang.NullPointerException(); }
+      return internalGetAttributes().getMap().containsKey(key);
     }
     /**
-     * <code>string attribute = 1;</code>
-     * @return The bytes for attribute.
+     * Use {@link #getAttributesMap()} instead.
      */
     @java.lang.Override
-    public com.google.protobuf.ByteString
-        getAttributeBytes() {
-      java.lang.Object ref = attribute_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        attribute_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
+    @java.lang.Deprecated
+    public java.util.Map<java.lang.String, java.lang.String> getAttributes() {
+      return getAttributesMap();
     }
+    /**
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
+     */
+    @java.lang.Override
 
-    public static final int PREFIX_FIELD_NUMBER = 2;
-    private volatile java.lang.Object prefix_;
+    public java.util.Map<java.lang.String, java.lang.String> getAttributesMap() {
+      return internalGetAttributes().getMap();
+    }
     /**
-     * <code>string prefix = 2;</code>
-     * @return The prefix.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
     @java.lang.Override
-    public java.lang.String getPrefix() {
-      java.lang.Object ref = prefix_;
-      if (ref instanceof java.lang.String) {
-        return (java.lang.String) ref;
-      } else {
-        com.google.protobuf.ByteString bs = 
-            (com.google.protobuf.ByteString) ref;
-        java.lang.String s = bs.toStringUtf8();
-        prefix_ = s;
-        return s;
-      }
+
+    public java.lang.String getAttributesOrDefault(
+        java.lang.String key,
+        java.lang.String defaultValue) {
+      if (key == null) { throw new java.lang.NullPointerException(); }
+      java.util.Map<java.lang.String, java.lang.String> map =
+          internalGetAttributes().getMap();
+      return map.containsKey(key) ? map.get(key) : defaultValue;
     }
     /**
-     * <code>string prefix = 2;</code>
-     * @return The bytes for prefix.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
     @java.lang.Override
-    public com.google.protobuf.ByteString
-        getPrefixBytes() {
-      java.lang.Object ref = prefix_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        prefix_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
+
+    public java.lang.String getAttributesOrThrow(
+        java.lang.String key) {
+      if (key == null) { throw new java.lang.NullPointerException(); }
+      java.util.Map<java.lang.String, java.lang.String> map =
+          internalGetAttributes().getMap();
+      if (!map.containsKey(key)) {
+        throw new java.lang.IllegalArgumentException();
       }
+      return map.get(key);
     }
 
     private byte memoizedIsInitialized = -1;
@@ -2143,12 +2170,12 @@ public final class DataPlaneContract {
     @java.lang.Override
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
-      if (!getAttributeBytes().isEmpty()) {
-        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, attribute_);
-      }
-      if (!getPrefixBytes().isEmpty()) {
-        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, prefix_);
-      }
+      com.google.protobuf.GeneratedMessageV3
+        .serializeStringMapTo(
+          output,
+          internalGetAttributes(),
+          AttributesDefaultEntryHolder.defaultEntry,
+          1);
       unknownFields.writeTo(output);
     }
 
@@ -2158,11 +2185,15 @@ public final class DataPlaneContract {
       if (size != -1) return size;
 
       size = 0;
-      if (!getAttributeBytes().isEmpty()) {
-        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, attribute_);
-      }
-      if (!getPrefixBytes().isEmpty()) {
-        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, prefix_);
+      for (java.util.Map.Entry<java.lang.String, java.lang.String> entry
+           : internalGetAttributes().getMap().entrySet()) {
+        com.google.protobuf.MapEntry<java.lang.String, java.lang.String>
+        attributes__ = AttributesDefaultEntryHolder.defaultEntry.newBuilderForType()
+            .setKey(entry.getKey())
+            .setValue(entry.getValue())
+            .build();
+        size += com.google.protobuf.CodedOutputStream
+            .computeMessageSize(1, attributes__);
       }
       size += unknownFields.getSerializedSize();
       memoizedSize = size;
@@ -2179,10 +2210,8 @@ public final class DataPlaneContract {
       }
       dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Prefix other = (dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Prefix) obj;
 
-      if (!getAttribute()
-          .equals(other.getAttribute())) return false;
-      if (!getPrefix()
-          .equals(other.getPrefix())) return false;
+      if (!internalGetAttributes().equals(
+          other.internalGetAttributes())) return false;
       if (!unknownFields.equals(other.unknownFields)) return false;
       return true;
     }
@@ -2194,10 +2223,10 @@ public final class DataPlaneContract {
       }
       int hash = 41;
       hash = (19 * hash) + getDescriptor().hashCode();
-      hash = (37 * hash) + ATTRIBUTE_FIELD_NUMBER;
-      hash = (53 * hash) + getAttribute().hashCode();
-      hash = (37 * hash) + PREFIX_FIELD_NUMBER;
-      hash = (53 * hash) + getPrefix().hashCode();
+      if (!internalGetAttributes().getMap().isEmpty()) {
+        hash = (37 * hash) + ATTRIBUTES_FIELD_NUMBER;
+        hash = (53 * hash) + internalGetAttributes().hashCode();
+      }
       hash = (29 * hash) + unknownFields.hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -2305,6 +2334,28 @@ public final class DataPlaneContract {
         return dev.knative.eventing.kafka.broker.contract.DataPlaneContract.internal_static_Prefix_descriptor;
       }
 
+      @SuppressWarnings({"rawtypes"})
+      protected com.google.protobuf.MapField internalGetMapField(
+          int number) {
+        switch (number) {
+          case 1:
+            return internalGetAttributes();
+          default:
+            throw new RuntimeException(
+                "Invalid map field number: " + number);
+        }
+      }
+      @SuppressWarnings({"rawtypes"})
+      protected com.google.protobuf.MapField internalGetMutableMapField(
+          int number) {
+        switch (number) {
+          case 1:
+            return internalGetMutableAttributes();
+          default:
+            throw new RuntimeException(
+                "Invalid map field number: " + number);
+        }
+      }
       @java.lang.Override
       protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
           internalGetFieldAccessorTable() {
@@ -2331,10 +2382,7 @@ public final class DataPlaneContract {
       @java.lang.Override
       public Builder clear() {
         super.clear();
-        attribute_ = "";
-
-        prefix_ = "";
-
+        internalGetMutableAttributes().clear();
         return this;
       }
 
@@ -2361,8 +2409,9 @@ public final class DataPlaneContract {
       @java.lang.Override
       public dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Prefix buildPartial() {
         dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Prefix result = new dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Prefix(this);
-        result.attribute_ = attribute_;
-        result.prefix_ = prefix_;
+        int from_bitField0_ = bitField0_;
+        result.attributes_ = internalGetAttributes();
+        result.attributes_.makeImmutable();
         onBuilt();
         return result;
       }
@@ -2411,14 +2460,8 @@ public final class DataPlaneContract {
 
       public Builder mergeFrom(dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Prefix other) {
         if (other == dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Prefix.getDefaultInstance()) return this;
-        if (!other.getAttribute().isEmpty()) {
-          attribute_ = other.attribute_;
-          onChanged();
-        }
-        if (!other.getPrefix().isEmpty()) {
-          prefix_ = other.prefix_;
-          onChanged();
-        }
+        internalGetMutableAttributes().mergeFrom(
+            other.internalGetAttributes());
         this.mergeUnknownFields(other.unknownFields);
         onChanged();
         return this;
@@ -2447,156 +2490,133 @@ public final class DataPlaneContract {
         }
         return this;
       }
+      private int bitField0_;
 
-      private java.lang.Object attribute_ = "";
-      /**
-       * <code>string attribute = 1;</code>
-       * @return The attribute.
-       */
-      public java.lang.String getAttribute() {
-        java.lang.Object ref = attribute_;
-        if (!(ref instanceof java.lang.String)) {
-          com.google.protobuf.ByteString bs =
-              (com.google.protobuf.ByteString) ref;
-          java.lang.String s = bs.toStringUtf8();
-          attribute_ = s;
-          return s;
-        } else {
-          return (java.lang.String) ref;
+      private com.google.protobuf.MapField<
+          java.lang.String, java.lang.String> attributes_;
+      private com.google.protobuf.MapField<java.lang.String, java.lang.String>
+      internalGetAttributes() {
+        if (attributes_ == null) {
+          return com.google.protobuf.MapField.emptyMapField(
+              AttributesDefaultEntryHolder.defaultEntry);
         }
+        return attributes_;
       }
-      /**
-       * <code>string attribute = 1;</code>
-       * @return The bytes for attribute.
-       */
-      public com.google.protobuf.ByteString
-          getAttributeBytes() {
-        java.lang.Object ref = attribute_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          attribute_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
+      private com.google.protobuf.MapField<java.lang.String, java.lang.String>
+      internalGetMutableAttributes() {
+        onChanged();;
+        if (attributes_ == null) {
+          attributes_ = com.google.protobuf.MapField.newMapField(
+              AttributesDefaultEntryHolder.defaultEntry);
+        }
+        if (!attributes_.isMutable()) {
+          attributes_ = attributes_.copy();
         }
+        return attributes_;
+      }
+
+      public int getAttributesCount() {
+        return internalGetAttributes().getMap().size();
       }
       /**
-       * <code>string attribute = 1;</code>
-       * @param value The attribute to set.
-       * @return This builder for chaining.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public Builder setAttribute(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  
-        attribute_ = value;
-        onChanged();
-        return this;
+
+      @java.lang.Override
+      public boolean containsAttributes(
+          java.lang.String key) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        return internalGetAttributes().getMap().containsKey(key);
       }
       /**
-       * <code>string attribute = 1;</code>
-       * @return This builder for chaining.
+       * Use {@link #getAttributesMap()} instead.
        */
-      public Builder clearAttribute() {
-        
-        attribute_ = getDefaultInstance().getAttribute();
-        onChanged();
-        return this;
+      @java.lang.Override
+      @java.lang.Deprecated
+      public java.util.Map<java.lang.String, java.lang.String> getAttributes() {
+        return getAttributesMap();
       }
       /**
-       * <code>string attribute = 1;</code>
-       * @param value The bytes for attribute to set.
-       * @return This builder for chaining.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public Builder setAttributeBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  checkByteStringIsUtf8(value);
-        
-        attribute_ = value;
-        onChanged();
-        return this;
-      }
+      @java.lang.Override
 
-      private java.lang.Object prefix_ = "";
+      public java.util.Map<java.lang.String, java.lang.String> getAttributesMap() {
+        return internalGetAttributes().getMap();
+      }
       /**
-       * <code>string prefix = 2;</code>
-       * @return The prefix.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public java.lang.String getPrefix() {
-        java.lang.Object ref = prefix_;
-        if (!(ref instanceof java.lang.String)) {
-          com.google.protobuf.ByteString bs =
-              (com.google.protobuf.ByteString) ref;
-          java.lang.String s = bs.toStringUtf8();
-          prefix_ = s;
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
+      @java.lang.Override
+
+      public java.lang.String getAttributesOrDefault(
+          java.lang.String key,
+          java.lang.String defaultValue) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        java.util.Map<java.lang.String, java.lang.String> map =
+            internalGetAttributes().getMap();
+        return map.containsKey(key) ? map.get(key) : defaultValue;
       }
       /**
-       * <code>string prefix = 2;</code>
-       * @return The bytes for prefix.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public com.google.protobuf.ByteString
-          getPrefixBytes() {
-        java.lang.Object ref = prefix_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          prefix_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
+      @java.lang.Override
+
+      public java.lang.String getAttributesOrThrow(
+          java.lang.String key) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        java.util.Map<java.lang.String, java.lang.String> map =
+            internalGetAttributes().getMap();
+        if (!map.containsKey(key)) {
+          throw new java.lang.IllegalArgumentException();
         }
+        return map.get(key);
+      }
+
+      public Builder clearAttributes() {
+        internalGetMutableAttributes().getMutableMap()
+            .clear();
+        return this;
       }
       /**
-       * <code>string prefix = 2;</code>
-       * @param value The prefix to set.
-       * @return This builder for chaining.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public Builder setPrefix(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  
-        prefix_ = value;
-        onChanged();
+
+      public Builder removeAttributes(
+          java.lang.String key) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        internalGetMutableAttributes().getMutableMap()
+            .remove(key);
         return this;
       }
       /**
-       * <code>string prefix = 2;</code>
-       * @return This builder for chaining.
+       * Use alternate mutation accessors instead.
        */
-      public Builder clearPrefix() {
-        
-        prefix_ = getDefaultInstance().getPrefix();
-        onChanged();
+      @java.lang.Deprecated
+      public java.util.Map<java.lang.String, java.lang.String>
+      getMutableAttributes() {
+        return internalGetMutableAttributes().getMutableMap();
+      }
+      /**
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
+       */
+      public Builder putAttributes(
+          java.lang.String key,
+          java.lang.String value) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        if (value == null) { throw new java.lang.NullPointerException(); }
+        internalGetMutableAttributes().getMutableMap()
+            .put(key, value);
         return this;
       }
       /**
-       * <code>string prefix = 2;</code>
-       * @param value The bytes for prefix to set.
-       * @return This builder for chaining.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public Builder setPrefixBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  checkByteStringIsUtf8(value);
-        
-        prefix_ = value;
-        onChanged();
+
+      public Builder putAllAttributes(
+          java.util.Map<java.lang.String, java.lang.String> values) {
+        internalGetMutableAttributes().getMutableMap()
+            .putAll(values);
         return this;
       }
       @java.lang.Override
@@ -2657,28 +2677,38 @@ public final class DataPlaneContract {
       com.google.protobuf.MessageOrBuilder {
 
     /**
-     * <code>string attribute = 1;</code>
-     * @return The attribute.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
-    java.lang.String getAttribute();
+    int getAttributesCount();
     /**
-     * <code>string attribute = 1;</code>
-     * @return The bytes for attribute.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
-    com.google.protobuf.ByteString
-        getAttributeBytes();
-
+    boolean containsAttributes(
+        java.lang.String key);
     /**
-     * <code>string suffix = 2;</code>
-     * @return The suffix.
+     * Use {@link #getAttributesMap()} instead.
      */
-    java.lang.String getSuffix();
+    @java.lang.Deprecated
+    java.util.Map<java.lang.String, java.lang.String>
+    getAttributes();
     /**
-     * <code>string suffix = 2;</code>
-     * @return The bytes for suffix.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
-    com.google.protobuf.ByteString
-        getSuffixBytes();
+    java.util.Map<java.lang.String, java.lang.String>
+    getAttributesMap();
+    /**
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
+     */
+
+    java.lang.String getAttributesOrDefault(
+        java.lang.String key,
+        java.lang.String defaultValue);
+    /**
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
+     */
+
+    java.lang.String getAttributesOrThrow(
+        java.lang.String key);
   }
   /**
    * Protobuf type {@code Suffix}
@@ -2693,8 +2723,6 @@ public final class DataPlaneContract {
       super(builder);
     }
     private Suffix() {
-      attribute_ = "";
-      suffix_ = "";
     }
 
     @java.lang.Override
@@ -2717,6 +2745,7 @@ public final class DataPlaneContract {
       if (extensionRegistry == null) {
         throw new java.lang.NullPointerException();
       }
+      int mutable_bitField0_ = 0;
       com.google.protobuf.UnknownFieldSet.Builder unknownFields =
           com.google.protobuf.UnknownFieldSet.newBuilder();
       try {
@@ -2728,15 +2757,16 @@ public final class DataPlaneContract {
               done = true;
               break;
             case 10: {
-              java.lang.String s = input.readStringRequireUtf8();
-
-              attribute_ = s;
-              break;
-            }
-            case 18: {
-              java.lang.String s = input.readStringRequireUtf8();
-
-              suffix_ = s;
+              if (!((mutable_bitField0_ & 0x00000001) != 0)) {
+                attributes_ = com.google.protobuf.MapField.newMapField(
+                    AttributesDefaultEntryHolder.defaultEntry);
+                mutable_bitField0_ |= 0x00000001;
+              }
+              com.google.protobuf.MapEntry<java.lang.String, java.lang.String>
+              attributes__ = input.readMessage(
+                  AttributesDefaultEntryHolder.defaultEntry.getParserForType(), extensionRegistry);
+              attributes_.getMutableMap().put(
+                  attributes__.getKey(), attributes__.getValue());
               break;
             }
             default: {
@@ -2763,6 +2793,18 @@ public final class DataPlaneContract {
       return dev.knative.eventing.kafka.broker.contract.DataPlaneContract.internal_static_Suffix_descriptor;
     }
 
+    @SuppressWarnings({"rawtypes"})
+    @java.lang.Override
+    protected com.google.protobuf.MapField internalGetMapField(
+        int number) {
+      switch (number) {
+        case 1:
+          return internalGetAttributes();
+        default:
+          throw new RuntimeException(
+              "Invalid map field number: " + number);
+      }
+    }
     @java.lang.Override
     protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
         internalGetFieldAccessorTable() {
@@ -2771,80 +2813,85 @@ public final class DataPlaneContract {
               dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Suffix.class, dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Suffix.Builder.class);
     }
 
-    public static final int ATTRIBUTE_FIELD_NUMBER = 1;
-    private volatile java.lang.Object attribute_;
+    public static final int ATTRIBUTES_FIELD_NUMBER = 1;
+    private static final class AttributesDefaultEntryHolder {
+      static final com.google.protobuf.MapEntry<
+          java.lang.String, java.lang.String> defaultEntry =
+              com.google.protobuf.MapEntry
+              .<java.lang.String, java.lang.String>newDefaultInstance(
+                  dev.knative.eventing.kafka.broker.contract.DataPlaneContract.internal_static_Suffix_AttributesEntry_descriptor, 
+                  com.google.protobuf.WireFormat.FieldType.STRING,
+                  "",
+                  com.google.protobuf.WireFormat.FieldType.STRING,
+                  "");
+    }
+    private com.google.protobuf.MapField<
+        java.lang.String, java.lang.String> attributes_;
+    private com.google.protobuf.MapField<java.lang.String, java.lang.String>
+    internalGetAttributes() {
+      if (attributes_ == null) {
+        return com.google.protobuf.MapField.emptyMapField(
+            AttributesDefaultEntryHolder.defaultEntry);
+      }
+      return attributes_;
+    }
+
+    public int getAttributesCount() {
+      return internalGetAttributes().getMap().size();
+    }
     /**
-     * <code>string attribute = 1;</code>
-     * @return The attribute.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
+
     @java.lang.Override
-    public java.lang.String getAttribute() {
-      java.lang.Object ref = attribute_;
-      if (ref instanceof java.lang.String) {
-        return (java.lang.String) ref;
-      } else {
-        com.google.protobuf.ByteString bs = 
-            (com.google.protobuf.ByteString) ref;
-        java.lang.String s = bs.toStringUtf8();
-        attribute_ = s;
-        return s;
-      }
+    public boolean containsAttributes(
+        java.lang.String key) {
+      if (key == null) { throw new java.lang.NullPointerException(); }
+      return internalGetAttributes().getMap().containsKey(key);
     }
     /**
-     * <code>string attribute = 1;</code>
-     * @return The bytes for attribute.
+     * Use {@link #getAttributesMap()} instead.
      */
     @java.lang.Override
-    public com.google.protobuf.ByteString
-        getAttributeBytes() {
-      java.lang.Object ref = attribute_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        attribute_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
-      }
+    @java.lang.Deprecated
+    public java.util.Map<java.lang.String, java.lang.String> getAttributes() {
+      return getAttributesMap();
     }
-
-    public static final int SUFFIX_FIELD_NUMBER = 2;
-    private volatile java.lang.Object suffix_;
     /**
-     * <code>string suffix = 2;</code>
-     * @return The suffix.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
     @java.lang.Override
-    public java.lang.String getSuffix() {
-      java.lang.Object ref = suffix_;
-      if (ref instanceof java.lang.String) {
-        return (java.lang.String) ref;
-      } else {
-        com.google.protobuf.ByteString bs = 
-            (com.google.protobuf.ByteString) ref;
-        java.lang.String s = bs.toStringUtf8();
-        suffix_ = s;
-        return s;
-      }
+
+    public java.util.Map<java.lang.String, java.lang.String> getAttributesMap() {
+      return internalGetAttributes().getMap();
     }
     /**
-     * <code>string suffix = 2;</code>
-     * @return The bytes for suffix.
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
      */
     @java.lang.Override
-    public com.google.protobuf.ByteString
-        getSuffixBytes() {
-      java.lang.Object ref = suffix_;
-      if (ref instanceof java.lang.String) {
-        com.google.protobuf.ByteString b = 
-            com.google.protobuf.ByteString.copyFromUtf8(
-                (java.lang.String) ref);
-        suffix_ = b;
-        return b;
-      } else {
-        return (com.google.protobuf.ByteString) ref;
+
+    public java.lang.String getAttributesOrDefault(
+        java.lang.String key,
+        java.lang.String defaultValue) {
+      if (key == null) { throw new java.lang.NullPointerException(); }
+      java.util.Map<java.lang.String, java.lang.String> map =
+          internalGetAttributes().getMap();
+      return map.containsKey(key) ? map.get(key) : defaultValue;
+    }
+    /**
+     * <code>map&lt;string, string&gt; attributes = 1;</code>
+     */
+    @java.lang.Override
+
+    public java.lang.String getAttributesOrThrow(
+        java.lang.String key) {
+      if (key == null) { throw new java.lang.NullPointerException(); }
+      java.util.Map<java.lang.String, java.lang.String> map =
+          internalGetAttributes().getMap();
+      if (!map.containsKey(key)) {
+        throw new java.lang.IllegalArgumentException();
       }
+      return map.get(key);
     }
 
     private byte memoizedIsInitialized = -1;
@@ -2861,12 +2908,12 @@ public final class DataPlaneContract {
     @java.lang.Override
     public void writeTo(com.google.protobuf.CodedOutputStream output)
                         throws java.io.IOException {
-      if (!getAttributeBytes().isEmpty()) {
-        com.google.protobuf.GeneratedMessageV3.writeString(output, 1, attribute_);
-      }
-      if (!getSuffixBytes().isEmpty()) {
-        com.google.protobuf.GeneratedMessageV3.writeString(output, 2, suffix_);
-      }
+      com.google.protobuf.GeneratedMessageV3
+        .serializeStringMapTo(
+          output,
+          internalGetAttributes(),
+          AttributesDefaultEntryHolder.defaultEntry,
+          1);
       unknownFields.writeTo(output);
     }
 
@@ -2876,11 +2923,15 @@ public final class DataPlaneContract {
       if (size != -1) return size;
 
       size = 0;
-      if (!getAttributeBytes().isEmpty()) {
-        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, attribute_);
-      }
-      if (!getSuffixBytes().isEmpty()) {
-        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, suffix_);
+      for (java.util.Map.Entry<java.lang.String, java.lang.String> entry
+           : internalGetAttributes().getMap().entrySet()) {
+        com.google.protobuf.MapEntry<java.lang.String, java.lang.String>
+        attributes__ = AttributesDefaultEntryHolder.defaultEntry.newBuilderForType()
+            .setKey(entry.getKey())
+            .setValue(entry.getValue())
+            .build();
+        size += com.google.protobuf.CodedOutputStream
+            .computeMessageSize(1, attributes__);
       }
       size += unknownFields.getSerializedSize();
       memoizedSize = size;
@@ -2897,10 +2948,8 @@ public final class DataPlaneContract {
       }
       dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Suffix other = (dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Suffix) obj;
 
-      if (!getAttribute()
-          .equals(other.getAttribute())) return false;
-      if (!getSuffix()
-          .equals(other.getSuffix())) return false;
+      if (!internalGetAttributes().equals(
+          other.internalGetAttributes())) return false;
       if (!unknownFields.equals(other.unknownFields)) return false;
       return true;
     }
@@ -2912,10 +2961,10 @@ public final class DataPlaneContract {
       }
       int hash = 41;
       hash = (19 * hash) + getDescriptor().hashCode();
-      hash = (37 * hash) + ATTRIBUTE_FIELD_NUMBER;
-      hash = (53 * hash) + getAttribute().hashCode();
-      hash = (37 * hash) + SUFFIX_FIELD_NUMBER;
-      hash = (53 * hash) + getSuffix().hashCode();
+      if (!internalGetAttributes().getMap().isEmpty()) {
+        hash = (37 * hash) + ATTRIBUTES_FIELD_NUMBER;
+        hash = (53 * hash) + internalGetAttributes().hashCode();
+      }
       hash = (29 * hash) + unknownFields.hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -3023,6 +3072,28 @@ public final class DataPlaneContract {
         return dev.knative.eventing.kafka.broker.contract.DataPlaneContract.internal_static_Suffix_descriptor;
       }
 
+      @SuppressWarnings({"rawtypes"})
+      protected com.google.protobuf.MapField internalGetMapField(
+          int number) {
+        switch (number) {
+          case 1:
+            return internalGetAttributes();
+          default:
+            throw new RuntimeException(
+                "Invalid map field number: " + number);
+        }
+      }
+      @SuppressWarnings({"rawtypes"})
+      protected com.google.protobuf.MapField internalGetMutableMapField(
+          int number) {
+        switch (number) {
+          case 1:
+            return internalGetMutableAttributes();
+          default:
+            throw new RuntimeException(
+                "Invalid map field number: " + number);
+        }
+      }
       @java.lang.Override
       protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
           internalGetFieldAccessorTable() {
@@ -3049,10 +3120,7 @@ public final class DataPlaneContract {
       @java.lang.Override
       public Builder clear() {
         super.clear();
-        attribute_ = "";
-
-        suffix_ = "";
-
+        internalGetMutableAttributes().clear();
         return this;
       }
 
@@ -3079,8 +3147,9 @@ public final class DataPlaneContract {
       @java.lang.Override
       public dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Suffix buildPartial() {
         dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Suffix result = new dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Suffix(this);
-        result.attribute_ = attribute_;
-        result.suffix_ = suffix_;
+        int from_bitField0_ = bitField0_;
+        result.attributes_ = internalGetAttributes();
+        result.attributes_.makeImmutable();
         onBuilt();
         return result;
       }
@@ -3129,14 +3198,8 @@ public final class DataPlaneContract {
 
       public Builder mergeFrom(dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Suffix other) {
         if (other == dev.knative.eventing.kafka.broker.contract.DataPlaneContract.Suffix.getDefaultInstance()) return this;
-        if (!other.getAttribute().isEmpty()) {
-          attribute_ = other.attribute_;
-          onChanged();
-        }
-        if (!other.getSuffix().isEmpty()) {
-          suffix_ = other.suffix_;
-          onChanged();
-        }
+        internalGetMutableAttributes().mergeFrom(
+            other.internalGetAttributes());
         this.mergeUnknownFields(other.unknownFields);
         onChanged();
         return this;
@@ -3165,156 +3228,133 @@ public final class DataPlaneContract {
         }
         return this;
       }
+      private int bitField0_;
 
-      private java.lang.Object attribute_ = "";
-      /**
-       * <code>string attribute = 1;</code>
-       * @return The attribute.
-       */
-      public java.lang.String getAttribute() {
-        java.lang.Object ref = attribute_;
-        if (!(ref instanceof java.lang.String)) {
-          com.google.protobuf.ByteString bs =
-              (com.google.protobuf.ByteString) ref;
-          java.lang.String s = bs.toStringUtf8();
-          attribute_ = s;
-          return s;
-        } else {
-          return (java.lang.String) ref;
+      private com.google.protobuf.MapField<
+          java.lang.String, java.lang.String> attributes_;
+      private com.google.protobuf.MapField<java.lang.String, java.lang.String>
+      internalGetAttributes() {
+        if (attributes_ == null) {
+          return com.google.protobuf.MapField.emptyMapField(
+              AttributesDefaultEntryHolder.defaultEntry);
         }
+        return attributes_;
       }
-      /**
-       * <code>string attribute = 1;</code>
-       * @return The bytes for attribute.
-       */
-      public com.google.protobuf.ByteString
-          getAttributeBytes() {
-        java.lang.Object ref = attribute_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          attribute_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
+      private com.google.protobuf.MapField<java.lang.String, java.lang.String>
+      internalGetMutableAttributes() {
+        onChanged();;
+        if (attributes_ == null) {
+          attributes_ = com.google.protobuf.MapField.newMapField(
+              AttributesDefaultEntryHolder.defaultEntry);
         }
+        if (!attributes_.isMutable()) {
+          attributes_ = attributes_.copy();
+        }
+        return attributes_;
+      }
+
+      public int getAttributesCount() {
+        return internalGetAttributes().getMap().size();
       }
       /**
-       * <code>string attribute = 1;</code>
-       * @param value The attribute to set.
-       * @return This builder for chaining.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public Builder setAttribute(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  
-        attribute_ = value;
-        onChanged();
-        return this;
+
+      @java.lang.Override
+      public boolean containsAttributes(
+          java.lang.String key) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        return internalGetAttributes().getMap().containsKey(key);
       }
       /**
-       * <code>string attribute = 1;</code>
-       * @return This builder for chaining.
+       * Use {@link #getAttributesMap()} instead.
        */
-      public Builder clearAttribute() {
-        
-        attribute_ = getDefaultInstance().getAttribute();
-        onChanged();
-        return this;
+      @java.lang.Override
+      @java.lang.Deprecated
+      public java.util.Map<java.lang.String, java.lang.String> getAttributes() {
+        return getAttributesMap();
       }
       /**
-       * <code>string attribute = 1;</code>
-       * @param value The bytes for attribute to set.
-       * @return This builder for chaining.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public Builder setAttributeBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  checkByteStringIsUtf8(value);
-        
-        attribute_ = value;
-        onChanged();
-        return this;
-      }
+      @java.lang.Override
 
-      private java.lang.Object suffix_ = "";
+      public java.util.Map<java.lang.String, java.lang.String> getAttributesMap() {
+        return internalGetAttributes().getMap();
+      }
       /**
-       * <code>string suffix = 2;</code>
-       * @return The suffix.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public java.lang.String getSuffix() {
-        java.lang.Object ref = suffix_;
-        if (!(ref instanceof java.lang.String)) {
-          com.google.protobuf.ByteString bs =
-              (com.google.protobuf.ByteString) ref;
-          java.lang.String s = bs.toStringUtf8();
-          suffix_ = s;
-          return s;
-        } else {
-          return (java.lang.String) ref;
-        }
+      @java.lang.Override
+
+      public java.lang.String getAttributesOrDefault(
+          java.lang.String key,
+          java.lang.String defaultValue) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        java.util.Map<java.lang.String, java.lang.String> map =
+            internalGetAttributes().getMap();
+        return map.containsKey(key) ? map.get(key) : defaultValue;
       }
       /**
-       * <code>string suffix = 2;</code>
-       * @return The bytes for suffix.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public com.google.protobuf.ByteString
-          getSuffixBytes() {
-        java.lang.Object ref = suffix_;
-        if (ref instanceof String) {
-          com.google.protobuf.ByteString b = 
-              com.google.protobuf.ByteString.copyFromUtf8(
-                  (java.lang.String) ref);
-          suffix_ = b;
-          return b;
-        } else {
-          return (com.google.protobuf.ByteString) ref;
+      @java.lang.Override
+
+      public java.lang.String getAttributesOrThrow(
+          java.lang.String key) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        java.util.Map<java.lang.String, java.lang.String> map =
+            internalGetAttributes().getMap();
+        if (!map.containsKey(key)) {
+          throw new java.lang.IllegalArgumentException();
         }
+        return map.get(key);
+      }
+
+      public Builder clearAttributes() {
+        internalGetMutableAttributes().getMutableMap()
+            .clear();
+        return this;
       }
       /**
-       * <code>string suffix = 2;</code>
-       * @param value The suffix to set.
-       * @return This builder for chaining.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public Builder setSuffix(
-          java.lang.String value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  
-        suffix_ = value;
-        onChanged();
+
+      public Builder removeAttributes(
+          java.lang.String key) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        internalGetMutableAttributes().getMutableMap()
+            .remove(key);
         return this;
       }
       /**
-       * <code>string suffix = 2;</code>
-       * @return This builder for chaining.
+       * Use alternate mutation accessors instead.
        */
-      public Builder clearSuffix() {
-        
-        suffix_ = getDefaultInstance().getSuffix();
-        onChanged();
+      @java.lang.Deprecated
+      public java.util.Map<java.lang.String, java.lang.String>
+      getMutableAttributes() {
+        return internalGetMutableAttributes().getMutableMap();
+      }
+      /**
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
+       */
+      public Builder putAttributes(
+          java.lang.String key,
+          java.lang.String value) {
+        if (key == null) { throw new java.lang.NullPointerException(); }
+        if (value == null) { throw new java.lang.NullPointerException(); }
+        internalGetMutableAttributes().getMutableMap()
+            .put(key, value);
         return this;
       }
       /**
-       * <code>string suffix = 2;</code>
-       * @param value The bytes for suffix to set.
-       * @return This builder for chaining.
+       * <code>map&lt;string, string&gt; attributes = 1;</code>
        */
-      public Builder setSuffixBytes(
-          com.google.protobuf.ByteString value) {
-        if (value == null) {
-    throw new NullPointerException();
-  }
-  checkByteStringIsUtf8(value);
-        
-        suffix_ = value;
-        onChanged();
+
+      public Builder putAllAttributes(
+          java.util.Map<java.lang.String, java.lang.String> values) {
+        internalGetMutableAttributes().getMutableMap()
+            .putAll(values);
         return this;
       }
       @java.lang.Override
@@ -24576,11 +24616,21 @@ public final class DataPlaneContract {
   private static final 
     com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
       internal_static_Prefix_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_Prefix_AttributesEntry_descriptor;
+  private static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_Prefix_AttributesEntry_fieldAccessorTable;
   private static final com.google.protobuf.Descriptors.Descriptor
     internal_static_Suffix_descriptor;
   private static final 
     com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
       internal_static_Suffix_fieldAccessorTable;
+  private static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_Suffix_AttributesEntry_descriptor;
+  private static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_Suffix_AttributesEntry_fieldAccessorTable;
   private static final com.google.protobuf.Descriptors.Descriptor
     internal_static_All_descriptor;
   private static final 
@@ -24683,69 +24733,72 @@ public final class DataPlaneContract {
       "\n\016contract.proto\"\007\n\005Empty\"f\n\005Exact\022*\n\nat" +
       "tributes\030\001 \003(\0132\026.Exact.AttributesEntry\0321" +
       "\n\017AttributesEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030" +
-      "\002 \001(\t:\0028\001\"+\n\006Prefix\022\021\n\tattribute\030\001 \001(\t\022\016" +
-      "\n\006prefix\030\002 \001(\t\"+\n\006Suffix\022\021\n\tattribute\030\001 " +
-      "\001(\t\022\016\n\006suffix\030\002 \001(\t\"(\n\003All\022!\n\007filters\030\001 " +
-      "\003(\0132\020.DialectedFilter\"(\n\003Any\022!\n\007filters\030" +
-      "\001 \003(\0132\020.DialectedFilter\"\'\n\003Not\022 \n\006filter" +
-      "\030\001 \001(\0132\020.DialectedFilter\"\033\n\005CESQL\022\022\n\nexp" +
-      "ression\030\001 \001(\t\"\302\001\n\017DialectedFilter\022\027\n\005exa" +
-      "ct\030\001 \001(\0132\006.ExactH\000\022\031\n\006prefix\030\002 \001(\0132\007.Pre" +
-      "fixH\000\022\031\n\006suffix\030\003 \001(\0132\007.SuffixH\000\022\023\n\003all\030" +
-      "\004 \001(\0132\004.AllH\000\022\023\n\003any\030\005 \001(\0132\004.AnyH\000\022\023\n\003no" +
-      "t\030\006 \001(\0132\004.NotH\000\022\027\n\005cesql\030\007 \001(\0132\006.CESQLH\000" +
-      "B\010\n\006filter\"h\n\006Filter\022+\n\nattributes\030\001 \003(\013" +
-      "2\027.Filter.AttributesEntry\0321\n\017AttributesE" +
-      "ntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\177\n\014" +
-      "EgressConfig\022\022\n\ndeadLetter\030\001 \001(\t\022\r\n\005retr" +
-      "y\030\002 \001(\r\022%\n\rbackoffPolicy\030\003 \001(\0162\016.Backoff" +
-      "Policy\022\024\n\014backoffDelay\030\004 \001(\004\022\017\n\007timeout\030" +
-      "\005 \001(\004\"\370\002\n\006Egress\022\025\n\rconsumerGroup\030\001 \001(\t\022" +
-      "\023\n\013destination\030\002 \001(\t\022\022\n\010replyUrl\030\003 \001(\tH\000" +
-      "\022&\n\024replyToOriginalTopic\030\004 \001(\0132\006.EmptyH\000" +
-      "\022\036\n\014discardReply\030\t \001(\0132\006.EmptyH\000\022\027\n\006filt" +
-      "er\030\005 \001(\0132\007.Filter\022\013\n\003uid\030\006 \001(\t\022#\n\014egress" +
-      "Config\030\007 \001(\0132\r.EgressConfig\022%\n\rdeliveryO" +
-      "rder\030\010 \001(\0162\016.DeliveryOrder\022\031\n\007keyType\030\n " +
-      "\001(\0162\010.KeyType\022\035\n\treference\030\013 \001(\0132\n.Refer" +
-      "ence\022)\n\017dialectedFilter\030\014 \003(\0132\020.Dialecte" +
-      "dFilterB\017\n\rreplyStrategy\"[\n\007Ingress\022!\n\013c" +
-      "ontentMode\030\001 \001(\0162\014.ContentMode\022\016\n\004path\030\002" +
-      " \001(\tH\000\022\016\n\004host\030\003 \001(\tH\000B\r\n\013ingressType\"K\n" +
-      "\tReference\022\014\n\004uuid\030\001 \001(\t\022\021\n\tnamespace\030\002 " +
-      "\001(\t\022\014\n\004name\030\003 \001(\t\022\017\n\007version\030\004 \001(\t\"`\n\017Se" +
-      "cretReference\022\035\n\treference\030\001 \001(\0132\n.Refer" +
-      "ence\022.\n\022keyFieldReferences\030\002 \003(\0132\022.KeyFi" +
-      "eldReference\"C\n\021KeyFieldReference\022\021\n\tsec" +
-      "retKey\030\002 \001(\t\022\033\n\005field\030\003 \001(\0162\014.SecretFiel" +
-      "d\"Y\n\024MultiSecretReference\022\033\n\010protocol\030\001 " +
-      "\001(\0162\t.Protocol\022$\n\nreferences\030\002 \003(\0132\020.Sec" +
-      "retReference\"\202\001\n\023CloudEventOverrides\0228\n\n" +
-      "extensions\030\001 \003(\0132$.CloudEventOverrides.E" +
-      "xtensionsEntry\0321\n\017ExtensionsEntry\022\013\n\003key" +
-      "\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\350\002\n\010Resource\022\013" +
-      "\n\003uid\030\001 \001(\t\022\016\n\006topics\030\002 \003(\t\022\030\n\020bootstrap" +
-      "Servers\030\003 \001(\t\022\031\n\007ingress\030\004 \001(\0132\010.Ingress" +
-      "\022#\n\014egressConfig\030\005 \001(\0132\r.EgressConfig\022\031\n" +
-      "\010egresses\030\006 \003(\0132\007.Egress\022\034\n\nabsentAuth\030\007" +
-      " \001(\0132\006.EmptyH\000\022 \n\nauthSecret\030\010 \001(\0132\n.Ref" +
-      "erenceH\000\0220\n\017multiAuthSecret\030\t \001(\0132\025.Mult" +
-      "iSecretReferenceH\000\0221\n\023cloudEventOverride" +
-      "s\030\n \001(\0132\024.CloudEventOverrides\022\035\n\treferen" +
-      "ce\030\013 \001(\0132\n.ReferenceB\006\n\004Auth\"<\n\010Contract" +
-      "\022\022\n\ngeneration\030\001 \001(\004\022\034\n\tresources\030\002 \003(\0132" +
-      "\t.Resource*,\n\rBackoffPolicy\022\017\n\013Exponenti" +
-      "al\020\000\022\n\n\006Linear\020\001*+\n\rDeliveryOrder\022\r\n\tUNO" +
-      "RDERED\020\000\022\013\n\007ORDERED\020\001*=\n\007KeyType\022\n\n\006Stri" +
-      "ng\020\000\022\013\n\007Integer\020\001\022\n\n\006Double\020\002\022\r\n\tByteArr" +
-      "ay\020\003*)\n\013ContentMode\022\n\n\006BINARY\020\000\022\016\n\nSTRUC" +
-      "TURED\020\001*a\n\013SecretField\022\022\n\016SASL_MECHANISM" +
-      "\020\000\022\n\n\006CA_CRT\020\001\022\014\n\010USER_CRT\020\002\022\014\n\010USER_KEY" +
-      "\020\003\022\010\n\004USER\020\004\022\014\n\010PASSWORD\020\005*D\n\010Protocol\022\r" +
-      "\n\tPLAINTEXT\020\000\022\022\n\016SASL_PLAINTEXT\020\001\022\007\n\003SSL" +
-      "\020\002\022\014\n\010SASL_SSL\020\003B[\n*dev.knative.eventing" +
-      ".kafka.broker.contractB\021DataPlaneContrac" +
-      "tZ\032control-plane/pkg/contractb\006proto3"
+      "\002 \001(\t:\0028\001\"h\n\006Prefix\022+\n\nattributes\030\001 \003(\0132" +
+      "\027.Prefix.AttributesEntry\0321\n\017AttributesEn" +
+      "try\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"h\n\006S" +
+      "uffix\022+\n\nattributes\030\001 \003(\0132\027.Suffix.Attri" +
+      "butesEntry\0321\n\017AttributesEntry\022\013\n\003key\030\001 \001" +
+      "(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"(\n\003All\022!\n\007filters\030" +
+      "\001 \003(\0132\020.DialectedFilter\"(\n\003Any\022!\n\007filter" +
+      "s\030\001 \003(\0132\020.DialectedFilter\"\'\n\003Not\022 \n\006filt" +
+      "er\030\001 \001(\0132\020.DialectedFilter\"\033\n\005CESQL\022\022\n\ne" +
+      "xpression\030\001 \001(\t\"\302\001\n\017DialectedFilter\022\027\n\005e" +
+      "xact\030\001 \001(\0132\006.ExactH\000\022\031\n\006prefix\030\002 \001(\0132\007.P" +
+      "refixH\000\022\031\n\006suffix\030\003 \001(\0132\007.SuffixH\000\022\023\n\003al" +
+      "l\030\004 \001(\0132\004.AllH\000\022\023\n\003any\030\005 \001(\0132\004.AnyH\000\022\023\n\003" +
+      "not\030\006 \001(\0132\004.NotH\000\022\027\n\005cesql\030\007 \001(\0132\006.CESQL" +
+      "H\000B\010\n\006filter\"h\n\006Filter\022+\n\nattributes\030\001 \003" +
+      "(\0132\027.Filter.AttributesEntry\0321\n\017Attribute" +
+      "sEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\177" +
+      "\n\014EgressConfig\022\022\n\ndeadLetter\030\001 \001(\t\022\r\n\005re" +
+      "try\030\002 \001(\r\022%\n\rbackoffPolicy\030\003 \001(\0162\016.Backo" +
+      "ffPolicy\022\024\n\014backoffDelay\030\004 \001(\004\022\017\n\007timeou" +
+      "t\030\005 \001(\004\"\370\002\n\006Egress\022\025\n\rconsumerGroup\030\001 \001(" +
+      "\t\022\023\n\013destination\030\002 \001(\t\022\022\n\010replyUrl\030\003 \001(\t" +
+      "H\000\022&\n\024replyToOriginalTopic\030\004 \001(\0132\006.Empty" +
+      "H\000\022\036\n\014discardReply\030\t \001(\0132\006.EmptyH\000\022\027\n\006fi" +
+      "lter\030\005 \001(\0132\007.Filter\022\013\n\003uid\030\006 \001(\t\022#\n\014egre" +
+      "ssConfig\030\007 \001(\0132\r.EgressConfig\022%\n\rdeliver" +
+      "yOrder\030\010 \001(\0162\016.DeliveryOrder\022\031\n\007keyType\030" +
+      "\n \001(\0162\010.KeyType\022\035\n\treference\030\013 \001(\0132\n.Ref" +
+      "erence\022)\n\017dialectedFilter\030\014 \003(\0132\020.Dialec" +
+      "tedFilterB\017\n\rreplyStrategy\"[\n\007Ingress\022!\n" +
+      "\013contentMode\030\001 \001(\0162\014.ContentMode\022\016\n\004path" +
+      "\030\002 \001(\tH\000\022\016\n\004host\030\003 \001(\tH\000B\r\n\013ingressType\"" +
+      "K\n\tReference\022\014\n\004uuid\030\001 \001(\t\022\021\n\tnamespace\030" +
+      "\002 \001(\t\022\014\n\004name\030\003 \001(\t\022\017\n\007version\030\004 \001(\t\"`\n\017" +
+      "SecretReference\022\035\n\treference\030\001 \001(\0132\n.Ref" +
+      "erence\022.\n\022keyFieldReferences\030\002 \003(\0132\022.Key" +
+      "FieldReference\"C\n\021KeyFieldReference\022\021\n\ts" +
+      "ecretKey\030\002 \001(\t\022\033\n\005field\030\003 \001(\0162\014.SecretFi" +
+      "eld\"Y\n\024MultiSecretReference\022\033\n\010protocol\030" +
+      "\001 \001(\0162\t.Protocol\022$\n\nreferences\030\002 \003(\0132\020.S" +
+      "ecretReference\"\202\001\n\023CloudEventOverrides\0228" +
+      "\n\nextensions\030\001 \003(\0132$.CloudEventOverrides" +
+      ".ExtensionsEntry\0321\n\017ExtensionsEntry\022\013\n\003k" +
+      "ey\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\350\002\n\010Resource" +
+      "\022\013\n\003uid\030\001 \001(\t\022\016\n\006topics\030\002 \003(\t\022\030\n\020bootstr" +
+      "apServers\030\003 \001(\t\022\031\n\007ingress\030\004 \001(\0132\010.Ingre" +
+      "ss\022#\n\014egressConfig\030\005 \001(\0132\r.EgressConfig\022" +
+      "\031\n\010egresses\030\006 \003(\0132\007.Egress\022\034\n\nabsentAuth" +
+      "\030\007 \001(\0132\006.EmptyH\000\022 \n\nauthSecret\030\010 \001(\0132\n.R" +
+      "eferenceH\000\0220\n\017multiAuthSecret\030\t \001(\0132\025.Mu" +
+      "ltiSecretReferenceH\000\0221\n\023cloudEventOverri" +
+      "des\030\n \001(\0132\024.CloudEventOverrides\022\035\n\trefer" +
+      "ence\030\013 \001(\0132\n.ReferenceB\006\n\004Auth\"<\n\010Contra" +
+      "ct\022\022\n\ngeneration\030\001 \001(\004\022\034\n\tresources\030\002 \003(" +
+      "\0132\t.Resource*,\n\rBackoffPolicy\022\017\n\013Exponen" +
+      "tial\020\000\022\n\n\006Linear\020\001*+\n\rDeliveryOrder\022\r\n\tU" +
+      "NORDERED\020\000\022\013\n\007ORDERED\020\001*=\n\007KeyType\022\n\n\006St" +
+      "ring\020\000\022\013\n\007Integer\020\001\022\n\n\006Double\020\002\022\r\n\tByteA" +
+      "rray\020\003*)\n\013ContentMode\022\n\n\006BINARY\020\000\022\016\n\nSTR" +
+      "UCTURED\020\001*a\n\013SecretField\022\022\n\016SASL_MECHANI" +
+      "SM\020\000\022\n\n\006CA_CRT\020\001\022\014\n\010USER_CRT\020\002\022\014\n\010USER_K" +
+      "EY\020\003\022\010\n\004USER\020\004\022\014\n\010PASSWORD\020\005*D\n\010Protocol" +
+      "\022\r\n\tPLAINTEXT\020\000\022\022\n\016SASL_PLAINTEXT\020\001\022\007\n\003S" +
+      "SL\020\002\022\014\n\010SASL_SSL\020\003B[\n*dev.knative.eventi" +
+      "ng.kafka.broker.contractB\021DataPlaneContr" +
+      "actZ\032control-plane/pkg/contractb\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -24774,13 +24827,25 @@ public final class DataPlaneContract {
     internal_static_Prefix_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_Prefix_descriptor,
-        new java.lang.String[] { "Attribute", "Prefix", });
+        new java.lang.String[] { "Attributes", });
+    internal_static_Prefix_AttributesEntry_descriptor =
+      internal_static_Prefix_descriptor.getNestedTypes().get(0);
+    internal_static_Prefix_AttributesEntry_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_Prefix_AttributesEntry_descriptor,
+        new java.lang.String[] { "Key", "Value", });
     internal_static_Suffix_descriptor =
       getDescriptor().getMessageTypes().get(3);
     internal_static_Suffix_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_Suffix_descriptor,
-        new java.lang.String[] { "Attribute", "Suffix", });
+        new java.lang.String[] { "Attributes", });
+    internal_static_Suffix_AttributesEntry_descriptor =
+      internal_static_Suffix_descriptor.getNestedTypes().get(0);
+    internal_static_Suffix_AttributesEntry_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_Suffix_AttributesEntry_descriptor,
+        new java.lang.String[] { "Key", "Value", });
     internal_static_All_descriptor =
       getDescriptor().getMessageTypes().get(4);
     internal_static_All_fieldAccessorTable = new
diff --git a/data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/reconciler/impl/ResourcesReconcilerImpl.java b/data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/reconciler/impl/ResourcesReconcilerImpl.java
index f7dab59a0..35af385ae 100644
--- a/data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/reconciler/impl/ResourcesReconcilerImpl.java
+++ b/data-plane/core/src/main/java/dev/knative/eventing/kafka/broker/core/reconciler/impl/ResourcesReconcilerImpl.java
@@ -22,7 +22,6 @@ import dev.knative.eventing.kafka.broker.core.reconciler.ResourcesReconciler;
 import dev.knative.eventing.kafka.broker.core.utils.CollectionsUtils;
 import io.vertx.core.CompositeFuture;
 import io.vertx.core.Future;
-
 import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -32,7 +31,6 @@ import java.util.Map;
 import java.util.Objects;
 import java.util.function.Function;
 import java.util.stream.Collectors;
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -250,7 +248,8 @@ public class ResourcesReconcilerImpl implements ResourcesReconciler {
       && Objects.equals(e1.getReplyToOriginalTopic(), e2.getReplyToOriginalTopic())
       && Objects.equals(e1.getEgressConfig(), e2.getEgressConfig())
       && Objects.equals(e1.getFilter(), e2.getFilter())
-      && Objects.equals(e1.getKeyType(), e2.getKeyType());
+      && Objects.equals(e1.getKeyType(), e2.getKeyType())
+      && Objects.equals(e1.getDialectedFilterList(), e2.getDialectedFilterList());
   }
 
   private static void logFailure(final String msg, final DataPlaneContract.Egress egress, final Throwable cause) {
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AttributesFilter.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AttributesFilter.java
index f4fb61451..d113256c3 100644
--- a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AttributesFilter.java
+++ b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AttributesFilter.java
@@ -21,19 +21,37 @@ import io.cloudevents.core.v03.CloudEventV03;
 import io.cloudevents.core.v1.CloudEventV1;
 import io.cloudevents.lang.Nullable;
 import java.net.URI;
-import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.function.Function;
 import java.util.stream.Collectors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static java.time.format.DateTimeFormatter.ISO_INSTANT;
 
-public class AttributesFilter implements Filter {
+public abstract class AttributesFilter implements Filter {
+
+  static class AttributeEntry {
+    private final String name;
+    private final String expectedValue;
+    // An extractor function to turn an event into a string value.
+    // specversion -> 1.0
+    // f(event) -> event.getSpecVersion().toString() -> 1.0
+    private final Function<CloudEvent, String> extractor;
+
+    public AttributeEntry(String name, String expectedValue, Function<CloudEvent, String> extractor) {
+      this.name = name;
+      this.expectedValue = expectedValue;
+      this.extractor = extractor;
+    }
+  }
 
   private static final String DEFAULT_STRING = "";
 
+  protected final Logger logger = LoggerFactory.getLogger(getClass());
+
+
   static final Map<String, Function<CloudEvent, String>> attributesMapper = Map.of(
     CloudEventV1.SPECVERSION, event -> event.getSpecVersion().toString(),
     CloudEventV1.ID, CloudEvent::getId,
@@ -46,11 +64,7 @@ public class AttributesFilter implements Filter {
     CloudEventV1.TIME, event -> getOrDefault(event.getTime(), time -> time.format(ISO_INSTANT))
   );
 
-  // the key represents the function to turn an event into a string value.
-  // the value represents the value to match.
-  // specversion -> 1.0
-  // f(event) -> event.getSpecVersion().toString() -> 1.0
-  private final List<Entry<Function<CloudEvent, String>, String>> attributes;
+  private final List<AttributeEntry> attributes;
 
   /**
    * All args constructor.
@@ -60,7 +74,9 @@ public class AttributesFilter implements Filter {
   public AttributesFilter(final Map<String, String> attributes) {
     this.attributes = attributes.entrySet().stream()
       .filter(entry -> isNotEmpty(entry.getValue()))
-      .map(entry -> new SimpleImmutableEntry<>(
+      .map(entry -> new AttributeEntry(
+        entry.getKey(),
+        entry.getValue(),
         attributesMapper.getOrDefault(
           entry.getKey(),
           event -> {
@@ -70,9 +86,7 @@ public class AttributesFilter implements Filter {
               return getOrDefault(event.getExtension(entry.getKey()), Object::toString);
             }
           }
-        ),
-        entry.getValue()
-      ))
+        )))
       .collect(Collectors.toUnmodifiableList());
   }
 
@@ -86,16 +100,31 @@ public class AttributesFilter implements Filter {
    */
   @Override
   public boolean test(final CloudEvent event) {
-
+    logger.debug("Testing event attributes. Event {}", event);
     for (final var entry : attributes) {
-      if (!entry.getKey().apply(event).equals(entry.getValue())) {
+      Function<CloudEvent, String> extractorFunc = entry.extractor;
+      String wantedValue = entry.expectedValue;
+      String existingValue = extractorFunc.apply(event);
+      if (!this.match(existingValue, wantedValue)) {
+        logger.debug("Event attributes matching failed. Attribute: {} Want: {} Got: {} Event: {}",
+          entry.name, wantedValue, existingValue, event);
         return false;
       }
     }
-
+    logger.debug("Event attributes matching succeeded");
     return true;
   }
 
+
+  /**
+   * Matches the given value against the wanted value.
+   *
+   * @param wanted desired attribute value
+   * @param given  cloud event current attribute value
+   * @return
+   */
+  protected abstract boolean match(String given, String wanted);
+
   private static <T> String getOrDefault(
     @Nullable final T s,
     final Function<T, String> stringProvider) {
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/BaseStringFilter.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/BaseStringFilter.java
deleted file mode 100644
index e151a39b3..000000000
--- a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/BaseStringFilter.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright © 2018 Knative Authors (knative-dev@googlegroups.com)
- *
- * 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 dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
-
-import dev.knative.eventing.kafka.broker.dispatcher.Filter;
-import io.cloudevents.CloudEvent;
-import java.util.function.Function;
-
-public abstract class BaseStringFilter implements Filter {
-
-  protected final Function<CloudEvent, String> extractor;
-  protected final String expectedValue;
-
-  public BaseStringFilter(String attribute, String expectedValue) {
-    if (attribute == null || attribute.isBlank()) {
-      throw new IllegalArgumentException("Attribute name is empty");
-    }
-    if (expectedValue == null || expectedValue.isBlank()) {
-      throw new IllegalArgumentException("Attribute value is empty");
-    }
-
-    this.extractor = AttributesFilter.attributesMapper.getOrDefault(attribute, e -> {
-      Object extValue = e.getExtension(attribute);
-      if (extValue == null) {
-        return null;
-      }
-      return extValue.toString();
-    });
-    this.expectedValue = expectedValue;
-  }
-
-}
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AllFilter.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AllFilter.java
similarity index 75%
rename from data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AllFilter.java
rename to data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AllFilter.java
index 67bd56464..1ba8c183b 100644
--- a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AllFilter.java
+++ b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AllFilter.java
@@ -13,15 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
 import dev.knative.eventing.kafka.broker.dispatcher.Filter;
 import io.cloudevents.CloudEvent;
 import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class AllFilter implements Filter {
 
   private final Set<Filter> filters;
+  private static final Logger logger = LoggerFactory.getLogger(AllFilter.class);
+
 
   public AllFilter(Set<Filter> filters) {
     this.filters = filters;
@@ -29,11 +33,14 @@ public class AllFilter implements Filter {
 
   @Override
   public boolean test(CloudEvent cloudEvent) {
+    logger.debug("Testing event against ALL filters. Event {}", cloudEvent);
     for (Filter filter : filters) {
       if (!filter.test(cloudEvent)) {
+        logger.debug("Test failed. Filter {} Event {}", filter, cloudEvent);
         return false;
       }
     }
+    logger.debug("Test ALL filters succeeded. Event {}", cloudEvent);
     return true;
   }
 }
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AnyFilter.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AnyFilter.java
similarity index 74%
rename from data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AnyFilter.java
rename to data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AnyFilter.java
index 8b2c1a618..a593ae0ca 100644
--- a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AnyFilter.java
+++ b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AnyFilter.java
@@ -13,14 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
 import dev.knative.eventing.kafka.broker.dispatcher.Filter;
 import io.cloudevents.CloudEvent;
 import java.util.Set;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class AnyFilter implements Filter {
 
+  private static final Logger logger = LoggerFactory.getLogger(AnyFilter.class);
+
   private final Set<Filter> filters;
 
   public AnyFilter(Set<Filter> filters) {
@@ -29,11 +33,15 @@ public class AnyFilter implements Filter {
 
   @Override
   public boolean test(CloudEvent cloudEvent) {
+    logger.debug("Testing event against ANY filter. Event {}", cloudEvent);
+
     for (Filter filter : filters) {
       if (filter.test(cloudEvent)) {
+        logger.debug("Test succeeded. Filter {} Event {}", filter, cloudEvent);
         return true;
       }
     }
+    logger.debug("Test failed. All filters failed. Event {}", cloudEvent);
     return false;
   }
 }
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SqlFilter.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/CeSqlFilter.java
similarity index 69%
rename from data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SqlFilter.java
rename to data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/CeSqlFilter.java
index ecdfa1bf4..e00347a23 100644
--- a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SqlFilter.java
+++ b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/CeSqlFilter.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
 import dev.knative.eventing.kafka.broker.dispatcher.Filter;
 import io.cloudevents.CloudEvent;
@@ -22,13 +22,17 @@ import io.cloudevents.sql.EvaluationRuntime;
 import io.cloudevents.sql.Expression;
 import io.cloudevents.sql.Parser;
 import io.cloudevents.sql.Type;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-public class SqlFilter implements Filter {
+public class CeSqlFilter implements Filter {
+
+  private static final Logger logger = LoggerFactory.getLogger(CeSqlFilter.class);
 
   private final Expression expression;
   private final EvaluationRuntime runtime;
 
-  public SqlFilter(String sqlExpression) {
+  public CeSqlFilter(String sqlExpression) {
     this.expression = Parser.parseDefault(sqlExpression);
     this.runtime = EvaluationRuntime.getDefault();
   }
@@ -36,9 +40,13 @@ public class SqlFilter implements Filter {
   @Override
   public boolean test(CloudEvent cloudEvent) {
     try {
+      logger.debug("Testing event against CESQL expression. Expression {} - Event {}", this.expression, cloudEvent);
       Object value = this.expression.tryEvaluate(this.runtime, cloudEvent);
+      logger.debug("CESQL evaluation succeeded. Expression {} - Event {} - Result {}", expression, cloudEvent, value);
       return (Boolean) this.runtime.cast(value, Type.BOOLEAN);
     } catch (EvaluationException evaluationException) {
+      logger.error("Exception while evaluating CESQL expression. Test failed. Expression {} - Exception {}",
+        this.expression, evaluationException);
       return false;
     }
   }
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/ExactFilter.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/ExactFilter.java
similarity index 68%
rename from data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/ExactFilter.java
rename to data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/ExactFilter.java
index c609175fc..6eb881e82 100644
--- a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/ExactFilter.java
+++ b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/ExactFilter.java
@@ -13,18 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
-import io.cloudevents.CloudEvent;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.AttributesFilter;
+import java.util.Map;
 
-public class ExactFilter extends BaseStringFilter {
+public class ExactFilter extends AttributesFilter {
 
-  public ExactFilter(String attribute, String expectedValue) {
-    super(attribute, expectedValue);
+  public ExactFilter(Map<String, String> attributes) {
+    super(attributes);
   }
 
   @Override
-  public boolean test(CloudEvent cloudEvent) {
-    return expectedValue.equals(this.extractor.apply(cloudEvent));
+  public boolean match(String given, String wanted) {
+    return given.equals(wanted);
   }
 }
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/NotFilter.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/NotFilter.java
new file mode 100644
index 000000000..1dff06fa8
--- /dev/null
+++ b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/NotFilter.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2018 Knative Authors (knative-dev@googlegroups.com)
+ *
+ * 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 dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
+
+import dev.knative.eventing.kafka.broker.dispatcher.Filter;
+import io.cloudevents.CloudEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NotFilter implements Filter {
+
+  private static final Logger logger = LoggerFactory.getLogger(NotFilter.class);
+
+  private final Filter filter;
+
+  public NotFilter(Filter filter) {
+    this.filter = filter;
+  }
+
+  @Override
+  public boolean test(CloudEvent cloudEvent) {
+    logger.debug("Testing NOT filter. Event {}", cloudEvent);
+    boolean passed = !filter.test(cloudEvent);
+    String result = passed ? "Succeeded" : "Failed";
+    logger.debug("{}: Filter {} - Event {}", result, this.filter, cloudEvent);
+    return passed;
+  }
+}
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/PrefixFilter.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/PrefixFilter.java
similarity index 67%
rename from data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/PrefixFilter.java
rename to data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/PrefixFilter.java
index 22f31cc9e..82e1e663e 100644
--- a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/PrefixFilter.java
+++ b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/PrefixFilter.java
@@ -13,19 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
-import io.cloudevents.CloudEvent;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.AttributesFilter;
+import java.util.Map;
 
-public class PrefixFilter extends BaseStringFilter {
+public class PrefixFilter extends AttributesFilter {
 
-  public PrefixFilter(String attribute, String expectedValue) {
-    super(attribute, expectedValue);
+  public PrefixFilter(Map<String, String> attributes) {
+    super(attributes);
   }
 
   @Override
-  public boolean test(CloudEvent cloudEvent) {
-    String value = this.extractor.apply(cloudEvent);
-    return value != null && value.startsWith(this.expectedValue);
+  public boolean match(String given, String wanted) {
+    return given.startsWith(wanted);
   }
 }
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SuffixFilter.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/SuffixFilter.java
similarity index 67%
rename from data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SuffixFilter.java
rename to data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/SuffixFilter.java
index e43a3cf46..06a10f708 100644
--- a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SuffixFilter.java
+++ b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/SuffixFilter.java
@@ -13,19 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
-import io.cloudevents.CloudEvent;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.AttributesFilter;
+import java.util.Map;
 
-public class SuffixFilter extends BaseStringFilter {
+public class SuffixFilter extends AttributesFilter {
 
-  public SuffixFilter(String attribute, String expectedValue) {
-    super(attribute, expectedValue);
+  public SuffixFilter(Map<String, String> attributes) {
+    super(attributes);
   }
 
   @Override
-  public boolean test(CloudEvent cloudEvent) {
-    String value = this.extractor.apply(cloudEvent);
-    return value != null && value.endsWith(this.expectedValue);
+  public boolean match(String given, String wanted) {
+    return given.endsWith(wanted);
   }
 }
diff --git a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/main/ConsumerVerticleFactoryImpl.java b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/main/ConsumerVerticleFactoryImpl.java
index 74126def6..8b7503b8b 100644
--- a/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/main/ConsumerVerticleFactoryImpl.java
+++ b/data-plane/dispatcher/src/main/java/dev/knative/eventing/kafka/broker/dispatcher/main/ConsumerVerticleFactoryImpl.java
@@ -29,9 +29,9 @@ import dev.knative.eventing.kafka.broker.dispatcher.ResponseHandler;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.NoopResponseHandler;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.RecordDispatcherImpl;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.RecordDispatcherMutatorChain;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.ResourceContext;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.ResponseToHttpEndpointHandler;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.ResponseToKafkaTopicHandler;
-import dev.knative.eventing.kafka.broker.dispatcher.impl.ResourceContext;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.consumer.BaseConsumerVerticle;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.consumer.CloudEventOverridesMutator;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.consumer.InvalidCloudEventInterceptor;
@@ -39,7 +39,13 @@ import dev.knative.eventing.kafka.broker.dispatcher.impl.consumer.KeyDeserialize
 import dev.knative.eventing.kafka.broker.dispatcher.impl.consumer.OffsetManager;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.consumer.OrderedConsumerVerticle;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.consumer.UnorderedConsumerVerticle;
-import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.AttributesFilter;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi.AllFilter;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi.AnyFilter;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi.CeSqlFilter;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi.ExactFilter;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi.NotFilter;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi.PrefixFilter;
+import dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi.SuffixFilter;
 import dev.knative.eventing.kafka.broker.dispatcher.impl.http.WebClientCloudEventSender;
 import io.cloudevents.CloudEvent;
 import io.micrometer.core.instrument.Counter;
@@ -56,14 +62,10 @@ import io.vertx.kafka.client.common.KafkaClientOptions;
 import io.vertx.kafka.client.common.tracing.ConsumerTracer;
 import io.vertx.kafka.client.consumer.KafkaConsumer;
 import io.vertx.kafka.client.producer.KafkaProducer;
-import org.apache.kafka.clients.consumer.ConsumerConfig;
-import org.apache.kafka.clients.producer.ProducerConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
@@ -72,6 +74,10 @@ import java.util.Set;
 import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import static dev.knative.eventing.kafka.broker.core.utils.Logging.keyValue;
 
@@ -148,72 +154,100 @@ public class ConsumerVerticleFactoryImpl implements ConsumerVerticleFactory {
 
     final BaseConsumerVerticle.Initializer initializer = (vertx, consumerVerticle) ->
       authProvider.getCredentials(resource).onSuccess(credentials -> {
-        KafkaClientsAuth.attachCredentials(consumerConfigs, credentials);
-        KafkaClientsAuth.attachCredentials(producerConfigs, credentials);
-
-        final KafkaConsumer<Object, CloudEvent> consumer = createConsumer(vertx, consumerConfigs);
-        AutoCloseable metricsCloser = Metrics.register(consumer.unwrap());
-
-        final var egressConfig =
-          egress.hasEgressConfig() ?
-            egress.getEgressConfig() :
-            resource.getEgressConfig();
-
-        final var egressSubscriberSender = createConsumerRecordSender(
-          vertx,
-          egress.getDestination(),
-          egressConfig
-        );
-
-        final var egressDeadLetterSender = hasDeadLetterSink(egressConfig)
-          ? createConsumerRecordSender(vertx, egressConfig.getDeadLetter(), egressConfig)
-          : NO_DEAD_LETTER_SINK_SENDER;
-
-        final var filter = egress.hasFilter() ?
-          new AttributesFilter(egress.getFilter().getAttributesMap()) :
-          Filter.noop();
-
-        final var responseHandler = getResponseHandler(egress,
-          () -> getResponseToKafkaTopicHandler(vertx, producerConfigs, resource),
-          () -> new ResponseToHttpEndpointHandler(createConsumerRecordSender(vertx, egress.getReplyUrl(), egressConfig)));
-        final var commitIntervalMs = Integer.parseInt(String.valueOf(consumerConfigs.get(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG)));
-
-        final var recordDispatcher = new RecordDispatcherMutatorChain(
-          new RecordDispatcherImpl(
-            new ResourceContext(resource, egress),
-            filter,
-            egressSubscriberSender,
-            egressDeadLetterSender,
-            responseHandler,
-            new OffsetManager(vertx, consumer, eventsSentCounter::increment, commitIntervalMs),
-            ConsumerTracer.create(
-              ((VertxInternal) vertx).tracer(),
-              new KafkaClientOptions()
-                .setConfig(consumerConfigs)
-                // Make sure the policy is propagate for the manually instantiated consumer tracer
-                .setTracingPolicy(TracingPolicy.PROPAGATE)
-            ),
-            Metrics.getRegistry()
-          ),
-          new CloudEventOverridesMutator(resource.getCloudEventOverrides())
-        );
-
-        // Set all the built objects in the consumer verticle
-        consumerVerticle.setRecordDispatcher(recordDispatcher);
-        consumerVerticle.setConsumer(consumer);
-        consumerVerticle.setCloser(AsyncCloseable.wrapAutoCloseable(metricsCloser));
-      })
-        .mapEmpty();
+       KafkaClientsAuth.attachCredentials(consumerConfigs, credentials);
+       KafkaClientsAuth.attachCredentials(producerConfigs, credentials);
+
+       final KafkaConsumer<Object, CloudEvent> consumer = createConsumer(vertx, consumerConfigs);
+       AutoCloseable metricsCloser = Metrics.register(consumer.unwrap());
+
+       final var egressConfig =
+         egress.hasEgressConfig() ?
+           egress.getEgressConfig() :
+           resource.getEgressConfig();
+
+       final var egressSubscriberSender = createConsumerRecordSender(
+         vertx,
+         egress.getDestination(),
+         egressConfig
+       );
+
+       final var egressDeadLetterSender = hasDeadLetterSink(egressConfig)
+         ? createConsumerRecordSender(vertx, egressConfig.getDeadLetter(), egressConfig)
+         : NO_DEAD_LETTER_SINK_SENDER;
+
+       final var filter = getFilter(egress);
+
+       final var responseHandler = getResponseHandler(egress,
+         () -> getResponseToKafkaTopicHandler(vertx, producerConfigs, resource),
+         () -> new ResponseToHttpEndpointHandler(createConsumerRecordSender(vertx, egress.getReplyUrl(), egressConfig)));
+       final var commitIntervalMs = Integer.parseInt(String.valueOf(consumerConfigs.get(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG)));
+
+       final var recordDispatcher = new RecordDispatcherMutatorChain(
+         new RecordDispatcherImpl(
+           new ResourceContext(resource, egress),
+           filter,
+           egressSubscriberSender,
+           egressDeadLetterSender,
+           responseHandler,
+           new OffsetManager(vertx, consumer, eventsSentCounter::increment, commitIntervalMs),
+           ConsumerTracer.create(
+             ((VertxInternal) vertx).tracer(),
+             new KafkaClientOptions()
+               .setConfig(consumerConfigs)
+               // Make sure the policy is propagate for the manually instantiated consumer tracer
+               .setTracingPolicy(TracingPolicy.PROPAGATE)
+           ),
+           Metrics.getRegistry()
+         ),
+         new CloudEventOverridesMutator(resource.getCloudEventOverrides())
+       );
+
+       // Set all the built objects in the consumer verticle
+       consumerVerticle.setRecordDispatcher(recordDispatcher);
+       consumerVerticle.setConsumer(consumer);
+       consumerVerticle.setCloser(AsyncCloseable.wrapAutoCloseable(metricsCloser));
+     })
+       .mapEmpty();
 
     return getConsumerVerticle(deliveryOrder, initializer, new HashSet<>(resource.getTopicsList()));
   }
 
+  private Filter getFilter(DataPlaneContract.Egress egress) {
+    // Dialected filters should override the attributes filter
+    if (egress.getDialectedFilterCount() > 0) {
+      logger.debug("Egress contains dialected-filters. Dialected-filters will be used for event filtering. Egress {}", egress.getReference());
+      return getFilter(egress.getDialectedFilterList());
+    } else if (egress.hasFilter()) {
+      return new ExactFilter(egress.getFilter().getAttributesMap());
+    }
+    return Filter.noop();
+  }
+
+  private static Filter getFilter(DataPlaneContract.DialectedFilter filter) {
+    return switch (filter.getFilterCase()) {
+      case EXACT -> new ExactFilter(filter.getExact().getAttributesMap());
+      case PREFIX -> new PrefixFilter(filter.getPrefix().getAttributesMap());
+      case SUFFIX -> new SuffixFilter(filter.getSuffix().getAttributesMap());
+      case NOT -> new NotFilter(getFilter(filter.getNot().getFilter()));
+      case ANY -> new AnyFilter(filter.getAny().getFiltersList().stream().
+        map(ConsumerVerticleFactoryImpl::getFilter).collect(Collectors.toSet()));
+      case ALL -> new AllFilter(filter.getAll().getFiltersList().stream().
+        map(ConsumerVerticleFactoryImpl::getFilter).collect(Collectors.toSet()));
+      case CESQL -> new CeSqlFilter(filter.getCesql().getExpression());
+      default -> Filter.noop();
+    };
+  }
+
+  private static Filter getFilter(List<DataPlaneContract.DialectedFilter> filters) {
+    return new AllFilter(filters.stream().map(ConsumerVerticleFactoryImpl::getFilter).collect(Collectors.toSet()));
+  }
+
   static ResponseHandler getResponseHandler(final DataPlaneContract.Egress egress,
                                             final Supplier<ResponseHandler> kafkaSupplier,
                                             final Supplier<ResponseHandler> httpSupplier) {
-    if(egress.hasReplyUrl()){
+    if (egress.hasReplyUrl()) {
       return httpSupplier.get();
-    } else if(egress.hasReplyToOriginalTopic()){
+    } else if (egress.hasReplyToOriginalTopic()) {
       return kafkaSupplier.get();
     } else if (egress.hasDiscardReply()) {
       return new NoopResponseHandler();
diff --git a/proto/contract.proto b/proto/contract.proto
index 096ff28bb..e0bed4ff1 100644
--- a/proto/contract.proto
+++ b/proto/contract.proto
@@ -16,13 +16,11 @@ message Exact {
 }
 
 message Prefix {
-  string attribute = 1;
-  string prefix = 2;
+  map<string, string> attributes = 1;
 }
 
 message Suffix {
-  string attribute = 1;
-  string suffix = 2;
+  map<string, string> attributes = 1;
 }
 
 message All {
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 5b007fb89..0694e83b4 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1212,6 +1212,7 @@ knative.dev/eventing/test
 knative.dev/eventing/test/conformance/helpers
 knative.dev/eventing/test/conformance/helpers/tracing
 knative.dev/eventing/test/e2e/helpers
+knative.dev/eventing/test/experimental/features/new_trigger_filters
 knative.dev/eventing/test/flags
 knative.dev/eventing/test/lib
 knative.dev/eventing/test/lib/dropevents


Test patch:
diff --git a/.github/workflows/kind-e2e.yaml b/.github/workflows/kind-e2e.yaml
index 36ecf4fd0..6b71b408f 100644
--- a/.github/workflows/kind-e2e.yaml
+++ b/.github/workflows/kind-e2e.yaml
@@ -35,6 +35,7 @@ jobs:
           - ./test/e2e_new
           - ./test/e2e_channel
           - ./test/e2e_new_channel
+          - ./test/experimental
 
         # Map between K8s and KinD versions.
         # This is attempting to make it a bit clearer what's being tested.
@@ -63,6 +64,12 @@ jobs:
             channel-auth-scenario: "SASL_SSL"
           - test-suite: ./test/e2e_new
             channel-auth-scenario: "SASL_PLAIN"
+          - test-suite: ./test/experimental
+            channel-auth-scenario: "SSL"
+          - test-suite: ./test/experimental
+            channel-auth-scenario: "SASL_SSL"
+          - test-suite: ./test/experimental
+            channel-auth-scenario: "SASL_PLAIN"
 
     env:
       GOPATH: ${{ github.workspace }}
diff --git a/control-plane/pkg/contract/subscriptionsapi_test.go b/control-plane/pkg/contract/subscriptionsapi_test.go
new file mode 100644
index 000000000..aa4b6c54b
--- /dev/null
+++ b/control-plane/pkg/contract/subscriptionsapi_test.go
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2022 The Knative 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 contract
+
+import (
+	"testing"
+
+	"github.com/google/go-cmp/cmp"
+	"github.com/google/go-cmp/cmp/cmpopts"
+
+	v1 "knative.dev/eventing/pkg/apis/eventing/v1"
+)
+
+func TestFromSubscriptionFilter(t *testing.T) {
+	tt := []struct {
+		name      string
+		apiFilter v1.SubscriptionsAPIFilter
+		want      *DialectedFilter
+	}{
+		{
+			name:      "empty all filter",
+			apiFilter: v1.SubscriptionsAPIFilter{},
+			want:      &DialectedFilter{},
+		},
+		{
+			name: "all filter with exact, prefix & suffix",
+			apiFilter: v1.SubscriptionsAPIFilter{
+				All: []v1.SubscriptionsAPIFilter{
+					{
+						Exact: map[string]string{"type": "dev.knative.kafkasrc.kafkarecord"},
+					},
+					{
+						Prefix: map[string]string{"source": "dev.knative"},
+					},
+					{
+						Suffix: map[string]string{"subject": "source"},
+					},
+					{
+						Not: &v1.SubscriptionsAPIFilter{
+							Prefix: map[string]string{"source": "dev.knative"},
+						},
+					},
+					{
+						CESQL: "subject = 'source'",
+					},
+				},
+			},
+			want: &DialectedFilter{
+				Filter: &DialectedFilter_All{
+					All: &All{
+						Filters: []*DialectedFilter{
+							{
+								Filter: &DialectedFilter_Exact{
+									Exact: &Exact{
+										Attributes: map[string]string{"type": "dev.knative.kafkasrc.kafkarecord"},
+									},
+								},
+							},
+							{
+								Filter: &DialectedFilter_Prefix{
+									Prefix: &Prefix{
+										Attributes: map[string]string{"source": "dev.knative"},
+									},
+								},
+							},
+							{
+								Filter: &DialectedFilter_Suffix{
+									Suffix: &Suffix{
+										Attributes: map[string]string{"subject": "source"},
+									},
+								},
+							},
+							{
+								Filter: &DialectedFilter_Not{
+									Not: &Not{
+										Filter: &DialectedFilter{
+											Filter: &DialectedFilter_Prefix{
+												Prefix: &Prefix{
+													Attributes: map[string]string{"source": "dev.knative"},
+												},
+											},
+										},
+									},
+								},
+							},
+							{
+								Filter: &DialectedFilter_Cesql{
+									Cesql: &CESQL{
+										Expression: "subject = 'source'",
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, tc := range tt {
+		t.Run(tc.name, func(t *testing.T) {
+			got := FromSubscriptionFilter(tc.apiFilter)
+			if cmp.Diff(got, tc.want, cmpopts.IgnoreUnexported(DialectedFilter{},
+				All{}, Prefix{}, Suffix{}, Exact{}, Not{}, CESQL{})) != "" {
+				t.Errorf("FromSubscriptionFilter() = %v, want %v", got, tc.want)
+			}
+		})
+	}
+
+}
diff --git a/control-plane/pkg/reconciler/trigger/controller_test.go b/control-plane/pkg/reconciler/trigger/controller_test.go
index 48491fc93..7f7cf4741 100644
--- a/control-plane/pkg/reconciler/trigger/controller_test.go
+++ b/control-plane/pkg/reconciler/trigger/controller_test.go
@@ -20,19 +20,20 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	eventing "knative.dev/eventing/pkg/apis/eventing/v1"
-	brokerinformer "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker"
-	"knative.dev/pkg/configmap"
-
-	reconcilertesting "knative.dev/pkg/reconciler/testing"
 
-	_ "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker/fake"
-	_ "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/trigger/fake"
 	_ "knative.dev/pkg/client/injection/ducks/duck/v1/addressable/fake"
 	_ "knative.dev/pkg/client/injection/kube/informers/core/v1/configmap/fake"
 	_ "knative.dev/pkg/client/injection/kube/informers/core/v1/pod/fake"
 	_ "knative.dev/pkg/client/injection/kube/informers/core/v1/secret/fake"
+	"knative.dev/pkg/configmap"
+	reconcilertesting "knative.dev/pkg/reconciler/testing"
+
+	eventing "knative.dev/eventing/pkg/apis/eventing/v1"
+	brokerinformer "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker"
+	_ "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/broker/fake"
+	_ "knative.dev/eventing/pkg/client/injection/informers/eventing/v1/trigger/fake"
 
 	"knative.dev/eventing-kafka-broker/control-plane/pkg/config"
 	"knative.dev/eventing-kafka-broker/control-plane/pkg/kafka"
@@ -41,7 +42,11 @@ import (
 func TestNewController(t *testing.T) {
 	ctx, _ := reconcilertesting.SetupFakeContext(t)
 
-	controller := NewController(ctx, configmap.NewStaticWatcher(), &config.Env{})
+	controller := NewController(ctx, configmap.NewStaticWatcher(&corev1.ConfigMap{
+		ObjectMeta: metav1.ObjectMeta{
+			Name: "config-features",
+		},
+	}), &config.Env{})
 	if controller == nil {
 		t.Error("failed to create controller: <nil>")
 	}
diff --git a/control-plane/pkg/reconciler/trigger/trigger_test.go b/control-plane/pkg/reconciler/trigger/trigger_test.go
index 114f6a7db..a8471db73 100644
--- a/control-plane/pkg/reconciler/trigger/trigger_test.go
+++ b/control-plane/pkg/reconciler/trigger/trigger_test.go
@@ -22,32 +22,31 @@ import (
 	"testing"
 	"time"
 
+	"github.com/google/go-cmp/cmp"
 	"google.golang.org/protobuf/testing/protocmp"
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/types"
+	clientgotesting "k8s.io/client-go/testing"
 	"k8s.io/utils/pointer"
-	eventingduck "knative.dev/eventing/pkg/apis/duck/v1"
+	"knative.dev/pkg/apis"
 	duckv1 "knative.dev/pkg/apis/duck/v1"
+	kubeclient "knative.dev/pkg/client/injection/kube/client/fake"
+	"knative.dev/pkg/controller"
+	"knative.dev/pkg/logging"
+	. "knative.dev/pkg/reconciler/testing"
+	"knative.dev/pkg/resolver"
 	"knative.dev/pkg/tracker"
 
 	internals "knative.dev/eventing-kafka-broker/control-plane/pkg/apis/internals/kafka/eventing"
 	"knative.dev/eventing-kafka-broker/control-plane/pkg/config"
-
 	"knative.dev/eventing-kafka-broker/control-plane/pkg/contract"
-
-	"github.com/google/go-cmp/cmp"
-	corev1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/apimachinery/pkg/types"
-	clientgotesting "k8s.io/client-go/testing"
+	eventingduck "knative.dev/eventing/pkg/apis/duck/v1"
 	eventing "knative.dev/eventing/pkg/apis/eventing/v1"
+	"knative.dev/eventing/pkg/apis/feature"
 	eventingclient "knative.dev/eventing/pkg/client/injection/client/fake"
 	triggerreconciler "knative.dev/eventing/pkg/client/injection/reconciler/eventing/v1/trigger"
 	reconcilertesting "knative.dev/eventing/pkg/reconciler/testing/v1"
-	"knative.dev/pkg/apis"
-	kubeclient "knative.dev/pkg/client/injection/kube/client/fake"
-	"knative.dev/pkg/controller"
-	"knative.dev/pkg/logging"
-	. "knative.dev/pkg/reconciler/testing"
-	"knative.dev/pkg/resolver"
 
 	"knative.dev/eventing-kafka-broker/control-plane/pkg/receiver"
 	"knative.dev/eventing-kafka-broker/control-plane/pkg/reconciler/base"
@@ -80,17 +79,40 @@ var (
 	exponential = eventingduck.BackoffPolicyExponential
 )
 
+type EgressBuilder struct {
+	contract.Egress
+}
+
+func (b EgressBuilder) build(useDialectedFilters bool) *contract.Egress {
+	if useDialectedFilters {
+		b.Filter = nil
+	} else {
+		b.DialectedFilter = nil
+	}
+	return &b.Egress
+}
+
 func TestTriggerReconciler(t *testing.T) {
 	eventing.RegisterAlternateBrokerConditionSet(base.IngressConditionSet)
 
 	t.Parallel()
 
 	for _, f := range Formats {
-		triggerReconciliation(t, f, *DefaultEnv)
+		triggerReconciliation(t, f, *DefaultEnv, false)
+	}
+}
+
+func TestTriggerWithNewFiltersReconciler(t *testing.T) {
+	eventing.RegisterAlternateBrokerConditionSet(base.IngressConditionSet)
+
+	t.Parallel()
+
+	for _, f := range Formats {
+		triggerReconciliation(t, f, *DefaultEnv, true)
 	}
 }
 
-func triggerReconciliation(t *testing.T, format string, env config.Env) {
+func triggerReconciliation(t *testing.T, format string, env config.Env, useNewFilters bool) {
 
 	testKey := fmt.Sprintf("%s/%s", TriggerNamespace, TriggerName)
 
@@ -526,23 +548,45 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 							Topics:  []string{BrokerTopic()},
 							Ingress: &contract.Ingress{IngressType: &contract.Ingress_Path{Path: receiver.Path(BrokerNamespace, BrokerName)}},
 							Egresses: []*contract.Egress{
-								{
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source_value",
-									}},
-									Destination:   ServiceURL,
-									ConsumerGroup: TriggerUUID + "a",
-									Uid:           TriggerUUID + "a",
-								},
-								{
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source_value",
-									}},
-									Destination:   ServiceURL,
-									ConsumerGroup: TriggerUUID,
-									Uid:           TriggerUUID,
-									Reference:     TriggerReference(),
-								},
+								EgressBuilder{
+									contract.Egress{
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source_value",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source_value",
+													},
+												},
+											}},
+										},
+										Destination:   ServiceURL,
+										ConsumerGroup: TriggerUUID + "a",
+										Uid:           TriggerUUID + "a",
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source_value",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source_value",
+													},
+												},
+											}},
+										},
+										Destination:   ServiceURL,
+										ConsumerGroup: TriggerUUID,
+										Uid:           TriggerUUID,
+										Reference:     TriggerReference(),
+									},
+								}.build(useNewFilters),
 							},
 						},
 					},
@@ -578,14 +622,25 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 							Topics:  []string{BrokerTopic()},
 							Ingress: &contract.Ingress{IngressType: &contract.Ingress_Path{Path: receiver.Path(BrokerNamespace, BrokerName)}},
 							Egresses: []*contract.Egress{
-								{
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source_value",
-									}},
-									Destination:   ServiceURL,
-									ConsumerGroup: TriggerUUID + "a",
-									Uid:           TriggerUUID + "a",
-								},
+								EgressBuilder{
+									contract.Egress{
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source_value",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source_value",
+													},
+												},
+											}},
+										},
+										Destination:   ServiceURL,
+										ConsumerGroup: TriggerUUID + "a",
+										Uid:           TriggerUUID + "a",
+									},
+								}.build(useNewFilters),
 								{
 									Destination:   ServiceURL,
 									ConsumerGroup: TriggerUUID,
@@ -863,9 +918,17 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 					BrokerReady,
 				),
 				newTrigger(
-					withAttributes(map[string]string{
-						"type": "type1",
-					}),
+					withFilters(
+						map[string]string{"type": "type1"},
+						[]eventing.SubscriptionsAPIFilter{
+							{
+								Exact: map[string]string{
+									"type": "type1",
+								},
+							},
+						},
+						useNewFilters,
+					),
 				),
 				NewService(),
 				NewConfigMapFromContract(&contract.Contract{
@@ -875,15 +938,26 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 							Topics:  []string{BrokerTopic()},
 							Ingress: &contract.Ingress{IngressType: &contract.Ingress_Path{Path: receiver.Path(BrokerNamespace, BrokerName)}},
 							Egresses: []*contract.Egress{
-								{
-									Destination:   ServiceURL,
-									ConsumerGroup: TriggerUUID,
-									Uid:           TriggerUUID,
-									Reference:     TriggerReference(),
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"type": "type1",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"type": "type1",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"type": "type1",
+													},
+												},
+											}},
+										},
+										Destination:   ServiceURL,
+										ConsumerGroup: TriggerUUID,
+										Uid:           TriggerUUID,
+										Reference:     TriggerReference(),
+									},
+								}.build(useNewFilters),
 							},
 						},
 					},
@@ -901,9 +975,17 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 			WantStatusUpdates: []clientgotesting.UpdateActionImpl{
 				{
 					Object: newTrigger(
-						withAttributes(map[string]string{
-							"type": "type1",
-						}),
+						withFilters(
+							map[string]string{"type": "type1"},
+							[]eventing.SubscriptionsAPIFilter{
+								{
+									Exact: map[string]string{
+										"type": "type1",
+									},
+								},
+							},
+							useNewFilters,
+						),
 						reconcilertesting.WithInitTriggerConditions,
 						reconcilertesting.WithTriggerSubscribed(),
 						withSubscriberURI,
@@ -922,9 +1004,17 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 					BrokerReady,
 				),
 				newTrigger(
-					withAttributes(map[string]string{
-						"type": "type1",
-					}),
+					withFilters(
+						map[string]string{"type": "type1"},
+						[]eventing.SubscriptionsAPIFilter{
+							{
+								Exact: map[string]string{
+									"type": "type1",
+								},
+							},
+						},
+						useNewFilters,
+					),
 				),
 				NewService(),
 				NewConfigMapFromContract(&contract.Contract{
@@ -945,22 +1035,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 						{
@@ -978,22 +1090,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 					},
@@ -1015,36 +1149,69 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 							Topics:  []string{BrokerTopic()},
 							Ingress: &contract.Ingress{IngressType: &contract.Ingress_Path{Path: receiver.Path(BrokerNamespace, BrokerName)}},
 							Egresses: []*contract.Egress{
-								{
-									Destination:   ServiceURL,
-									ConsumerGroup: TriggerUUID,
-									Uid:           TriggerUUID,
-									Reference:     TriggerReference(),
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"type": "type1",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   ServiceURL,
+										ConsumerGroup: TriggerUUID,
+										Uid:           TriggerUUID,
+										Reference:     TriggerReference(),
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"type": "type1",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"type": "type1",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 								{
 									Destination:   "http://example.com/1",
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 						{
@@ -1062,22 +1229,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 					},
@@ -1090,9 +1279,17 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 			WantStatusUpdates: []clientgotesting.UpdateActionImpl{
 				{
 					Object: newTrigger(
-						withAttributes(map[string]string{
-							"type": "type1",
-						}),
+						withFilters(
+							map[string]string{"type": "type1"},
+							[]eventing.SubscriptionsAPIFilter{
+								{
+									Exact: map[string]string{
+										"type": "type1",
+									},
+								},
+							},
+							useNewFilters,
+						),
 						reconcilertesting.WithInitTriggerConditions,
 						reconcilertesting.WithTriggerSubscribed(),
 						withSubscriberURI,
@@ -1111,9 +1308,17 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 					BrokerReady,
 				),
 				newTrigger(
-					withAttributes(map[string]string{
-						"ext": "extval",
-					}),
+					withFilters(
+						map[string]string{"ext": "extval"},
+						[]eventing.SubscriptionsAPIFilter{
+							{
+								Exact: map[string]string{
+									"ext": "extval",
+								},
+							},
+						},
+						useNewFilters,
+					),
 				),
 				NewService(),
 				NewConfigMapFromContract(&contract.Contract{
@@ -1133,22 +1338,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 						{
@@ -1161,22 +1388,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 					},
@@ -1208,22 +1457,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 						{
@@ -1236,31 +1507,64 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
-								{
-									Destination:   ServiceURL,
-									ConsumerGroup: TriggerUUID,
-									Uid:           TriggerUUID,
-									Reference:     TriggerReference(),
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"ext": "extval",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   ServiceURL,
+										ConsumerGroup: TriggerUUID,
+										Uid:           TriggerUUID,
+										Reference:     TriggerReference(),
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"ext": "extval",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"ext": "extval",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 					},
@@ -1273,9 +1577,17 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 			WantStatusUpdates: []clientgotesting.UpdateActionImpl{
 				{
 					Object: newTrigger(
-						withAttributes(map[string]string{
-							"ext": "extval",
-						}),
+						withFilters(
+							map[string]string{"ext": "extval"},
+							[]eventing.SubscriptionsAPIFilter{
+								{
+									Exact: map[string]string{
+										"ext": "extval",
+									},
+								},
+							},
+							useNewFilters,
+						),
 						reconcilertesting.WithInitTriggerConditions,
 						reconcilertesting.WithTriggerSubscribed(),
 						withSubscriberURI,
@@ -1312,22 +1624,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 						{
@@ -1340,30 +1674,63 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   ServiceURL,
-									ConsumerGroup: TriggerUUID,
-									Uid:           TriggerUUID,
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   ServiceURL,
+										ConsumerGroup: TriggerUUID,
+										Uid:           TriggerUUID,
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 						{
@@ -1381,22 +1748,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 					},
@@ -1428,22 +1817,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 						{
@@ -1456,28 +1867,50 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 								{
 									Destination:   ServiceURL,
 									ConsumerGroup: TriggerUUID,
 									Uid:           TriggerUUID,
 									Reference:     TriggerReference(),
 								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 						{
@@ -1495,22 +1928,44 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 									ConsumerGroup: "1",
 									Uid:           "1",
 								},
-								{
-									Destination:   "http://example.com/2",
-									ConsumerGroup: "2",
-									Uid:           "2",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source2",
-									}},
-								},
-								{
-									Destination:   "http://example.com/3",
-									ConsumerGroup: "3",
-									Uid:           "3",
-									Filter: &contract.Filter{Attributes: map[string]string{
-										"source": "source3",
-									}},
-								},
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/2",
+										ConsumerGroup: "2",
+										Uid:           "2",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source2",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source2",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
+								EgressBuilder{
+									contract.Egress{
+										Destination:   "http://example.com/3",
+										ConsumerGroup: "3",
+										Uid:           "3",
+										Filter: &contract.Filter{Attributes: map[string]string{
+											"source": "source3",
+										}},
+										DialectedFilter: []*contract.DialectedFilter{
+											{Filter: &contract.DialectedFilter_Exact{
+												Exact: &contract.Exact{
+													Attributes: map[string]string{
+														"source": "source3",
+													},
+												},
+											}},
+										},
+									},
+								}.build(useNewFilters),
 							},
 						},
 					},
@@ -1565,7 +2020,11 @@ func triggerReconciliation(t *testing.T, format string, env config.Env) {
 		table[i].Name = table[i].Name + " - " + format
 	}
 
-	useTable(t, table, &env)
+	if useNewFilters {
+		useTableWithFlags(t, table, &env, map[string]feature.Flag{feature.NewTriggerFilters: feature.Enabled})
+	} else {
+		useTable(t, table, &env)
+	}
 }
 
 func withDelivery(trigger *eventing.Trigger) {
@@ -2283,6 +2742,10 @@ func triggerFinalizer(t *testing.T, format string, env config.Env) {
 }
 
 func useTable(t *testing.T, table TableTest, env *config.Env) {
+	useTableWithFlags(t, table, env, nil)
+}
+
+func useTableWithFlags(t *testing.T, table TableTest, env *config.Env, flags feature.Flags) {
 
 	table.Test(t, NewFactory(env, func(ctx context.Context, listers *Listers, env *config.Env, row *TableRow) controller.Reconciler {
 
@@ -2304,6 +2767,7 @@ func useTable(t *testing.T, table TableTest, env *config.Env) {
 			EventingClient: eventingclient.Get(ctx),
 			Resolver:       nil,
 			Env:            env,
+			Flags:          flags,
 		}
 
 		reconciler.Resolver = resolver.NewURIResolverFromTracker(ctx, tracker.New(func(name types.NamespacedName) {}, 0))
@@ -2339,10 +2803,14 @@ func newTrigger(options ...reconcilertesting.TriggerOption) runtime.Object {
 	)
 }
 
-func withAttributes(attributes eventing.TriggerFilterAttributes) func(*eventing.Trigger) {
+func withFilters(attributes eventing.TriggerFilterAttributes, newFilters []eventing.SubscriptionsAPIFilter, withNewFilters bool) func(*eventing.Trigger) {
 	return func(e *eventing.Trigger) {
-		e.Spec.Filter = &eventing.TriggerFilter{
-			Attributes: attributes,
+		if withNewFilters {
+			e.Spec.Filters = newFilters
+		} else {
+			e.Spec.Filter = &eventing.TriggerFilter{
+				Attributes: attributes,
+			}
 		}
 	}
 }
diff --git a/data-plane/core/src/test/java/dev/knative/eventing/kafka/broker/core/reconciler/impl/ResourcesReconcilerImplTest.java b/data-plane/core/src/test/java/dev/knative/eventing/kafka/broker/core/reconciler/impl/ResourcesReconcilerImplTest.java
index 5e55eaf45..a5a769957 100644
--- a/data-plane/core/src/test/java/dev/knative/eventing/kafka/broker/core/reconciler/impl/ResourcesReconcilerImplTest.java
+++ b/data-plane/core/src/test/java/dev/knative/eventing/kafka/broker/core/reconciler/impl/ResourcesReconcilerImplTest.java
@@ -695,6 +695,68 @@ class ResourcesReconcilerImplTest {
       .run();
   }
 
+  @Test
+  void reconcileEgressModifyingTheResourceWithDialectedFilters() {
+    new ResourceReconcilerTestRunner()
+      .enableEgressListener()
+      .reconcile(List.of(
+        baseResource("1-1234").build()
+      ))
+      .reconcile(List.of(
+        baseResource("1-1234")
+          .addEgresses(egress("aaa"))
+          .addEgresses(egress("bbb"))
+          .addEgresses(egress("ccc"))
+          .addEgresses(egress("ddd"))
+          .build()
+      ))
+      .expect()
+      .newEgress("aaa")
+      .newEgress("bbb")
+      .newEgress("ccc")
+      .newEgress("ddd")
+      .then()
+      .reconcile(List.of(
+        baseResource("1-1234")
+          .addEgresses(egress("aaa"))
+          .addEgresses(baseEgress("bbb").addDialectedFilter(DataPlaneContract.DialectedFilter.newBuilder().setExact(
+            DataPlaneContract.Exact.newBuilder().putAttributes("id", "hello").build()
+          )))
+          .addEgresses(baseEgress("ccc").addDialectedFilter(DataPlaneContract.DialectedFilter.newBuilder().setPrefix(
+            DataPlaneContract.Prefix.newBuilder().putAttributes("source", "dev.knative").build()
+          )))
+          .addEgresses(baseEgress("ddd").addDialectedFilter(DataPlaneContract.DialectedFilter.newBuilder().getAllBuilder()
+            .addFiltersBuilder().setPrefix(DataPlaneContract.Prefix.newBuilder().putAttributes("source", "dev.knative").build()).build()
+          ))
+          .build()
+      ))
+      .expect()
+      .updatedEgress("bbb")
+      .updatedEgress("ccc")
+      .updatedEgress("ddd")
+      .then()
+      .reconcile(List.of(
+        baseResource("1-1234")
+          .addEgresses(egress("aaa"))
+          .addEgresses(egress("ccc"))
+          .build()
+      ))
+      .expect()
+      .deletedEgress("bbb")
+      .deletedEgress("ddd")
+      .updatedEgress("ccc")
+      .then()
+      .reconcile(List.of(
+        baseResource("1-1234")
+          .build()
+      ))
+      .expect()
+      .deletedEgress("aaa")
+      .deletedEgress("ccc")
+      .then()
+      .run();
+  }
+
   @Test
   void reconcileEgressModifyingTheGlobalEgressConfig() {
     new ResourceReconcilerTestRunner()
diff --git a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AllFilterTest.java b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AllFilterTest.java
similarity index 77%
rename from data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AllFilterTest.java
rename to data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AllFilterTest.java
index 89e0e79b1..14c594521 100644
--- a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AllFilterTest.java
+++ b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AllFilterTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
 import dev.knative.eventing.kafka.broker.dispatcher.Filter;
 import io.cloudevents.CloudEvent;
@@ -22,6 +22,7 @@ import java.net.URI;
 import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
 import java.util.Collections;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Stream;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -55,10 +56,10 @@ public class AllFilterTest {
 
   static Stream<Arguments> testCases() {
     return Stream.of(
-      Arguments.of(event, new AllFilter(Set.of(new ExactFilter("id", "123-42"))), true),
-      Arguments.of(event, new AllFilter(Set.of(new ExactFilter("id", "123-42"), new ExactFilter("source", "/api/some-source"))), true),
-      Arguments.of(event, new AllFilter(Set.of(new ExactFilter("id", "123"), new ExactFilter("source", "/api/some-source"))), false),
-      Arguments.of(event, new AllFilter(Set.of(new ExactFilter("id", "123-42"), new ExactFilter("source", "/api/something-else"))), false),
+      Arguments.of(event, new AllFilter(Set.of(new ExactFilter(Map.of("id", "123-42")))), true),
+      Arguments.of(event, new AllFilter(Set.of(new ExactFilter(Map.of("id", "123-42")), new ExactFilter(Map.of("source", "/api/some-source")))), true),
+      Arguments.of(event, new AllFilter(Set.of(new ExactFilter(Map.of("id", "123")), new ExactFilter(Map.of("source", "/api/some-source")))), false),
+      Arguments.of(event, new AllFilter(Set.of(new ExactFilter(Map.of("id", "123-42")), new ExactFilter(Map.of("source", "/api/something-else")))), false),
       Arguments.of(event, new AllFilter(Collections.emptySet()), true)
     );
   }
diff --git a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AnyFilterTest.java b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AnyFilterTest.java
similarity index 72%
rename from data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AnyFilterTest.java
rename to data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AnyFilterTest.java
index 99ef54b95..960ee8c91 100644
--- a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AnyFilterTest.java
+++ b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/AnyFilterTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
 import dev.knative.eventing.kafka.broker.dispatcher.Filter;
 import io.cloudevents.CloudEvent;
@@ -22,6 +22,7 @@ import java.net.URI;
 import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
 import java.util.Collections;
+import java.util.Map;
 import java.util.Set;
 import java.util.stream.Stream;
 import org.junit.jupiter.params.ParameterizedTest;
@@ -55,11 +56,11 @@ public class AnyFilterTest {
 
   static Stream<Arguments> testCases() {
     return Stream.of(
-      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter("id", "123-42"))), true),
-      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter("id", "123-42"), new ExactFilter("source", "/api/some-source"))), true),
-      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter("id", "123"), new ExactFilter("source", "/api/some-source"))), true),
-      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter("id", "123-42"), new ExactFilter("source", "/api/something-else"))), true),
-      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter("id", "123"), new ExactFilter("source", "/api/something-else"))), false),
+      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter(Map.of("id", "123-42")))), true),
+      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter(Map.of("id", "123-42")), new ExactFilter(Map.of("source", "/api/some-source")))), true),
+      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter(Map.of("id", "123")), new ExactFilter(Map.of("source", "/api/some-source")))), true),
+      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter(Map.of("id", "123-42")), new ExactFilter(Map.of("source", "/api/something-else")))), true),
+      Arguments.of(event, new AnyFilter(Set.of(new ExactFilter(Map.of("id", "123")), new ExactFilter(Map.of("source", "/api/something-else")))), false),
       Arguments.of(event, new AnyFilter(Collections.emptySet()), false)
     );
   }
diff --git a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SqlFilterTest.java b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/CeSqlFilterTest.java
similarity index 95%
rename from data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SqlFilterTest.java
rename to data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/CeSqlFilterTest.java
index 314771bb0..487f75c9b 100644
--- a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SqlFilterTest.java
+++ b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/CeSqlFilterTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
 import io.cloudevents.CloudEvent;
 import io.cloudevents.core.builder.CloudEventBuilder;
@@ -27,7 +27,7 @@ import org.junit.jupiter.params.provider.MethodSource;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-public class SqlFilterTest {
+public class CeSqlFilterTest {
 
   final static CloudEvent event = CloudEventBuilder.v1()
     .withId("123-42")
@@ -46,7 +46,7 @@ public class SqlFilterTest {
   @ParameterizedTest
   @MethodSource(value = {"testCases"})
   public void match(CloudEvent event, String expression, boolean shouldMatch) {
-    var filter = new SqlFilter(expression);
+    var filter = new CeSqlFilter(expression);
     assertThat(filter.test(event))
       .isEqualTo(shouldMatch);
   }
diff --git a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AttributesFilterTest.java b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/ExactFilterTest.java
similarity index 97%
rename from data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AttributesFilterTest.java
rename to data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/ExactFilterTest.java
index 7bca39a3f..561af6d2d 100644
--- a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/AttributesFilterTest.java
+++ b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/ExactFilterTest.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
 import io.cloudevents.CloudEvent;
 import io.cloudevents.core.builder.CloudEventBuilder;
@@ -31,7 +31,7 @@ import org.junit.jupiter.params.provider.MethodSource;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
-public class AttributesFilterTest {
+public class ExactFilterTest {
 
   @ParameterizedTest
   @MethodSource(value = {"testCases"})
@@ -40,7 +40,7 @@ public class AttributesFilterTest {
     final CloudEvent event,
     final boolean shouldMatch) {
 
-    final var filter = new AttributesFilter(attributes);
+    final var filter = new ExactFilter(attributes);
 
     final var match = filter.test(event);
 
@@ -62,7 +62,7 @@ public class AttributesFilterTest {
       "type", ""
     );
 
-    final var filter = new AttributesFilter(attributes);
+    final var filter = new ExactFilter(attributes);
 
     final boolean match = filter.test(event);
 
@@ -87,7 +87,7 @@ public class AttributesFilterTest {
       "extension2", "valueExtension2"
     );
 
-    final var filter = new AttributesFilter(attributes);
+    final var filter = new ExactFilter(attributes);
 
     final boolean match = filter.test(event);
 
@@ -109,7 +109,7 @@ public class AttributesFilterTest {
       "extension2", "valueExtension"
     );
 
-    final var filter = new AttributesFilter(attributes);
+    final var filter = new ExactFilter(attributes);
 
     final boolean match = filter.test(event);
 
@@ -133,7 +133,7 @@ public class AttributesFilterTest {
       "type", ""
     );
 
-    final var filter = new AttributesFilter(attributes);
+    final var filter = new ExactFilter(attributes);
 
     final boolean match = filter.test(event);
 
diff --git a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/ExactFilterTest.java b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/NotFilterTest.java
similarity index 56%
rename from data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/ExactFilterTest.java
rename to data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/NotFilterTest.java
index cdc951671..e9067ee4e 100644
--- a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/ExactFilterTest.java
+++ b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/NotFilterTest.java
@@ -13,24 +13,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
+import dev.knative.eventing.kafka.broker.dispatcher.Filter;
 import io.cloudevents.CloudEvent;
 import io.cloudevents.core.builder.CloudEventBuilder;
 import java.net.URI;
 import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
+import java.util.Map;
 import java.util.stream.Stream;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
 import org.junit.jupiter.params.provider.MethodSource;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-public class ExactFilterTest {
 
+public class NotFilterTest {
   final static CloudEvent event = CloudEventBuilder.v1()
     .withId("123-42")
     .withDataContentType("application/cloudevents+json")
@@ -43,45 +42,19 @@ public class ExactFilterTest {
       23, 20, 50, 0,
       ZoneOffset.UTC
     ))
-    .withExtension("abc", "123")
-    .withExtension("urlext", URI.create("/ext"))
     .build();
 
-  @Test
-  public void testInvalidKey() {
-    assertThatThrownBy(() -> new ExactFilter(null, "123"))
-      .isInstanceOf(IllegalArgumentException.class);
-    assertThatThrownBy(() -> new ExactFilter("", "123"))
-      .isInstanceOf(IllegalArgumentException.class);
-  }
-
-  @Test
-  public void testInvalidValue() {
-    assertThatThrownBy(() -> new ExactFilter("abc", null))
-      .isInstanceOf(IllegalArgumentException.class);
-    assertThatThrownBy(() -> new ExactFilter("abc", ""))
-      .isInstanceOf(IllegalArgumentException.class);
-  }
-
   @ParameterizedTest
   @MethodSource(value = {"testCases"})
-  public void match(CloudEvent event, String key, String value, boolean shouldMatch) {
-    var filter = new ExactFilter(key, value);
+  public void match(CloudEvent event, Filter filter, boolean shouldMatch) {
     assertThat(filter.test(event))
       .isEqualTo(shouldMatch);
   }
 
   static Stream<Arguments> testCases() {
     return Stream.of(
-      Arguments.of(event, "id", "123-42", true),
-      Arguments.of(event, "id", "123-43", false),
-      Arguments.of(event, "source", "/api/some-source", true),
-      Arguments.of(event, "source", "/api/something-else", false),
-      Arguments.of(event, "abc", "123", true),
-      Arguments.of(event, "abc", "456", false),
-      Arguments.of(event, "urlext", "/ext", true),
-      Arguments.of(event, "urlext", "/no-ext", false)
+      Arguments.of(event, new NotFilter(new ExactFilter(Map.of("id", "123-42"))), false),
+      Arguments.of(event, new NotFilter(new ExactFilter(Map.of("source", "/api/wrong-source"))), true)
     );
   }
-
 }
diff --git a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/PrefixFilterTest.java b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/PrefixFilterTest.java
similarity index 95%
rename from data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/PrefixFilterTest.java
rename to data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/PrefixFilterTest.java
index 66c07b37c..9eabc6306 100644
--- a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/PrefixFilterTest.java
+++ b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/PrefixFilterTest.java
@@ -13,13 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
 import io.cloudevents.CloudEvent;
 import io.cloudevents.core.builder.CloudEventBuilder;
 import java.net.URI;
 import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
+import java.util.Map;
 import java.util.stream.Stream;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
@@ -46,7 +47,7 @@ public class PrefixFilterTest {
   @ParameterizedTest
   @MethodSource(value = {"testCases"})
   public void match(CloudEvent event, String key, String value, boolean shouldMatch) {
-    var filter = new PrefixFilter(key, value);
+    var filter = new PrefixFilter(Map.of(key, value));
     assertThat(filter.test(event))
       .isEqualTo(shouldMatch);
   }
diff --git a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SuffixFilterTest.java b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/SuffixFilterTest.java
similarity index 95%
rename from data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SuffixFilterTest.java
rename to data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/SuffixFilterTest.java
index 6753a1cb8..b07c3ec60 100644
--- a/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/SuffixFilterTest.java
+++ b/data-plane/dispatcher/src/test/java/dev/knative/eventing/kafka/broker/dispatcher/impl/filter/subscriptionsapi/SuffixFilterTest.java
@@ -13,13 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package dev.knative.eventing.kafka.broker.dispatcher.impl.filter;
+package dev.knative.eventing.kafka.broker.dispatcher.impl.filter.subscriptionsapi;
 
 import io.cloudevents.CloudEvent;
 import io.cloudevents.core.builder.CloudEventBuilder;
 import java.net.URI;
 import java.time.OffsetDateTime;
 import java.time.ZoneOffset;
+import java.util.Map;
 import java.util.stream.Stream;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.Arguments;
@@ -46,7 +47,7 @@ public class SuffixFilterTest {
   @ParameterizedTest
   @MethodSource(value = {"testCases"})
   public void match(CloudEvent event, String key, String value, boolean shouldMatch) {
-    var filter = new SuffixFilter(key, value);
+    var filter = new SuffixFilter(Map.of(key, value));
     assertThat(filter.test(event))
       .isEqualTo(shouldMatch);
   }
diff --git a/test/experimental/features_config/features.yaml b/test/experimental/features_config/features.yaml
new file mode 100644
index 000000000..dd4b493d4
--- /dev/null
+++ b/test/experimental/features_config/features.yaml
@@ -0,0 +1,29 @@
+# Copyright 2021 The Knative 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
+#
+#     https://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.
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: config-features
+  namespace: knative-eventing
+  labels:
+    eventing.knative.dev/release: devel
+    knative.dev/config-propagation: original
+    knative.dev/config-category: eventing
+data:
+  kreference-group: "disabled"
+  delivery-retryafter: "disabled"
+  delivery-timeout: "disabled"
+  strict-subscriber: "disabled"
+  new-trigger-filters: "enabled"
diff --git a/test/experimental/features_config/install.go b/test/experimental/features_config/install.go
new file mode 100644
index 000000000..623066464
--- /dev/null
+++ b/test/experimental/features_config/install.go
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2021 The Knative 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 features_config
+
+import (
+	"context"
+
+	"knative.dev/reconciler-test/pkg/feature"
+	"knative.dev/reconciler-test/pkg/manifest"
+)
+
+func Install(ctx context.Context, t feature.T) {
+	if _, err := manifest.InstallLocalYaml(ctx, map[string]interface{}{}); err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/test/experimental/main_test.go b/test/experimental/main_test.go
new file mode 100644
index 000000000..f9d653c99
--- /dev/null
+++ b/test/experimental/main_test.go
@@ -0,0 +1,65 @@
+//go:build e2e
+// +build e2e
+
+/*
+ * Copyright 2021 The Knative 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 experimental
+
+import (
+	"flag"
+	"os"
+	"testing"
+
+	// Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters).
+	_ "k8s.io/client-go/plugin/pkg/client/auth/gcp"
+	"knative.dev/pkg/injection"
+	_ "knative.dev/pkg/system/testing"
+
+	"knative.dev/reconciler-test/pkg/environment"
+)
+
+// global is the singleton instance of GlobalEnvironment. It is used to parse
+// the testing config for the test run. The config will specify the cluster
+// config as well as the parsing level and state flags.
+var global environment.GlobalEnvironment
+
+func init() {
+	// environment.InitFlags registers state and level filter flags.
+	environment.InitFlags(flag.CommandLine)
+}
+
+// TestMain is the first entry point for `go test`.
+func TestMain(m *testing.M) {
+	// We get a chance to parse flags to include the framework flags for the
+	// framework as well as any additional flags included in the integration.
+	flag.Parse()
+
+	// EnableInjectionOrDie will enable client injection, this is used by the
+	// testing framework for namespace management, and could be leveraged by
+	// features to pull Kubernetes clients or the test environment out of the
+	// context passed in the features.
+	ctx, startInformers := injection.EnableInjectionOrDie(nil, nil) //nolint
+
+	startInformers()
+
+	// global is used to make instances of Environments, NewGlobalEnvironment
+	// is passing and saving the client injection enabled context for use later.
+	global = environment.NewGlobalEnvironment(ctx)
+
+	// Run the tests.
+	os.Exit(m.Run())
+}
diff --git a/test/experimental/new_trigger_filters_test.go b/test/experimental/new_trigger_filters_test.go
new file mode 100644
index 000000000..ec2942d52
--- /dev/null
+++ b/test/experimental/new_trigger_filters_test.go
@@ -0,0 +1,68 @@
+//go:build e2e
+// +build e2e
+
+/*
+ * Copyright 2021 The Knative 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 experimental
+
+import (
+	"testing"
+
+	"knative.dev/pkg/system"
+	"knative.dev/reconciler-test/pkg/environment"
+	"knative.dev/reconciler-test/pkg/feature"
+	"knative.dev/reconciler-test/pkg/k8s"
+	"knative.dev/reconciler-test/pkg/knative"
+
+	"knative.dev/eventing-kafka-broker/control-plane/pkg/kafka"
+	"knative.dev/eventing-kafka-broker/test/e2e_new/single_partition_config"
+	"knative.dev/eventing-kafka-broker/test/experimental/features_config"
+
+	newfilters "knative.dev/eventing/test/experimental/features/new_trigger_filters"
+	"knative.dev/eventing/test/rekt/resources/broker"
+)
+
+func TestNewTriggerFilters(t *testing.T) {
+	t.Parallel()
+
+	ctx, env := global.Environment(
+		knative.WithKnativeNamespace(system.Namespace()),
+		knative.WithLoggingConfig,
+		knative.WithTracingConfig,
+		k8s.WithEventListener,
+		environment.Managed(t),
+	)
+	brokerName := feature.MakeRandomK8sName("broker")
+
+	env.Prerequisite(ctx, t, InstallKafkaBrokerWithExperimentalFeatures(brokerName))
+	env.TestSet(ctx, t, newfilters.FiltersFeatureSet(brokerName))
+}
+
+func InstallKafkaBrokerWithExperimentalFeatures(name string) *feature.Feature {
+	f := feature.NewFeatureNamed("Kafka broker")
+	f.Setup("enable new trigger filters experimental feature", features_config.Install)
+	f.Setup("install one partition configuration", single_partition_config.Install)
+	f.Setup("install broker", broker.Install(
+		name,
+		broker.WithBrokerClass(kafka.BrokerClass),
+		broker.WithConfig(single_partition_config.ConfigMapName),
+	))
+	f.Setup("broker is ready", broker.IsReady(name))
+	f.Setup("broker is addressable", broker.IsAddressable(name))
+
+	return f
+}
diff --git a/vendor/knative.dev/eventing/test/experimental/features/new_trigger_filters/filters.go b/vendor/knative.dev/eventing/test/experimental/features/new_trigger_filters/filters.go
new file mode 100644
index 000000000..7eae91b09
--- /dev/null
+++ b/vendor/knative.dev/eventing/test/experimental/features/new_trigger_filters/filters.go
@@ -0,0 +1,123 @@
+/*
+Copyright 2022 The Knative 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 new_trigger_filters
+
+import (
+	"context"
+	"fmt"
+
+	. "github.com/cloudevents/sdk-go/v2/test"
+	"knative.dev/reconciler-test/pkg/eventshub"
+	. "knative.dev/reconciler-test/pkg/eventshub/assert"
+	"knative.dev/reconciler-test/pkg/feature"
+	"knative.dev/reconciler-test/pkg/manifest"
+	"knative.dev/reconciler-test/resources/svc"
+
+	"knative.dev/eventing/test/rekt/resources/broker"
+	"knative.dev/eventing/test/rekt/resources/trigger"
+)
+
+// FiltersFeatureSet creates a feature set for testing the broker implementation of the new trigger filters experimental feature
+// (aka Cloud Events Subscriptions API filters). It requires a created and ready Broker resource with brokerName.
+//
+// The feature set tests four filter dialects: exact, prefix, suffix and cesql (aka CloudEvents SQL).
+func FiltersFeatureSet(brokerName string) *feature.FeatureSet {
+	matchedEvent := FullEvent()
+	unmatchedEvent := MinEvent()
+	unmatchedEvent.SetType("org.wrong.type")
+	unmatchedEvent.SetSource("org.wrong.source")
+
+	features := make([]*feature.Feature, 0, 8)
+	tests := map[string]struct {
+		filters string
+		step    feature.StepFn
+	}{
+		"Exact filter": {
+			filters: fmt.Sprintf(snippetFor("exact"), matchedEvent.Type(), matchedEvent.Source()),
+		},
+		"Prefix filter": {
+			filters: fmt.Sprintf(snippetFor("prefix"), matchedEvent.Type()[:4], matchedEvent.Source()[:4]),
+		},
+		"Suffix filter": {
+			filters: fmt.Sprintf(snippetFor("suffix"), matchedEvent.Type()[5:], matchedEvent.Source()[5:]),
+		},
+		"CloudEvents SQL filter": {
+			filters: fmt.Sprintf(`- cesql: "type = '%s' AND source = '%s'" `, matchedEvent.Type(), matchedEvent.Source()),
+		},
+	}
+
+	for name, fs := range tests {
+		matchedSender := feature.MakeRandomK8sName("sender")
+		unmatchedSender := feature.MakeRandomK8sName("sender")
+		subscriber := feature.MakeRandomK8sName("subscriber")
+		triggerName := feature.MakeRandomK8sName("viaTrigger")
+
+		f := feature.NewFeatureNamed(name)
+
+		f.Setup("Install trigger subscriber", eventshub.Install(subscriber, eventshub.StartReceiver))
+
+		// Set the Trigger subscriber.
+		cfg := []manifest.CfgFn{
+			trigger.WithSubscriber(svc.AsKReference(subscriber), ""),
+			WithNewFilters(fs.filters),
+		}
+
+		f.Setup("Install trigger", trigger.Install(triggerName, brokerName, cfg...))
+		f.Setup("Wait for trigger to become ready", trigger.IsReady(triggerName))
+
+		f.Requirement("Install matched event sender", func(ctx context.Context, t feature.T) {
+			u, err := broker.Address(ctx, brokerName)
+			if err != nil || u == nil {
+				t.Error("failed to get the address of the broker", brokerName, err)
+			}
+			eventshub.Install(matchedSender, eventshub.StartSenderURL(u.String()), eventshub.InputEvent(matchedEvent))(ctx, t)
+		})
+
+		f.Requirement("Install unmatched event sender", func(ctx context.Context, t feature.T) {
+			u, err := broker.Address(ctx, brokerName)
+			if err != nil || u == nil {
+				t.Error("failed to get the address of the broker", brokerName, err)
+			}
+			eventshub.Install(unmatchedSender, eventshub.StartSenderURL(u.String()), eventshub.InputEvent(unmatchedEvent))(ctx, t)
+		})
+
+		f.Alpha("Triggers with new filters").
+			Must("must deliver matched events", OnStore(subscriber).MatchEvent(HasId(matchedEvent.ID())).AtLeast(1)).
+			MustNot("must not deliver unmatched events", OnStore(subscriber).MatchEvent(HasId(unmatchedEvent.ID())).Not())
+		features = append(features, f)
+	}
+
+	return &feature.FeatureSet{
+		Name:     "New trigger filters",
+		Features: features,
+	}
+}
+
+func snippetFor(key string) string {
+	return fmt.Sprintf(`
+    - %s:
+        type: %%s
+    - %s:
+        source: %%s`, key, key)
+}
+
+// WithNewFilters adds a filter config to a Trigger spec using the new filters API.
+func WithNewFilters(filters string) manifest.CfgFn {
+	return func(cfg map[string]interface{}) {
+		cfg["filters"] = filters
+	}
+}