Skip to content

hack: reject proto changes that break binary wire compatibility - #1607

Open
haiyanmeng wants to merge 3 commits into
agent-substrate:mainfrom
haiyanmeng:proto-wire-compat-guard
Open

haiyanmeng wants to merge 3 commits into
agent-substrate:mainfrom
haiyanmeng:proto-wire-compat-guard

Conversation

@haiyanmeng

@haiyanmeng haiyanmeng commented Sep 11, 2026 •

Copy link
Copy Markdown
Collaborator

ateapi stores resources as binary protobuf in bytea columns. Binary protobuf identifies a field only by its number. If a field is renumbered, existing rows lose its value. If a retired number is reused, existing rows decode into the wrong field. atepg.go unmarshals with DiscardUnknown: true, so the original bytes are dropped on the next read-modify-write. Nothing reports this at runtime.

  • hack/tools/buf: adds buf v1.72.0 as a tool module, run through hack/run-tool.sh.
  • buf.yaml: checks the protos under api/ and internal/proto/ with buf's WIRE breaking rules, until there is a policy for internal protos. They reject renumbering a field, wire-incompatible type changes, and deleting a field without reserving its number. Field renames are allowed. Renaming a message used as a field type is rejected, because buf compares field types by name. WIRE_JSON would also pin names, which is too strict while the API is unreleased.
  • hack/verify/proto-breaking.sh: runs buf breaking on the working tree against the merge base of HEAD and origin/main (or main). CI checks out with fetch-depth: 0, so the merge base is available there. It passes --against-config buf.yaml so a baseline commit without buf.yaml still builds.
  • AGENTS.md: removes the Backward Compatibility section. Breaking changes are no longer acceptable once this check is in.
  • hack/verify-all.sh: runs every verifier and lists the failures at the end, instead of stopping at the first one. This is to make sure the CI runs every verifier on a PR including breaking proto changes. I can split this into its own PR if you prefer.

I used Claude Code to help write the change and this description.

@juli4n

Copy link
Copy Markdown
Collaborator

I'm not sure if we are there yet for something like this.

We are intentionally making breaking changes to the API. Does preserving IDs really give us any guaranty about backward compatibility? I don't think, unless we design every change in a way that is backwards compatible, and we are not doing that on main.

Tim Hockin (@thockin) thoughts?

@haiyanmeng

Copy link
Copy Markdown
Collaborator Author

I'm not sure if we are there yet for something like this.

We are intentionally making breaking changes to the API. Does preserving IDs really give us any guaranty about backward compatibility? I don't think, unless we design every change in a way that is backwards compatible, and we are not doing that on main.

Tim Hockin (Tim Hockin (@thockin)) thoughts?

Julian Gutierrez Oschmann (@juli4n) , this PR has two commits. The commit for reserving field numbers retired without a reserved declaration seems useful. The commit for adding a test rejecting proto changes that break binary wire compatibility may not be a good fit for where we are. Happy to scope down the PR to what is needed or close it.

A little bit context of how I got here. I am renaming an API field in #1597 and realize that some field numbers are retired but not reserved.

@thockin Tim Hockin (thockin) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the test, though it's not quite obvious if there's a calling convention?

We will probably renumber all the tags before we go GA, how do we do that on purpose?

When I run this I get a boatload of warnings and it fails:

benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/any.proto:128:9:`Any` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/api.proto:59:9:`Api` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/compiler/plugin.proto:33:9:`Version` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/cpp_features.proto:15:24:`cpp` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/cpp_features.proto:18:9:`CppFeatures` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:129:24:`options` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:167:36:`options` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:173:27:`options` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:193:32:`uninterpreted_option` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:197:20:`number` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:201:21:`full_name` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:206:21:`type` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:211:19:`reserved` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:215:19:`repeated` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:223:24:`declaration` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:238:30:`verification` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:324:19:`json_name` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:326:25:`options` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:355:25:`options` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:364:24:`options` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:395:29:`options` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:403:27:`options` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:418:26:`options` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:479:17:`java_multiple_files` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:494:17:`java_string_check_utf8` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:503:25:`optimize_for` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:532:17:`deprecated` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:578:32:`uninterpreted_option` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:606:17:`message_set_wire_format` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:617:17:`deprecated` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:642:17:`map_entry` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:666:32:`uninterpreted_option` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:680:18:`ctype` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:702:17:`packed` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:715:19:`jstype` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:749:17:`lazy` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:754:17:`unverified_lazy` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:760:17:`deprecated` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:795:29:`targets` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:798:22:`edition` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:799:21:`value` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:801:27:`edition_defaults` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:814:22:`edition_introduced` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:818:22:`edition_deprecated` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:822:21:`deprecation_warning` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:827:22:`edition_removed` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:829:27:`feature_support` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:832:32:`uninterpreted_option` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:849:32:`uninterpreted_option` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:859:17:`allow_alias` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:865:17:`deprecated` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:884:32:`uninterpreted_option` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:895:17:`deprecated` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:912:32:`uninterpreted_option` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:935:17:`deprecated` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:938:32:`uninterpreted_option` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:955:17:`deprecated` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:975:32:`uninterpreted_option` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/descriptor.proto:1018:9:`FeatureSet` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/duration.proto:102:9:`Duration` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/empty.proto:51:9:`Empty` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/field_mask.proto:242:9:`FieldMask` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/go_features.proto:17:23:`go` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/go_features.proto:20:9:`GoFeatures` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/java_features.proto:19:25:`java` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/java_features.proto:22:9:`JavaFeatures` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/source_context.proto:44:9:`SourceContext` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/struct.proto:51:9:`Struct` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/timestamp.proto:133:9:`Timestamp` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/type.proto:52:9:`Type` declared multiple times
benchmarking/locust/codegen/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/wrappers.proto:66:9:`DoubleValue` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/annotations.proto:19:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/annotations.proto:30:3:cannot find `HttpRule` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/annotations.proto:30:12:`http` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/auth.proto:43:9:`Authentication` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/backend.proto:26:9:`Backend` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/billing.proto:57:9:`Billing` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/client.proto:19:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/client.proto:65:19:`method_signature` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/client.proto:78:10:`default_host` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/client.proto:100:10:`oauth_scopes` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/client.proto:116:10:`api_version` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/client.proto:120:9:`CommonLanguageSettings` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/client.proto:142:3:cannot find `LaunchStage` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/config_change.proto:31:9:`ConfigChange` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/consumer.proto:40:9:`ProjectProperties` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/context.proto:61:9:`Context` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/control.proto:19:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/control.proto:33:9:`Control` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/control.proto:40:12:cannot find `MethodPolicy` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/distribution.proto:42:9:`Distribution` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/documentation.proto:80:9:`Documentation` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/endpoint.proto:46:9:`Endpoint` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:35:6:`ErrorReason` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:37:3:`ERROR_REASON_UNSPECIFIED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:54:3:`SERVICE_DISABLED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:71:3:`BILLING_DISABLED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:86:3:`API_KEY_INVALID` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:102:3:`API_KEY_SERVICE_BLOCKED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:118:3:`API_KEY_HTTP_REFERRER_BLOCKED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:134:3:`API_KEY_IP_ADDRESS_BLOCKED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:150:3:`API_KEY_ANDROID_APP_BLOCKED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:166:3:`API_KEY_IOS_APP_BLOCKED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:201:3:`RATE_LIMIT_EXCEEDED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:235:3:`RESOURCE_QUOTA_EXCEEDED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:256:3:`LOCATION_TAX_POLICY_VIOLATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:273:3:`USER_PROJECT_DENIED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:290:3:`CONSUMER_SUSPENDED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:305:3:`CONSUMER_INVALID` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:326:3:`SECURITY_POLICY_VIOLATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:340:3:`ACCESS_TOKEN_EXPIRED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:359:3:`ACCESS_TOKEN_SCOPE_INSUFFICIENT` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:381:3:`ACCOUNT_STATE_INVALID` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:396:3:`ACCESS_TOKEN_TYPE_UNSUPPORTED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:413:3:`CREDENTIALS_MISSING` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:432:3:`RESOURCE_PROJECT_INVALID` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:448:3:`SESSION_COOKIE_INVALID` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:465:3:`USER_BLOCKED_BY_ADMIN` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:482:3:`RESOURCE_USAGE_RESTRICTION_VIOLATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:500:3:`SYSTEM_PARAMETER_UNSUPPORTED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:517:3:`ORG_RESTRICTION_VIOLATION` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:534:3:`ORG_RESTRICTION_HEADER_INVALID` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:553:3:`SERVICE_NOT_VISIBLE` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:569:3:`GCP_SUSPENDED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:588:3:`LOCATION_POLICY_VIOLATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:604:3:`MISSING_ORIGIN` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:621:3:`OVERLOADED_CREDENTIALS` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:641:3:`LOCATION_ORG_POLICY_VIOLATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:660:3:`TLS_ORG_POLICY_VIOLATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:676:3:`EMULATOR_QUOTA_EXCEEDED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:691:3:`CREDENTIAL_ANDROID_APP_INVALID` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:706:3:`IAM_PERMISSION_DENIED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:720:3:`JWT_TOKEN_INVALID` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:735:3:`CREDENTIAL_TYPE_UNSUPPORTED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:749:3:`ACCOUNT_TYPE_UNSUPPORTED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:769:3:`ENDPOINT_USAGE_RESTRICTION_VIOLATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:789:3:`TLS_CIPHER_RESTRICTION_VIOLATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/error_reason.proto:806:3:`MCP_SERVER_DISABLED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:40:37:`field_behavior` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:49:6:`FieldBehavior` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:51:3:`FIELD_BEHAVIOR_UNSPECIFIED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:56:3:`OPTIONAL` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:61:3:`REQUIRED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:67:3:`OUTPUT_ONLY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:72:3:`INPUT_ONLY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:77:3:`IMMUTABLE` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:83:3:`UNORDERED_LIST` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:89:3:`NON_EMPTY_DEFAULT` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:103:3:`IDENTIFIER` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_info.proto:45:24:`field_info` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/field_info.proto:49:9:`FieldInfo` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/http.proto:28:9:`Http` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/httpbody.proto:70:9:`HttpBody` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/label.proto:26:9:`LabelDescriptor` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/launch_stage.proto:27:6:`LaunchStage` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/launch_stage.proto:29:3:`LAUNCH_STAGE_UNSPECIFIED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/launch_stage.proto:32:3:`UNIMPLEMENTED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/launch_stage.proto:35:3:`PRELAUNCH` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/launch_stage.proto:42:3:`EARLY_ACCESS` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/launch_stage.proto:53:3:`ALPHA` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/launch_stage.proto:60:3:`BETA` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/launch_stage.proto:64:3:`GA` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/launch_stage.proto:71:3:`DEPRECATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/log.proto:19:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/log.proto:35:9:`LogDescriptor` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/log.proto:45:12:cannot find `LabelDescriptor` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/logging.proto:54:9:`Logging` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/metric.proto:19:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/metric.proto:20:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/metric.proto:33:9:`MetricDescriptor` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/metric.proto:101:5:cannot find `LaunchStage` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/metric.proto:138:12:cannot find `LabelDescriptor` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/metric.proto:265:3:cannot find `LaunchStage` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/monitored_resource.proto:19:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/monitored_resource.proto:20:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/monitored_resource.proto:40:9:`MonitoredResourceDescriptor` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/monitored_resource.proto:70:12:cannot find `LabelDescriptor` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/monitored_resource.proto:73:3:cannot find `LaunchStage` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/monitoring.proto:77:9:`Monitoring` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/policy.proto:29:26:`field_policy` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/policy.proto:34:27:`method_policy` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/policy.proto:45:9:`FieldPolicy` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/quota.proto:76:9:`Quota` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/resource.proto:30:32:`resource_reference` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/resource.proto:36:42:`resource_definition` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/resource.proto:42:33:`resource` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/resource.proto:92:9:`ResourceDescriptor` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/routing.proto:29:26:`routing` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/routing.proto:395:9:`RoutingRule` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:19:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:20:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:21:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:22:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:23:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:24:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:25:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:26:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:27:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:28:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:29:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:30:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:31:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:32:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:33:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:34:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:35:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:36:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:80:9:`Service` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:127:3:cannot find `Documentation` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:130:3:cannot find `Backend` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:133:3:cannot find `Http` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:136:3:cannot find `Quota` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:139:3:cannot find `Authentication` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:142:3:cannot find `Context` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:145:3:cannot find `Usage` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:150:12:cannot find `Endpoint` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:153:3:cannot find `Control` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:156:12:cannot find `LogDescriptor` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:159:12:cannot find `MetricDescriptor` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:163:12:cannot find `MonitoredResourceDescriptor` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:166:3:cannot find `Billing` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:169:3:cannot find `Logging` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:172:3:cannot find `Monitoring` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:175:3:cannot find `SystemParameters` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:178:3:cannot find `SourceInfo` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/service.proto:183:3:cannot find `Publishing` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/source_info.proto:28:9:`SourceInfo` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/system_parameter.proto:31:9:`SystemParameters` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/usage.proto:26:9:`Usage` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/visibility.proto:29:29:`enum_visibility` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/visibility.proto:34:29:`value_visibility` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/visibility.proto:39:29:`field_visibility` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/visibility.proto:44:29:`message_visibility` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/visibility.proto:49:29:`method_visibility` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/visibility.proto:54:29:`api_visibility` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/api/visibility.proto:80:9:`Visibility` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:22:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:25:9:cannot find `google.api.resource_definition` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:31:9:cannot find `google.api.resource_definition` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:37:9:cannot find `google.api.resource_definition` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:43:9:cannot find `google.api.resource_definition` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:48:9:cannot find `google.api.resource_definition` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:65:28:`operation_field` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:76:10:`operation_request_field` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:87:10:`operation_response_field` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:116:10:`operation_service` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:120:8:`operation_polling_method` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:127:6:`OperationResponseMapping` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:129:3:`UNDEFINED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:133:3:`NAME` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:141:3:`STATUS` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:145:3:`ERROR_CODE` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:149:3:`ERROR_MESSAGE` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:19:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:21:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:32:9:`Locations` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:33:11:cannot find `google.api.default_host` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:34:11:cannot find `google.api.oauth_scopes` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:38:13:cannot find `google.api.http` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:48:13:cannot find `google.api.http` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/gapic/metadata/gapic_metadata.proto:30:9:`GapicMetadata` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/http_request.proto:32:9:`HttpRequest` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:43:6:`LogSeverity` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:45:3:`DEFAULT` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:48:3:`DEBUG` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:51:3:`INFO` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:55:3:`NOTICE` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:58:3:`WARNING` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:61:3:`ERROR` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:64:3:`CRITICAL` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:67:3:`ALERT` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/logging/type/log_severity.proto:70:3:`EMERGENCY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:19:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:20:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:25:1:imported file does not exist
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:43:36:`operation_info` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:55:9:`Operations` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:56:11:cannot find `google.api.default_host` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:61:13:cannot find `google.api.http` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:64:13:cannot find `google.api.method_signature` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:71:13:cannot find `google.api.http` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:74:13:cannot find `google.api.method_signature` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:82:13:cannot find `google.api.http` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:85:13:cannot find `google.api.method_signature` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:100:13:cannot find `google.api.http` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:104:13:cannot find `google.api.method_signature` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:144:5:cannot find `google.rpc.Status` in this scope
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:32:6:`Code` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:36:3:`OK` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:41:3:`CANCELLED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:50:3:`UNKNOWN` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:58:3:`INVALID_ARGUMENT` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:67:3:`DEADLINE_EXCEEDED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:78:3:`NOT_FOUND` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:84:3:`ALREADY_EXISTS` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:96:3:`PERMISSION_DENIED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:102:3:`UNAUTHENTICATED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:108:3:`RESOURCE_EXHAUSTED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:128:3:`FAILED_PRECONDITION` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:137:3:`ABORTED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:156:3:`OUT_OF_RANGE` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:162:3:`UNIMPLEMENTED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:169:3:`INTERNAL` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:180:3:`UNAVAILABLE` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/code.proto:185:3:`DATA_LOSS` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/context/attribute_context.proto:46:9:`AttributeContext` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/context/audit_context.proto:27:9:`AuditContext` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/error_details.proto:51:9:`ErrorInfo` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/http.proto:26:9:`HttpRequest` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/rpc/status.proto:34:9:`Status` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/calendar_period.proto:28:6:`CalendarPeriod` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/calendar_period.proto:30:3:`CALENDAR_PERIOD_UNSPECIFIED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/calendar_period.proto:33:3:`DAY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/calendar_period.proto:37:3:`WEEK` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/calendar_period.proto:42:3:`FORTNIGHT` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/calendar_period.proto:45:3:`MONTH` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/calendar_period.proto:49:3:`QUARTER` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/calendar_period.proto:52:3:`HALF` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/calendar_period.proto:55:3:`YEAR` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/color.proto:151:9:`Color` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/date.proto:41:9:`Date` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/datetime.proto:51:9:`DateTime` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/dayofweek.proto:26:6:`DayOfWeek` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/dayofweek.proto:28:3:`DAY_OF_WEEK_UNSPECIFIED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/dayofweek.proto:31:3:`MONDAY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/dayofweek.proto:34:3:`TUESDAY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/dayofweek.proto:37:3:`WEDNESDAY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/dayofweek.proto:40:3:`THURSDAY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/dayofweek.proto:43:3:`FRIDAY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/dayofweek.proto:46:3:`SATURDAY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/dayofweek.proto:49:3:`SUNDAY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/decimal.proto:30:9:`Decimal` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/expr.proto:56:9:`Expr` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/fraction.proto:26:9:`Fraction` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/interval.proto:33:9:`Interval` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/latlng.proto:30:9:`LatLng` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/localized_text.proto:26:9:`LocalizedText` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/money.proto:26:9:`Money` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:26:6:`Month` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:28:3:`MONTH_UNSPECIFIED` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:31:3:`JANUARY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:34:3:`FEBRUARY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:37:3:`MARCH` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:40:3:`APRIL` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:43:3:`MAY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:46:3:`JUNE` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:49:3:`JULY` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:52:3:`AUGUST` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:55:3:`SEPTEMBER` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:58:3:`OCTOBER` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:61:3:`NOVEMBER` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/month.proto:64:3:`DECEMBER` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/phone_number.proto:51:9:`PhoneNumber` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/postal_address.proto:42:9:`PostalAddress` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/quaternion.proto:82:9:`Quaternion` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/google/type/timeofday.proto:29:9:`TimeOfDay` declared multiple times
benchmarking/locust/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/cpp_features.proto:15:30:field number `1000` used more than once
benchmarking/locust/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/go_features.proto:17:28:field number `1002` used more than once
benchmarking/locust/venv/lib/python3.13/site-packages/grpc_tools/_proto/google/protobuf/java_features.proto:19:32:field number `1001` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/annotations.proto:19:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/annotations.proto:30:3:cannot find `HttpRule` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/annotations.proto:30:19:field number `72295728` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/client.proto:19:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/client.proto:65:38:field number `1051` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/client.proto:78:25:field number `1049` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/client.proto:100:25:field number `1050` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/client.proto:116:24:field number `525000001` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/client.proto:142:3:cannot find `LaunchStage` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/control.proto:19:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/control.proto:40:12:cannot find `MethodPolicy` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/field_behavior.proto:40:54:field number `1052` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/field_info.proto:45:37:field number `291403980` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/log.proto:19:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/log.proto:45:12:cannot find `LabelDescriptor` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/metric.proto:19:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/metric.proto:20:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/metric.proto:101:5:cannot find `LaunchStage` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/metric.proto:138:12:cannot find `LabelDescriptor` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/metric.proto:265:3:cannot find `LaunchStage` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/monitored_resource.proto:19:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/monitored_resource.proto:20:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/monitored_resource.proto:70:12:cannot find `LabelDescriptor` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/monitored_resource.proto:73:3:cannot find `LaunchStage` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/policy.proto:29:41:field number `158361448` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/policy.proto:34:43:field number `161893301` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/resource.proto:30:53:field number `1055` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/resource.proto:36:64:field number `1053` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/resource.proto:42:44:field number `1053` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/routing.proto:29:36:field number `72295729` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:19:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:20:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:21:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:22:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:23:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:24:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:25:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:26:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:27:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:28:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:29:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:30:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:31:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:32:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:33:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:34:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:35:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:36:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:127:3:cannot find `Documentation` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:130:3:cannot find `Backend` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:133:3:cannot find `Http` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:136:3:cannot find `Quota` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:139:3:cannot find `Authentication` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:142:3:cannot find `Context` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:145:3:cannot find `Usage` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:150:12:cannot find `Endpoint` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:153:3:cannot find `Control` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:156:12:cannot find `LogDescriptor` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:159:12:cannot find `MetricDescriptor` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:163:12:cannot find `MonitoredResourceDescriptor` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:166:3:cannot find `Billing` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:169:3:cannot find `Logging` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:172:3:cannot find `Monitoring` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:175:3:cannot find `SystemParameters` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:178:3:cannot find `SourceInfo` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/service.proto:183:3:cannot find `Publishing` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/visibility.proto:29:47:field number `72295727` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/visibility.proto:34:48:field number `72295727` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/visibility.proto:39:48:field number `72295727` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/visibility.proto:44:50:field number `72295727` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/visibility.proto:49:49:field number `72295727` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/api/visibility.proto:54:46:field number `72295727` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:22:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:25:9:cannot find `google.api.resource_definition` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:31:9:cannot find `google.api.resource_definition` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:37:9:cannot find `google.api.resource_definition` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:43:9:cannot find `google.api.resource_definition` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/common_resources.proto:48:9:cannot find `google.api.resource_definition` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:65:46:field number `1149` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:76:36:field number `1150` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:87:37:field number `1151` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:116:30:field number `1249` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/extended_operations.proto:120:35:field number `1250` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:19:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:21:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:33:11:cannot find `google.api.default_host` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:34:11:cannot find `google.api.oauth_scopes` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:38:13:cannot find `google.api.http` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/cloud/location/locations.proto:48:13:cannot find `google.api.http` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:19:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:20:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:25:1:imported file does not exist
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:43:53:field number `1049` used more than once
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:56:11:cannot find `google.api.default_host` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:61:13:cannot find `google.api.http` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:64:13:cannot find `google.api.method_signature` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:71:13:cannot find `google.api.http` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:74:13:cannot find `google.api.method_signature` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:82:13:cannot find `google.api.http` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:85:13:cannot find `google.api.method_signature` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:100:13:cannot find `google.api.http` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:104:13:cannot find `google.api.method_signature` in this scope
benchmarking/nighthawk-ingress/venv/lib/python3.13/site-packages/google/longrunning/operations_proto.proto:144:5:cannot find `google.rpc.Status` in this scope

