Motivation
preserve_unknown_fields(bool) is currently all-or-nothing. Disabling it is a legitimate memory optimization (drops the UnknownFields Vec header from every message), but it also silently removes round-trip fidelity everywhere — including on the handful of message types that actually get re-encoded, forwarded, or persisted. #269 is a concrete case: a client disabled preservation globally for memory and then lost unknown closed-enum values on forwarding paths.
A path-scoped variant lets a build keep the memory savings globally while retaining wire fidelity on the specific types that need it:
buffa_build::Config::new()
.preserve_unknown_fields(false) // global default
.preserve_unknown_fields_in(&[".wa.CallLogRecord", // per-message overrides
".wa.SyncdMutation"])
Shape
- Follows the existing
_in convention (bytes_type_in, string_type_in, unbox_oneof_in): proto-path prefixes resolved through matches_proto_prefix, global default first, last matching rule wins.
- Granularity is per-message. The flag gates whether the message struct carries
__buffa_unknown_fields: UnknownFields at all, so rules match message FQNs and package prefixes. Per-field granularity is not representable in the storage model.
- Nested/child messages resolve independently: a preserved outer message retains only its own-level unknown fields; each nested type is governed by its own matching rule.
Implementation notes
The global bool is consulted in several places today — struct field emission (message.rs), the decode arms (including the closed-enum unknown route), encode, the view decoders, and the JSON/extension-range interaction. The change is mechanical: resolve the flag per message from (global, rules) instead of reading one bool, and thread that resolution through the existing call sites.
Priority
Low. The default configuration already preserves unknown fields everywhere; this only benefits builds that opt out for memory and want selective fidelity back. For the #269 use case specifically, a scoped closed-enum openness override (discussed on that issue) is the more direct fix; this option is complementary.
Motivation
preserve_unknown_fields(bool)is currently all-or-nothing. Disabling it is a legitimate memory optimization (drops theUnknownFieldsVec header from every message), but it also silently removes round-trip fidelity everywhere — including on the handful of message types that actually get re-encoded, forwarded, or persisted. #269 is a concrete case: a client disabled preservation globally for memory and then lost unknown closed-enum values on forwarding paths.A path-scoped variant lets a build keep the memory savings globally while retaining wire fidelity on the specific types that need it:
Shape
_inconvention (bytes_type_in,string_type_in,unbox_oneof_in): proto-path prefixes resolved throughmatches_proto_prefix, global default first, last matching rule wins.__buffa_unknown_fields: UnknownFieldsat all, so rules match message FQNs and package prefixes. Per-field granularity is not representable in the storage model.Implementation notes
The global bool is consulted in several places today — struct field emission (
message.rs), the decode arms (including the closed-enum unknown route), encode, the view decoders, and the JSON/extension-range interaction. The change is mechanical: resolve the flag per message from(global, rules)instead of reading one bool, and thread that resolution through the existing call sites.Priority
Low. The default configuration already preserves unknown fields everywhere; this only benefits builds that opt out for memory and want selective fidelity back. For the #269 use case specifically, a scoped closed-enum openness override (discussed on that issue) is the more direct fix; this option is complementary.