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.
| Field shape | Record | Hold when |
|---|---|---|
| Proto3 scalar without optional | Implicit presence and default | Zero or empty can mean set or unset |
| Proto3 optional scalar | Explicit presence and has method | The receiver drops the presence bit |
| Message field | Presence behavior and wrapper | A null-like API value is mapped by assumption |
| Repeated field or map | Empty versus omitted policy | The application needs an absent state |
| Edition field | field_presence feature value | Migration relies on syntax alone |
| Unknown field | Retained, discarded, or unavailable | A 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.
| Observation | Safe statement | Open question |
|---|---|---|
| Oneof case method | The generated API reports one selected case | Was another case present earlier on the wire? |
| Duplicate oneof tags | Parser selection follows documented behavior | Does order reflect producer intent? |
| Field number | Member identifies a wire tag | Was a number reused after removal? |
| Reserved number or name | Schema prevents a future reuse | Does the historical schema honor it? |
| Unknown field set | Parser retained or discarded unknown data | Could a later reader recover it? |
| JSON object | Members are unordered and names are unique | Can 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
{"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"}| Round trip | Record | Stop if |
|---|---|---|
| Wire to generated API | Unknown fields and selected oneof case | The runtime version is missing |
| Generated API to wire | Default-valued fields emitted or omitted | Presence state is not captured |
| Wire to JSON | Null, omission, and oneof mapping | A mapper invents an order |
| JSON to wire | Fields restored and defaults applied | JSON null is treated as a value without policy |
| TextFormat to wire | Duplicate and repeated field handling | Duplicate 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.
| Change | Format observation | Application review |
|---|---|---|
| Implicit scalar to explicit scalar | Wire-compatible in some cases | Can a default value be intentionally present? |
| Add a oneof member | Older readers can treat it as unknown | Could a new case be silently discarded? |
| Move field into oneof | Case and presence behavior change | Is existing data semantically exclusive? |
| Reuse a removed number | Old bytes can be reinterpreted | Is the number reserved in every version? |
| Add an enum value | Older readers may retain unknown data | Does fallback hide a new state? |
| Change JSON mapping | Wire may remain stable | Does 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.