What's going on with that?

@haiyanmeng
haiyanmeng force-pushed the proto-wire-compat-guard branch from 62cfd8d to 0e85cd9 Compare September 12, 2026 14:10
@haiyanmeng

Copy link
Copy Markdown
Collaborator Author

I like the test, though it's not quite obvious if there's a calling convention?
We will probably renumber all the tags before we go GA, how do we do that on purpose?
When I run this I get a boatload of warnings and it fails:

Tim Hockin (@thockin) , there were merge conflicts. I rebased the PR. Here is how I test this locally:

  1. Engineer a breaking change:
message CIDRRule {
   // +k8s:maxItems=256
   // +k8s:listType=set
   // +k8s:customValidation # format
-  repeated string cidrs = 1;
+  repeated string cidrs = 7;
 }
  1. Run proto-breaking.sh:
./hack/verify/proto-breaking.sh 
pkg/proto/ateapipb/ateapi.proto:469:1:Previously present field "1" with name "cidrs" on message "CIDRRule" was deleted without reserving the number "1".
  1. Test out how to skip running proto-breaking.sh if a breaking change is introduced deliberately:
ALLOW_PROTO_BREAKING=1 ./hack/verify/proto-breaking.sh 
proto-breaking: skipped, ALLOW_PROTO_BREAKING is set

