Did you know? An agent can successfully parse a Protocol Buffers message and still corrupt a workflow by changing the meaning of a field, dropping data while converting to JSON, or writing a value that an older service cannot represent. Protocol Buffers provides a compact tagged wire format and rules for evolving message schemas. It does not automatically establish that two versions of an application understand one another’s business intent.
The practical answer is to protect field numbers as durable identities, distinguish binary wire safety from JSON and application compatibility, reserve deleted tags, test old and new readers in both directions, preserve unknown fields where the workflow depends on them, and release new producers only after consumers can handle the new meaning. For AI agents, treat both the schema and a tool’s returned message as bounded evidence, not as unrestricted authority to execute a side effect.
This guide concerns present-day software agents and distributed services. Artificial superintelligence remains hypothetical. All numerical service examples and deployment outcomes below are explicitly fictional teaching cases. The technical rules are checked against the current official Protocol Buffers documentation; no external system is claimed to have been modified or tested here.
Contents
- Why the same message can mean different things to two services
- Field numbers are identities, not decorative positions
- Deleting a field means retiring its number permanently
- Unknown fields can survive a binary round trip—under conditions
- Why a JSON bridge changes the compatibility promise
- Missing, zero and explicitly cleared are different states
- Enums, unknown values and exhaustive decisions
- Oneof evolution and competing claims of presence
- Build a version matrix instead of asking whether it works
- Worked scenario: 1,200 requests and a lossy JSON gateway
- Binary compatibility is not numerical or permission integrity
- How to roll out a schema change safely
- How a coding agent should handle a schema-edit task
- Changed-context exercise: widening a counter beyond older clients
- Common failure modes and the repair each one needs
- Important limits on what any protocol can guarantee
- Frequently asked questions
- Reader pathways and primary technical references
Why the same message can mean different things to two services
An agent may ask a payment service to provide a quote, send an approval to a workflow engine, or read a status record from an inventory system. Those interactions often pass through multiple software versions. A newer service might produce a field that an older service never knew existed. An older agent might then read the record, make a decision and send back a narrower version. The incident can look like an AI reasoning error even when the real fault is at the serialization boundary.
Protocol Buffers is designed for structured messages with stable numerical field tags. A schema defines field types, names and numbers. Generated code helps programs create and parse message instances, but different deployed services can have different generated versions for weeks or months. A safe change must consider both directions: whether old data can be read by new code and whether new data can be read by old code without losing required meaning.
The phrase backward compatible is frequently too vague to be actionable. Does it mean bytes still parse? That a JSON consumer accepts the new field? That a required business decision remains correct? That a client can round-trip unknown information unchanged? Or that a mobile installation that has not updated for a year still works? Record the specific guarantee, supported versions and acceptable loss before calling a change safe.
The official proto3 language guide separates binary wire-safe changes from conditionally compatible and unsafe changes. It also cautions that wire-safe changes can still break application code, for example an exhaustive switch statement after a new enum value is introduced. That distinction is essential for agent engineering because a generated client may parse correctly and still choose an unsafe action.
This article is deliberately narrower than generic workflow migration planning. The unique problem here is deciding whether a tagged binary record, its JSON representation and the business logic that interprets it can survive an incremental schema change.
Field numbers are identities, not decorative positions
A Protobuf field has a human-readable name and a numerical tag. The number identifies the field in the binary wire format. If the name changes but the number and wire interpretation remain compatible, the underlying binary identity may remain stable. If the number changes, the change is effectively a deletion and addition from the wire’s perspective, even when both definitions use the same name.
For example, imagine a message with `string request_id = 1`, `int64 amount_cents = 2` and `string currency = 3`. The first field identifies the request, the second stores an integer count of minor currency units, and the third names the currency. A new version adds `int64 expires_at_ms = 4`. Its number four is new; it does not take over the meaning of tags one to three. The exact decision about optional presence is separate from the assignment of its tag.
The Protobuf binary encoding combines a field number and wire type in a key. The official encoding guide explains the key as `(field_number << 3) | wire_type`. For a varint field numbered 1, the key is `(1 × 8) + 0 = 8`, hexadecimal 08. For a length-delimited field numbered 4, it is `(4 × 8) + 2 = 34`, hexadecimal 22. These calculations show why the tag, not the textual position in a `.proto` file, identifies serialized content.
That encoding detail is not permission to fabricate wire bytes from an intuition about the schema. The actual serialized value, length and field type matter, and Protobuf has separate packed and other encodings. The purpose of the arithmetic is to help reviewers understand why swapping two field numbers can make a decoder assign the wrong meaning to valid bytes.
Official field-number guidance places ordinary field tags within a documented range and reserves 19000 through 19999 for the implementation. It also recommends the low-number tags for frequently used fields because their keys can require fewer bytes. Efficiency is useful, but it is not a reason to repurpose an already assigned tag. An apparently economical renumbering of a public field creates a much larger compatibility risk than any saved byte.
Deleting a field means retiring its number permanently
Suppose version one contains `string legacy_code = 5`. Version two no longer needs that business property. Removing it from source code does not erase old records or old clients that still serialize it. If a developer later assigns tag five to `string access_token`, an old record can be misinterpreted under a new, unrelated meaning. That is a data-integrity and potentially security-sensitive problem.
The official proto3 guide instructs developers to reserve numbers for deleted fields. A schema can include a declaration such as `reserved 5;` and, where appropriate, separately reserve the old field name. The compiler then helps prevent future use of that number or name in the same message. This is a durable record of historical ownership, not merely an internal comment.
Reserving a number protects against accidental schema reuse, but it does not retroactively remove data from already stored messages or revoke an exposed secret. If earlier messages contained sensitive information, retention and deletion require their own governance. Serialization compatibility and privacy erasure are different reader jobs and must not be confused.
Reusing a tag can fail silently because the binary format does not carry the old schema’s semantic story. If the new type uses a compatible wire type, the decoder may produce a plausible-looking value rather than an obvious parse error. Tests that only check whether deserialization succeeded will miss the change in meaning.
For an AI coding agent, a deleted-number check should be a mechanical release gate. If a proposed patch removes a field, the agent can suggest a reserved declaration and generate a compatibility review. It should not bypass the project’s owner or assume it may rewrite historical schemas merely to make a current test pass.
Unknown fields can survive a binary round trip—under conditions
An old Protobuf reader may encounter a field whose number it does not recognise. The wire format can carry that field as unknown data. The official proto3 language guide states that proto3 messages preserve unknown fields in parse and serialization operations, matching proto2 behaviour. This lets a newer producer add fields while an older binary client can still parse the record without interpreting the new field.
Now consider the distinction between forwarding and reconstructing. If an old client parses a binary message and reserializes the same message object through message-oriented APIs, unknown fields may be preserved. If it constructs a fresh message by copying only the fields it knows, unknown fields can be lost. Both operations may produce a valid binary message. Only one may preserve all the information needed downstream.
This is especially important for agent-based workflows that enrich, approve and forward records. An agent might copy a status, add a comment and send it to a later tool. If the code serializes only a hand-built list of visible fields, information introduced by newer services can vanish. A downstream consumer may then fall back to an older default, misread a permission, or treat a missing expiration as a deliberate choice.
Do not overstate preservation. Unknown data is not necessarily meaningful to the old reader, and its mere presence cannot authorise an action. The agent must not make business decisions from opaque bytes it has not validated. Preservation is a transport property; deciding whether the data is safe to act on requires a compatible and authorised interpreter.
The guide’s unknown-fields section explains loss routes such as conversion to JSON and field-by-field copying, and identifies message-oriented APIs such as CopyFrom and MergeFrom as ways to retain unknown fields. An engineer should check the actual runtime and release version before generalising across languages.
Why a JSON bridge changes the compatibility promise
Binary Protobuf and ProtoJSON have different guarantees. In the binary format, a reader can encounter a new numbered field and preserve it as unknown data. JSON keys are names rather than wire tags. An older strict ProtoJSON parser may reject an unrecognised property, while an ignore-unknown setting may allow parsing by discarding it. In neither case should an agent assume the missing value travelled safely through the bridge.
The official ProtoJSON specification explicitly warns that the JSON representation does not support unknown fields as the binary format does. It also points out that field and enum names participate in the JSON encoding, so renaming them can be hazardous for old readers. A binary-safe schema change is not automatically JSON-safe.
A further trap involves large integers. ProtoJSON commonly serializes 64-bit integer types as decimal strings to avoid number precision losses in environments such as JavaScript. Some conforming parsers can accept more than one representation, but relying on a nonconforming client to handle them correctly is risky. If an agent turns the value into a floating-point number or rounds it, the record can pass structural validation while losing numerical accuracy.
Imagine a tool response with a large transaction identifier. It is not a quantity for arithmetic; it is an exact identity. Converting it from a quoted 64-bit value into an imprecise JavaScript number could cause two distinct identifiers to look equal. The remedy is to retain the exact type and representation through the whole chain, then compare the retrieved identifier with an authoritative source where required.
Before adding a field, enumerate every serialization hop. Direct binary gRPC might be compatible, while a dashboard, webhook gateway, browser form or data warehouse turns the same record into JSON. Those intermediate systems are real consumers and producers in the compatibility matrix, not incidental infrastructure.
Missing, zero and explicitly cleared are different states
Protobuf field presence needs careful interpretation. In some proto3 implicit-presence fields, a scalar default and an absent field are not distinguished in the same way as fields declared with explicit presence. The official field presence guide explains why presence semantics affect serialization, merging and updates.
Consider `timeout_seconds`. A value of zero might mean ‘disable the timeout’, ‘expire immediately’, or ‘no value supplied’ depending on the application’s contract. If an agent interprets a default zero as an instruction to remove a safety limit, a valid message can result in an unsafe decision. A schema cannot answer the business meaning without an application-level definition.
For an update operation, an omitted field often means ‘leave the previous value unchanged’. An explicitly present zero might mean ‘set this value to zero’. If the message representation cannot distinguish those states, a client may accidentally overwrite a live configuration. Optional presence, a field mask, or an explicitly named operation may be necessary, depending on the API design.
The risk grows during mixed-version operation. An old client may omit a field it cannot represent, while a new service reads that omission as permission to use a default. Conversely, the new client may explicitly send a zero that an old service treats as absence. A safe rollout must test both directions with the real business semantics, not just whether the bytes parse.
The key question for an agent is not merely ‘what number did I receive?’ but ‘was this property supplied, inherited, intentionally cleared or absent because of a version mismatch?’ Answering that question requires an API contract plus compatible presence semantics and a reliable source of current state.
Enums, unknown values and exhaustive decisions
Enums are convenient names for numeric alternatives such as PENDING, APPROVED and REJECTED. Adding a new value may be binary wire-safe, yet application logic can still break. An older client that expects exactly three known states might throw an exception, silently map the new state to UNKNOWN, or take an unsafe default branch. Different generated-language APIs and enum openness rules can behave differently.
Suppose a new service adds REQUIRES_REVIEW. An old agent sees a value it cannot name. If its workflow treats every unrecognised state as APPROVED, the failure is not a decoder crash but an unsafe business transition. The correct contract needs a conservative branch for unrecognised values, preserving enough information for investigation and refusing a privileged action until the state is understood.
The official language guide distinguishes wire compatibility from source-level compatibility, including the possibility of exhaustive switch statements failing after enum extension. The enum behaviour guidance gives additional detail about how unexpected values are represented and retained under different rules.
Do not reuse old enum numbers to mean new states. A number appearing in archived records retains its historical meaning. Renaming a constant does not rewrite those records, and changing the interpretation under the same number can silently alter audit histories. Names matter separately when JSON is involved.
In an agent’s decision loop, treat unknown enum values as a meaningful uncertainty condition. Log the source, schema version and raw value where appropriate, avoid transmitting sensitive details unnecessarily, and escalate or retry through a compatible reader. ‘I parsed a message’ is weaker than ‘I interpreted a supported state correctly’.
Oneof evolution and competing claims of presence
A oneof declares alternatives that should not be simultaneously set in a message. It is useful for representing mutually exclusive modes, such as a task being specified by an inline request or by a reference to a stored object. But moving existing fields into an already existing oneof can be wire-unsafe because old records may contain combinations that violate new expectations.
The official proto3 guide lists moving fields into an existing oneof as unsafe and describes narrower changes that may be safe, subject to constraints. Developers should follow the documented rules for the exact schema and language edition rather than assume every reorganisation is harmless if field numbers remain unchanged.
Consider an old request that contains both `source_text` and `source_url` because the earlier schema allowed both. A new oneof may retain only the last parsed member’s effective value. An agent believing that both have survived could cite or process the wrong source. If the distinction matters for compliance or evidence, the rollout needs explicit migration logic and tests with old dual-populated messages.
Oneof can also complicate unknown fields: an older reader may not know that a newly added field is a member of a oneof, so it cannot reliably infer whether another known member ought to be cleared. A clean parser success does not supply missing schema knowledge. Separate business decisions from serialization accident.
A safe replacement sometimes requires creating a new message with a new contract and a migration period rather than changing the meaning of the old message. More code can be less dangerous than a deceptively small schema edit when historical records and old clients need to coexist.
Build a version matrix instead of asking whether it works
Think of old and new producers and old and new consumers as four basic pairs: old producer to old consumer; old producer to new consumer; new producer to old consumer; and new producer to new consumer. Each needs testing with representative data. If a JSON gateway, archival replay process or mobile client is present, it adds more paths. The release decision should name which paths are supported and which are deliberately blocked.
For each pair, test both syntactic acceptance and semantic behaviour. Does the message parse? Are known and unknown fields retained? What happens if a new enum value is encountered? Does an omitted timeout retain the old setting or reset it? Can the consumer round-trip the record without losing critical data? A protobuf unit test that exercises only the newest generated client covers only a fraction of this matrix.
Use golden fixtures carefully. A fixture is a known byte sequence with a documented schema version, source and expected interpretation. Keep both old and new fixtures. Round-trip tests can check that unknown information survives through a stated path; decision tests can check that an agent does not act on an unrecognised approval state.
Compatibility test results should include the serializer path and library version. A message may be safe for one language runtime and not for a handwritten JSON adapter. Code generation versions, field presence behaviour and format configuration deserve an explicit record when they affect the contract. Do not infer real support merely from a successfully compiled `.proto` file.
The key form of progress is an evidence table: which old consumers were observed, what they were tested against, and what remains uncertain. This is more useful than reporting a global ‘backward compatible’ flag without identifying the reader job it protects.
Worked scenario: 1,200 requests and a lossy JSON gateway
Imagine a fictional organisation upgrading an approval message. A new producer adds field number four, `expires_at_ms`, to an existing binary schema. During a transition there are 1,200 requests. Nine hundred flow through updated binary services; 300 pass through an old JSON gateway configured to ignore unknown JSON properties and reconstruct a message using only the old schema.
All 1,200 requests may pass some form of parsing. But the 300 gateway-routed requests lose the expiration field. The observed preservation rate in this invented case is 900/1,200 = 75%, while the loss rate is 300/1,200 = 25%. Calling the whole rollout successful because parsing did not fail would conflate transport acceptance with preservation of the intended new business rule.
Suppose 120 of the 300 gateway-routed requests are later replayed for a secondary review. The count 120/300 = 40% describes the gateway subset, not all requests. If those 120 are replayed from the reconstructed messages, they no longer contain the new expiration field. Whether that causes an approval error depends on the consuming application’s semantics, which must be tested rather than guessed.
The repair is not to invent a default expiration in the agent’s natural-language reasoning. Hold back use of the new field on unsupported paths, upgrade or replace the JSON gateway with an agreed contract, and require all affected consumers to verify the new field’s presence and interpretation before enforcing the new rule. If a path cannot be upgraded promptly, block it or route it through a defined compatibility service rather than silently losing data.
After the fix, a verification batch might process, say, 200 held-out representative requests, including examples through every supported path. If all 200 retain the field and apply the intended rule, the measured batch preservation is 200/200 = 100%. That is evidence for those selected cases, not proof of universal reliability across all future messages. The test plan must include old clients, uncommon enum values, unset fields and out-of-range numbers.
This example is intentionally fictional. It illustrates why identifying the denominator and distinguishing ‘accepted’, ‘preserved’ and ‘applied correctly’ are essential in software reporting.
Binary compatibility is not numerical or permission integrity
A type may use the same wire representation while its business units change. If `amount` once meant cents and later means dollars, bytes may parse perfectly while downstream decisions are wrong by a factor of one hundred. The schema needs stable units or a new clearly named field; a reviewer should not infer units from a bare integer.
The separate agent numeric-integrity guide focuses on units, decimal representation and reconciliation. Here the important point is that safe serialization must preserve the type and the meaning together. An automatic agent validator can check the unit contract, but only trusted business requirements determine what the unit should be.
Permissions are another independent layer. A field called `can_publish` arriving in a response does not prove that an authenticated principal may publish. That permission must be checked through the authoritative access-control system. Otherwise a tool response, a stale cache or an untrusted payload can masquerade as approval.
Protobuf can encode nested structures with a known schema, but it is not a semantic firewall. Agents still need validation of string lengths, allowed enums, required cross-field relationships, numeric ranges and the identity of the source. A field being well-typed does not make it a safe instruction.
A safe platform treats schema changes as one component of an end-to-end evidence chain: authenticated producer, compatible transport, bounded interpretation, authorised action and verified result. This prevents a service-format improvement from becoming a hidden permission escalation.
How to roll out a schema change safely
Begin by publishing the intended contract. Identify fields being added, removed or reinterpreted, the allowed versions and the operational consequence. Require a stable numerical tag for every existing field and reserve every deleted tag. A code review should reject changes that repurpose a number, silently switch units or mix incompatible oneof semantics.
Next inventory active consumers, including archived jobs, queues, notebooks, data warehouse connectors, browser dashboards and offline devices. Test JSON paths separately from binary paths. Keep old producers sending old-format data while new consumers demonstrate they can read it. If the new field is optional during transition, define safe behaviour when it is absent instead of assuming all clients are updated simultaneously.
Then release readers before writers where that sequencing is necessary. Verify that downstream systems can interpret the new field and that errors remain observable. Enable new writes gradually and inspect real or representative canary messages for format loss and behavioural correctness. Keep a rollback option that does not require repurposing tags or hiding already written new data.
Check archival replays. A queue may replay messages created months before the upgrade. A parser or business function must still interpret old fields with their original meanings. If a new policy must apply retrospectively, that is a separate explicit migration, not something implied by changing a `.proto` definition.
Finally obtain independent confirmation from the relevant system of record. An agent that sends a message successfully has established only delivery to a boundary. An accepted update, approved transaction or emitted downstream event requires its own receipt and business verification. This matches the broader practice in safe database migration without duplicating that topic’s storage-specific guidance.
How a coding agent should handle a schema-edit task
Suppose a user asks an agent to add a new field to an internal tool. The agent should first identify the specific source schema, its repository and existing field ownership. It should then inspect generated-code consumers and formats, especially whether the tool is consumed as raw binary, gRPC, JSON, or through an application-specific adapter. Editing only the message declaration is incomplete whenever incompatible readers remain.
The agent can produce a proposed schema diff, compatibility matrix, example fixtures, test plan and risk note. It should distinguish what it inspected from what it merely hypothesised. If the agent did not run a generator or test, it must not report that generated code compiles or the consumers pass. A syntactically plausible new field is still a proposal until verified.
Tool output deserves its own protection. If an untrusted message includes text saying to bypass approvals, that instruction is not authority merely because it appears in a parsed field. Schema validation bounds the shape of information; it does not elevate the information’s trust level. The structured-output validation guide makes the same boundary explicit for JSON tool results.
Before writing, the agent should check whether another developer changed the `.proto` definition. If the base version moved, rebase its proposed edit and repeat the compatibility checks. It should never overwrite a concurrent owner’s schema just to restore its own assumptions. Repository and protected-branch rules remain part of the task’s authorisation.
After an approved change, record exact files, reserved tags, compatible and incompatible clients, tests actually run and the release status. Merging the schema is not equivalent to safely activating new semantics in every deployed component. Clear completion language prevents a correct local patch from being mistaken for a completed migration.
Changed-context exercise: widening a counter beyond older clients
Transfer the idea from adding a field to changing a field’s type. An old schema declares `int32 request_count = 7`; a proposed new schema changes the type at the same field number to `int64`. The official proto3 guide describes some integer widenings as conditionally binary compatible because the wire representation is related, but out-of-range values can be truncated or otherwise mishandled by an old reader. It is not a blanket licence to widen the produced value immediately.
The maximum signed 32-bit integer is 2,147,483,647. A new producer wants to write 2,147,483,650, which is larger by exactly three. A current int64 consumer can represent that value, but an old int32 consumer cannot represent it faithfully. A project that has only tested values below the old limit has not shown this new case is safe.
Suppose the system has 200 active consumers. One hundred and eighty are upgraded and twenty remain old. The upgraded share is 180/200 = 90%; the outdated share is 20/200 = 10%. Even if 90% sounds impressive, the new writer cannot assume the remaining 10% will safely interpret out-of-range counts. Consumer counts do not themselves establish how many messages those consumers will receive.
A safe strategy is to keep writing only values in the old legal range until supported consumers are upgraded or isolated, then activate the larger range behind a clear rollout gate. Another design is to add a new dedicated field if that better captures the changed semantic contract. The right choice depends on actual clients, retained messages and the use case; no single rule fits every deployment.
Now change the context again: the field is exported as ProtoJSON to a JavaScript dashboard. Even an upgraded logical schema may need careful handling because large 64-bit integers are typically represented as strings. If the dashboard converts those strings into imprecise floating-point numbers, the system has recreated a correctness problem outside the binary Protobuf layer. This is why the compatibility matrix must include format conversions and real consumers.
The transfer answer is therefore ‘conditionally compatible, not automatically safe’. Preserve old write bounds until readers and bridges are validated, then independently verify the activation. Avoid claiming success from a compiler check alone.
Common failure modes and the repair each one needs
Failure one is reusing a deleted number. The repair is reserving its tag and checking old message fixtures. Failure two is renaming a JSON-visible property without checking clients. The repair is a JSON contract review and a compatible transition, not reliance on binary safety alone.
Failure three is dropping unknown fields while rebuilding messages. The repair is a message-preserving path where needed and round-trip tests that include new fields through old code. Failure four is assuming a new enum value is understood. The repair is an explicit conservative unknown-value branch and tests of the application decision.
Failure five is confusing zero with absent. The repair is choosing suitable presence semantics or an explicit update contract, then testing old and new clients. Failure six is moving fields into a oneof without reviewing historical records. The repair is a controlled new message or migration when the change cannot be proven safe.
Failure seven is widening an integer type and immediately writing out-of-range values. The repair is staged activation after consumer capability checks. Failure eight is converting a 64-bit identifier through an imprecise JSON number. The repair is exact representation and end-to-end identity checks.
Failure nine is proving only newest-client compatibility. The repair is a producer-consumer-version matrix that includes archive replay and old applications. Failure ten is claiming business success from syntactic parsing. The repair is checking the actual decision, permission, unit and final system-of-record receipt.
These errors share one pattern: a boundary that seems technical is carrying meaning. The right response is not to distrust every schema change, but to make each guarantee explicit and test the smallest conditions on which it depends.
Important limits on what any protocol can guarantee
Protobuf is excellent at compact, structured transport and has detailed evolution rules. It is not a proof of source authenticity, access rights, numerical business meaning or end-to-end correctness. An unsigned message can be well formed and malicious. A correctly signed message can be stale. A fully compatible service can still apply the wrong policy.
Wire-safe does not imply source-compatible in every programming language. ProtoJSON differs from binary wire behavior. Defaults and presence can change how an update behaves. Enum values and oneof structure can alter the meaning of apparently valid data. These are documented constraints, not speculative excuses for delaying every upgrade.
Not all deployments need the same preservation guarantee. A read-only dashboard might intentionally ignore a newly introduced optional display field without harm. An audit and approval chain cannot casually drop an expiration or authorization field. Decide whether loss is acceptable from the application contract rather than assuming all unknown values must either be acted on or rejected.
Automated compatibility checkers can identify many structural changes but cannot infer every semantic contract. Engineers still need meaningful tests, explicit version coordination and human review for high-impact migrations. AI agents can make the checks more repeatable, yet they cannot invent authorisation or substitute a verbal assurance for executed evidence.
All examples here are illustrative and intentionally separated from the linked technical source material. No external compiler, schema registry, integration test or production rollout was executed to create the examples.
Frequently asked questions
What makes Protocol Buffers different from JSON? In its binary form it uses numerical field tags and has specified unknown-field preservation behaviour. ProtoJSON uses names and has weaker schema-evolution guarantees for unknown fields. The same logical message can behave differently across the two formats.
Can I rename a Protobuf field safely? Binary identity is based on the number, so a textual rename may leave binary parsing intact, but source code and JSON mappings can break. Review the actual consumers before treating a rename as safe.
Can an old client read a new field? An old binary client can often parse and retain it as unknown data, but cannot interpret its business meaning and may lose it through JSON or field-by-field reconstruction.
Why reserve deleted field numbers? Old serialized records can still contain those tags. Reserving them reduces the risk that someone later reuses the number for a different meaning and causes silent misinterpretation.
Does adding an enum value always work? Binary parsing may remain valid, while application logic with exhaustive switches or unsafe defaults can fail. Test the new value as an unknown state on old clients.
Is changing int32 to int64 safe? The official guide treats certain widening changes as conditionally compatible. Old readers may lose information for out-of-range values, so deployment and write ranges must be controlled.
Does successful deserialization prove a tool call is safe? No. Type checks are only one boundary; the action still needs source authenticity, domain validation, permissions and verified external results.
What is the best rollback after an unsafe schema release? It depends on what new messages were already written. Stop incompatible writes, preserve the evidence, restore supported consumers and choose a compatible migration rather than reusing tags or disguising data loss.
Can a coding agent independently approve a new business field? It can propose and validate a technical change within authorised scope. The owner of the business semantics and deployment permissions remains responsible for approval.
Reader pathways and primary technical references
If you build or review agents, start with a one-page compatibility record: message and field identities, numerical tags, old/new producer-reader pairs, binary/JSON paths, unknown-field requirements, allowed defaults, enum fallbacks, test receipts and activation authority. Make that record part of the review rather than an undocumented memory of the author.
If you teach engineering, let learners encode a tiny versioned message, compare the old and new schemas and reason about the key `(field_number << 3) | wire_type`. Then ask them to show how a JSON bridge or field-by-field reconstruction can lose information even when the parse succeeded. The goal is to explain the mechanism and the hidden assumption, not merely memorise the syntax.
If you maintain production APIs, validate old and new messages across the actual consumer inventory and document when new writes become safe. For adjacent details, read agent API pagination when completeness is the problem, and database expand–backfill–contract when persistence is the problem.
Primary documentation: Protocol Buffers Language Guide (proto3), binary encoding guide, ProtoJSON format, field presence guide and enum behaviour guidance. Consult the versioned language/runtime documentation when implementation details affect the result.
For a wider map of accountable agent design, continue to How Super Intelligence Works and the education-to-life transfer framework. The point is learning to preserve meaning across a real boundary, not merely memorising a serialization trick.