Skip to content

Evidence methods guide

Protobuf Presence and Oneof Schema Review: Preserve Meaning Across Schema Boundaries

Review implicit and explicit presence, oneof cases, defaults, wire behavior, and JSON round trips before treating two Protobuf schemas as equivalent.

A Protobuf field can carry a value while leaving its presence state unresolved. That difference matters when zero, false, an empty string, or an omitted member has different application meaning. Start with the field presence discipline, then inspect oneof membership, field numbers, duplicate wire values, and the chosen JSON or TextFormat boundary. This guide is a schema worksheet, not a compiler, parser, compatibility guarantee, privacy decision, or permission claim.

Updated

On this page

Name the presence discipline before comparing values

Create one row for each field and record syntax or edition, field number, label, declared type, presence discipline, generated presence method, default value, and whether an unset value is meaningful. The Protocol Buffers Documentation, (opens in a new tab) note describes implicit presence as relying on the value itself during serialization, while explicit presence carries a separate set or unset state. Do not turn a generated getter that returns zero into evidence that a sender sent zero.

The source dates in this guide use 22 October 2026 as retrieval evidence for documentation without a verified publication date. They are not publication claims. Where a verified publication date is available, it is recorded in the source ledger.

Name the presence discipline before comparing values (table)
Field shapeRecordHold when
Proto3 scalar without optionalImplicit presence and defaultZero or empty can mean set or unset
Proto3 optional scalarExplicit presence and has methodThe receiver drops the presence bit
Message fieldPresence behavior and wrapperA null-like API value is mapped by assumption
Repeated field or mapEmpty versus omitted policyThe application needs an absent state
Edition fieldfield_presence feature valueMigration relies on syntax alone
Unknown fieldRetained, discarded, or unavailableA round trip silently removes it

Preserve the schema text, descriptor or registry reference, and a neutral artifact digest. A schema comparison can establish what the definitions say. It cannot establish that a producer populated fields correctly or that a default is safe for every historical record.

Review oneof membership and duplicate wire values separately

The Protocol Buffers Documentation, (opens in a new tab) documents oneof as an API invariant with at most one active member. The wire stream can still contain multiple values that notionally belong to the same oneof, and the generated API applies a last one wins rule. Record the wire observation and API observation separately. A clean object after parsing is not proof that the input carried only one case.

Review oneof membership and duplicate wire values separately (table)
ObservationSafe statementOpen question
Oneof case methodThe generated API reports one selected caseWas another case present earlier on the wire?
Duplicate oneof tagsParser selection follows documented behaviorDoes order reflect producer intent?
Field numberMember identifies a wire tagWas a number reused after removal?
Reserved number or nameSchema prevents a future reuseDoes the historical schema honor it?
Unknown field setParser retained or discarded unknown dataCould a later reader recover it?
JSON objectMembers are unordered and names are uniqueCan two oneof cases be represented unambiguously?

If a oneof contains values that represent different kinds of evidence, write the business decision in a separate column. Oneof exclusivity is a format property. It does not prove that the producer chose the right case or that a later schema will preserve the same meaning.

Treat JSON and TextFormat as different review boundaries

The Protocol Buffers Documentation, (opens in a new tab) note says TextFormat follows present field mappings more closely, while JSON has unordered members and a null value that can represent a defined but not-present field. JSON cannot express a last one wins ordering for two same-name members and can leave multiple oneof cases ambiguous. Record the serialization format, mapper version, omission settings, null policy, and whether the conversion was lossy.

Synthetic presence fixture

Treat JSON and TextFormat as different review boundaries code example, JSON
{"schema":"synthetic.Account","field":{"name":"quota","number":"fixture-number","type":"int32","presence":"explicit"},"oneof":{"name":"contact","cases":["email","phone"]},"wire_cases":["email","phone"],"json_policy":"hold-for-review"}
Treat JSON and TextFormat as different review boundaries (table)
Round tripRecordStop if
Wire to generated APIUnknown fields and selected oneof caseThe runtime version is missing
Generated API to wireDefault-valued fields emitted or omittedPresence state is not captured
Wire to JSONNull, omission, and oneof mappingA mapper invents an order
JSON to wireFields restored and defaults appliedJSON null is treated as a value without policy
TextFormat to wireDuplicate and repeated field handlingDuplicate inputs are normalized without a record

Make schema changes with a directional evidence table

Compare old writer schema to new reader schema in the direction the read will use. Then perform the reverse comparison if older readers must consume newer writes. The Protocol Buffers Documentation, (opens in a new tab) documentation distinguishes explicit and implicit settings, and the field presence note describes how a default can disappear during a round trip. Record a compatibility result as wire-level, API-level, conversion-level, or unresolved rather than using one badge.

Make schema changes with a directional evidence table (table)
ChangeFormat observationApplication review
Implicit scalar to explicit scalarWire-compatible in some casesCan a default value be intentionally present?
Add a oneof memberOlder readers can treat it as unknownCould a new case be silently discarded?
Move field into oneofCase and presence behavior changeIs existing data semantically exclusive?
Reuse a removed numberOld bytes can be reinterpretedIs the number reserved in every version?
Add an enum valueOlder readers may retain unknown dataDoes fallback hide a new state?
Change JSON mappingWire may remain stableDoes an external client lose presence?

Stop on ambiguity before a qualified next step

Stop conditions

  • Stop if syntax, edition, field number, presence discipline, or generated runtime version is unknown.
  • Stop if an implicit default can mean both explicitly set and never set for the reader task.
  • Stop if oneof input can contain multiple cases and the source order is unavailable.
  • Stop if JSON or TextFormat conversion drops unknown fields, null policy, duplicate values, or oneof state.
  • Stop if a removed field number or name is not reserved across the schema history.
  • Stop before sampling real messages when the schema packet includes private payloads or identifiers.

Pair this worksheet with the data provenance log for schema and transformation history and the data card template for collection context. A clean descriptor comparison does not prove payload quality, ownership, privacy clearance, or permission.

For a supported non-health collection, once the owner has authority to describe the scope and a controlled metadata packet, the qualified appraisal request path may be a preparation step. It does not compile Protobuf, decode messages, assess compatibility, create a quote, match a buyer, or grant a license.

Sources

  1. Protocol Buffers Documentation: Application Note: Field Presence (opens in a new tab)
  2. Protocol Buffers Documentation: Language Guide: proto 3 (opens in a new tab)
  3. Protocol Buffers Documentation: Feature Settings for Editions: field presence (opens in a new tab)

Use the appraisal path after the Protobuf schema packet is organized.

It does not compile Protobuf, decode messages, assess compatibility, create a quote, match a buyer, or grant a license.