@thockin

Copy link
Copy Markdown
Collaborator

How do I set that variable so that I can pass CI? What I mean is that eventually we will do this on purpose and I don't see a way to bypass this test, which means I need to user GH admin power to allow a failing CI to merge?

I don't really see another way?

@haiyanmeng
haiyanmeng force-pushed the proto-wire-compat-guard branch from 0e85cd9 to 71f4b4f Compare September 12, 2026 21:58
@haiyanmeng

haiyanmeng commented Sep 12, 2026 •

Copy link
Copy Markdown
Collaborator Author

Tim Hockin (@thockin) , here is an alternative. If a breaking change is intended, the last paragraph of the commit message must carry a trailer Proto-Breaking-Change: to explain it. Otherwise, ./hack/verify/proto-breaking.sh fails like this:

./hack/verify/proto-breaking.sh 
pkg/proto/ateapipb/ateapi.proto:469:1:Previously present field "1" with name "cidrs" on message "CIDRRule" was deleted without reserving the number "1".

proto-breaking: if the break above is intended, commit it with a trailer in the
last paragraph of the commit message saying what stored data it costs:

  Proto-Breaking-Change: <what becomes unreadable, and why that is acceptable>

Indent any continuation line, or git will not read it as a trailer.

With this, we don't need to merge a PR failing CI.

