Repository navigation
feat: Add protobuf diff and replay support with optional copy-builder tracking - #960
Closed
derektriley wants to merge 4 commits into
Closed
derektriley wants to merge 4 commits into
derektriley wants to merge 4 commits into
Conversation
Signed-off-by: Derek Riley <derek.riley@swirldslabs.com>
JUnit Test Report 528 files + 7 528 suites +7 30s ⏱️ -2s Results for commit d8fafa4. ± Comparison against base commit c1b9317. This pull request removes 6 and adds 42 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Integration Test Report 432 files + 4 432 suites +4 20m 34s ⏱️ + 6m 41s Results for commit d8fafa4. ± Comparison against base commit c1b9317. This pull request removes 2 and adds 117 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
derektriley
marked this pull request as ready for review
October 13, 2026 17:21
Signed-off-by: Derek Riley <derek.riley@swirldslabs.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description:
Adds generated protobuf diff and replay support for consumers such as Hiero’s block-stream state updates. When only a few fields change, consumers can transmit those fields and an explicit clear list, then reconstruct the complete value from the previous value.
Updates replace whole top-level fields. Nested messages, repeated fields, and maps are each replaced as a unit.
Generated model APIs
Every generated model receives these methods, including when copy-builder tracking is disabled. Signatures below use
Modelas the generated class name.Compute a mask of fields whose values differ. The first overload automatically uses copy-builder provenance when its origin is exactly
prior, otherwise it compares every field. The second overload compares only the supplied candidates. Candidate fields are always checked by value, so calling a setter with an unchanged value does not create a difference.Creates a value containing the selected fields, with all other fields reset to their defaults. Its protobuf encoding supplies the replacement fields.
Returns the protobuf field numbers to clear, in ascending order. An explicit clear list is necessary because default-valued fields are normally omitted from protobuf encodings.
For a selected oneof, the overload accepting
priorclears only the previously active alternative when needed. Withoutprior, every inactive alternative is included.Checks whether omitted fields save at least
minSaving + overheadbytes. It measures cheaper fields first and stops when the threshold is reached, avoiding a complete size calculation when possible. Consumers can use this to choose between partial and full updates.Reconstructs the complete value directly from models, without serialization. It validates clear lists, rejects replace/clear conflicts and unknown clear numbers, and requires oneof switches to explicitly clear the old alternative.
Masks use declaration-order indexes, with one bit per ordinary field or oneof group. Models with more than 64 such entries use
long[]instead oflongthroughout these signatures. Clear lists always use protobuf field numbers.Byte-based replay
Adds these runtime methods to
PartialApplierfor consumers that retain serialized values:splice()replaces complete protobuf field runs and removes cleared fields while preserving all other bytes. Nested payloads remain opaque, so replay does not require decoding and re-encoding messages.Inputs must have ascending field order and canonical varints. The utility validates framing, ordering, and replace/clear conflicts; schema-specific validation remains the consumer’s responsibility.
Copy-builder tracking
Adds the
generateCopyBuilderTrackingcompiler setting, disabled by default. It can be enabled to track provenance:pbj { generateCopyBuilderTracking = true }When enabled, generated models implement
CopyBuilderTracked<Model>and expose:$copyBuilderChangedMask()returnslong[]for wide models.Copy-builder chains retain their original untracked instance and accumulate a mask of fields touched by setters. This accelerates comparisons against that exact origin. Comparisons against another instance fall back to checking every field.
Tracking metadata is excluded from equality, hashing, text output, and codecs.
$untracked()removes shallow provenance before long-lived storage; the runtime also providesCopyBuilderTracked.untracked(value)for generic callers.Comparison semantics and validation
Generated models also implement
DiffSupport.Value.$equalsForDiff(Object).DiffSupport.equal(Object, Object)supplies comparison support for nested generated messages, collections, oneofs, and raw floating-point payloads without changing ordinaryObject.equals().Top-level unknown fields require a full replacement. Tests cover tracking chains and builder reuse, wide masks, restored values, explicit presence, oneof switches, enum ordinals, NaN payloads, savings thresholds, and both object-based and byte-based replay.
Focused compiler/runtime test targets passed, along with 97 integration checks.
Related issue(s):
Fixes #
Notes for reviewer:
Checklist