@haiyanmeng

Copy link
Copy Markdown
Collaborator Author

Discussed this in the OSS community meeting today, decided to hold onto the PR until we get closer to the GA date.

Converted to draft for now.

@haiyanmeng
haiyanmeng marked this pull request as draft September 17, 2026 18:04
@BenTheElder Benjamin Elder (BenTheElder) added the DO NOT MERGE This PR must not be merged yet. label Sep 18, 2026
@haiyanmeng
haiyanmeng force-pushed the proto-wire-compat-guard branch 2 times, most recently from 5a1b324 to 3146224 Compare October 22, 2026 20:41
@haiyanmeng haiyanmeng changed the title Proto wire compat guard hack: reject proto changes that break binary wire compatibility Oct 22, 2026
@haiyanmeng
haiyanmeng force-pushed the proto-wire-compat-guard branch from 7a4aa72 to ac484f9 Compare October 22, 2026 21:28
@haiyanmeng
haiyanmeng marked this pull request as ready for review October 22, 2026 21:31
@haiyanmeng
haiyanmeng force-pushed the proto-wire-compat-guard branch 6 times, most recently from ddf3104 to 0df5054 Compare October 23, 2026 15:04
@haiyanmeng
haiyanmeng force-pushed the proto-wire-compat-guard branch 2 times, most recently from 2ed7d51 to 54a2c57 Compare October 23, 2026 15:10
Comment thread AGENTS.md Resolved
Comment thread buf.yaml Resolved
@haiyanmeng
haiyanmeng force-pushed the proto-wire-compat-guard branch from e374ad9 to 56c0cd8 Compare October 26, 2026 12:24
ateapi stores resources as binary protobuf in bytea columns. Binary
protobuf identifies a field only by its number. If a field is renumbered,
stored rows lose its value. If a retired number is reused, stored rows
decode into the wrong field. atepg.go unmarshals with DiscardUnknown, so
the original bytes are dropped on the next read-modify-write. Nothing
reports this at runtime.

Add buf as a tool module and a verify script that runs `buf breaking` on
api/ateapi/v1 against the merge base with main. The WIRE rules reject
renumbering, wire-incompatible type changes, and deleting a field without
reserving its number. They allow field renames. WIRE_JSON would also pin
names, which is too strict while the API is unreleased.

Other protos are not stored, so they keep the AGENTS.md rule against
reserved statements. AGENTS.md now lists api/ateapi/v1 field numbers as the
exception.
verify-all.sh ran the hack/verify scripts under errexit, so the first
failing verifier stopped the loop and the rest never ran. A presubmit
run then showed only one failure, and fixing it could reveal the next.

Run every verifier, collect the ones that fail, list them at the end,
and exit non-zero if any failed.
Check the protos under api/ and internal/proto/, not only api/ateapi/v1,
until there is a policy for internal protos. Breaking changes are no
longer acceptable once this check is in, so remove the Backward
Compatibility section from AGENTS.md.
@haiyanmeng
haiyanmeng force-pushed the proto-wire-compat-guard branch from 56c0cd8 to edbe612 Compare October 26, 2026 12:26
Comment thread buf.yaml

breaking:
use:
- WIRE

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Notes for reviewers:

buf has four categories, from loosest to strictest. Each stricter one forbids everything the looser ones do.

Category Rules Adds
WIRE 15 binary wire compatibility
WIRE_JSON 22 field and enum names, since protobuf's JSON form uses names
PACKAGE 51 generated code within a package; types can move between files
FILE 51 generated code per file; files can't move or be deleted

Common changes under each

Change WIRE FILE
Renumber a field rejected rejected
Change a field to a wire-incompatible type, e.g. string to int32 rejected rejected
Change a field to a wire-compatible type, e.g. int32 to int64, or a renamed message type allowed (buf still flags the renamed message, because it compares type names) rejected (FIELD_SAME_TYPE)
Delete a field and add reserved <n> allowed rejected (FIELD_NO_DELETE)
Rename a field or enum value allowed rejected (FIELD_SAME_NAME, ENUM_VALUE_SAME_NAME)
Change a field's JSON name allowed rejected (FIELD_SAME_JSON_NAME)
Delete an RPC, message, service or enum allowed rejected (RPC_NO_DELETE, MESSAGE_NO_DELETE, …)
Change an RPC's request or response type, or its streaming mode rejected rejected
Delete or move a .proto file allowed rejected (FILE_NO_DELETE)
Change go_package or other language options allowed rejected (FILE_SAME_GO_PACKAGE, …)
Remove a reserved statement rejected rejected

Why the difference

  • WIRE cares only about the bytes. On the wire, a field is just a number and a type, and an RPC is a method path with a request and response type. Names, files and Go packages never appear in the bytes, so WIRE lets you change them. Deleting things is also fine, as long as the old numbers can't be reused.

  • FILE also cares about generated code:

    • Renaming a field removes the Go getter GetFoo(), so callers stop compiling.
    • Deleting an RPC removes a client method.
    • Moving a file or changing go_package changes import paths.

    So FILE forbids almost every removal or rename.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eitan Yarmush (@EItanya) , Benjamin Elder (@BenTheElder) , Tim Hockin (@thockin) , Julian Gutierrez Oschmann (@juli4n) , I picked WIRE here. Let me know if we should use a stricter category.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is correct because we also use binary marshalling for the DB objects

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we ever make a change that keeps WIRE compat but breaks FILE, it's still a client break, requiring a new version of the "SDK". We punted that fort now, but I am calling it out.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like to bump this higher in a week or so for actual 1.0, but I think this is a good start to get people thinking until then

@EItanya Eitan Yarmush (EItanya) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a LGTM

@thockin

Copy link
Copy Markdown
Collaborator

Are we DONE with any proto changes / scrubs / cleanups we need to make? It's not that we can't open this door once shut, but it will take extraordinary action.

Julian Gutierrez Oschmann (@juli4n) Luiz Oliveira (@laoj2) Eitan Yarmush (@EItanya)

@BenTheElder

Copy link
Copy Markdown
Collaborator

Are we DONE with any proto changes / scrubs / cleanups we need to make? It's not that we can't open this door once shut, but it will take extraordinary action.

I'm not sure, e.g. we didn't close out the thread on enums vs strings and compat, but we do have the truly exceptional option to force merge, similar to dealing with broken / deadlocked CI, at minimum.

Need to read through this.

@laoj2

Copy link
Copy Markdown
Collaborator

Are we DONE with any proto changes / scrubs / cleanups we need to make? It's not that we can't open this door once shut, but it will take extraordinary action.

Julian Gutierrez Oschmann (Julian Gutierrez Oschmann (@juli4n)) Luiz Oliveira (Luiz Oliveira (@laoj2)) Eitan Yarmush (Eitan Yarmush (@EItanya))

Other findings from an audit I did this morning:

  • CredentialHeader.credential_uri is a primite union member without optional:
    // Exactly one of credential_uri and actor_jwt must be set.
    //
    // +k8s:optional
    // +k8s:unionMember
    // +k8s:customValidation # format
    string credential_uri = 3;
  • SnapshotStorage.status is a state enum. All other resources call it state:
    enum SnapshotStorageStatus {
    SNAPSHOT_STORAGE_STATUS_UNSPECIFIED = 0;
    // Snapshot creation in durable storage is in progress.
    SNAPSHOT_STORAGE_STATUS_PENDING = 1;
    // Snapshot is complete and ready for use in durable storage.
    SNAPSHOT_STORAGE_STATUS_COMPLETED = 2;
    // Keep this in sync with SnapshotStorage.status's maximum.
    }

@haiyanmeng haiyanmeng added this to the M3 milestone Oct 27, 2026
@thockin

Copy link
Copy Markdown
Collaborator

Let's hold this just a bit, since it is not code

@thockin Tim Hockin (thockin) added prio/P0 Highest priority / required for next milestone milestone-ack labels Oct 27, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api-machinery area/reliability DO NOT MERGE This PR must not be merged yet. kind/cleanup Small fixes that are not bugs, for example a typo in a code comment milestone-ack prio/P0 Highest priority / required for next milestone

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants