Repository navigation
Replace the json-everything family with an in-tree MeshWeaver.Json - #1292
Conversation
Deletes JsonPatch.Net, JsonPath.Net and the transitives Json.More.Net / JsonPointer.Net, and their four EXCEPTIONS entries in check-licenses.py. The issue's premise was wrong: JsonPatch.Net was NOT "the RFC 7396 merge-patch path behind every cross-hub stream.Update". Merge-patch is already ours (DataExtensions.MergePatchRecursive, MeshNodePatchMerge) and is untouched here, as is the hand-rolled RFC 6902 applier on the sync-stream hot path. What the package actually supplied was RFC 6901 pointers and the RFC 6902 diff. New MeshWeaver.Json namespace inside MeshWeaver.Utils (zero-dependency, reachable from both Data.Contract and Messaging.Hub, so no new NuGet package is minted): JsonPointer + JsonPointerSegment, JsonPatch / PatchOperation / OperationType / PatchResult with their converters, CreatePatch, Apply, IsEquivalentTo, AsNode and the Type.IsNumber predicates. Type NAMES are unchanged — the $type discriminator is the short name and typeof(JsonPatch) is in the hub TypeRegistry. Wire compatibility is the hard constraint: the patch goes out as raw RFC 6902 JSON that the React, gRPC-web and Python clients parse, and none of them are built by this repo's CI. Evidence: a differential harness ran both implementations side by side over 18,490 assertions with 0 mismatches, the diff algorithm was decompiled rather than guessed, and json-everything's literal output is committed as a golden fixture the new suite asserts against byte-for-byte. Also fixes three latent defects in the code this necessarily takes ownership of, all on paths no MeshWeaver-produced patch reaches: Move/Copy arguments were swapped at both call sites, the move/copy/test fallback serialized the PatchResult object instead of its Result, and DecodePointerSegment unescaped ~0 before ~1 (RFC 6901 §4 requires ~1 first, in a single pass). Humanizer.Core was riding in as an accidental transitive of JsonPointer.Net — the only copy in the graph with net10.0 compile assets — so it is now pinned and referenced by the two projects that call DateTime.Humanize(). Refs #1231. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR removes the json-everything dependency family (JsonPatch/Pointer/Path + transitives) and replaces their usage with a new in-tree MeshWeaver.Json implementation housed in MeshWeaver.Utils, while adding a dedicated golden-fixture-based test suite to lock wire compatibility for RFC 6901/6902 payloads.
Changes:
- Introduces
MeshWeaver.Json(RFC 6901JsonPointer, RFC 6902JsonPatch+ diff/apply + converters) insrc/MeshWeaver.Utils. - Updates all in-repo consumers to use
MeshWeaver.Jsonand removesJsonPatch.Net/JsonPath.Netpackage references and license-gate exceptions. - Adds
test/MeshWeaver.Json.Testwith embedded golden fixtures and property-style tests to prevent wire-shape drift; declaresHumanizer.Coreexplicitly where it was previously an accidental transitive.
Reviewed changes
Copilot reviewed 44 out of 45 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| test/MeshWeaver.Layout.Test/LayoutTest.cs | Switches JSON patch/pointer usings to MeshWeaver.Json. |
| test/MeshWeaver.Layout.Test/DomainLayoutServiceTest.cs | Switches json-everything usings to MeshWeaver.Json. |
| test/MeshWeaver.Json.Test/MeshWeaver.Json.Test.csproj | New test project referencing MeshWeaver.Utils and embedding the golden fixture resource. |
| test/MeshWeaver.Json.Test/Fixtures/json-everything-golden.json | Golden-wire oracle captured from json-everything to pin byte-identical serialization/diff behavior. |
| test/MeshWeaver.Json.Test/JsonPointerTest.cs | New RFC 6901 parsing/segment/resolve/serialization + golden conformance tests. |
| test/MeshWeaver.Json.Test/JsonPatchWireFormatTest.cs | New byte-for-byte wire-format serialization/deserialization tests for RFC 6902 operations. |
| test/MeshWeaver.Json.Test/JsonPatchDiffTest.cs | New diff correctness + golden diff corpus + apply(diff)==target property tests. |
| test/MeshWeaver.Json.Test/JsonPatchApplyTest.cs | New apply semantics tests (including escaped-key correctness and failure reporting). |
| test/MeshWeaver.Json.Test/JsonGenerator.cs | Random JSON generator/mutator used for property-style diff/apply tests. |
| test/MeshWeaver.Json.Test/GoldenFixtures.cs | Embedded-resource loader for the golden fixture, failing hard if missing/empty. |
| test/MeshWeaver.Data.Test/PointerSegmentCodecTest.cs | New regression tests pinning the RFC 6901 decode-order trap fix. |
| test/MeshWeaver.Data.Test/Playground.cs | Switches JSON patch/pointer usings to MeshWeaver.Json. |
| test/MeshWeaver.Data.Test/EntityUpdateDedupTest.cs | Switches JSON patch using to MeshWeaver.Json. |
| src/MeshWeaver.Utils/Json/PatchOperation.cs | New RFC 6902 operation model + converters (including property-order contract). |
| src/MeshWeaver.Utils/Json/PatchExtensions.cs | New diff (CreatePatch) and typed Apply helpers. |
| src/MeshWeaver.Utils/Json/JsonTypeExtensions.cs | New numeric-type predicates previously sourced from Json.More. |
| src/MeshWeaver.Utils/Json/JsonPointer.cs | New RFC 6901 pointer implementation + segment decode/evaluate + converter + exception type. |
| src/MeshWeaver.Utils/Json/JsonPatch.cs | New RFC 6902 patch container + apply engine and patch converter. |
| src/MeshWeaver.Utils/Json/JsonEquivalence.cs | New structural JSON equivalence logic + JsonElement→JsonNode bridge (AsNode). |
| src/MeshWeaver.Messaging.Hub/Serialization/ImmutableDictionaryConverter.cs | Replaces Json.More dependency with MeshWeaver.Json (AsNode). |
| src/MeshWeaver.Messaging.Hub/MeshWeaver.Messaging.Hub.csproj | Removes JsonPatch.Net package reference. |
| src/MeshWeaver.Layout/LayoutExtensions.cs | Switches JSON patch/pointer usings to MeshWeaver.Json. |
| src/MeshWeaver.Layout/EditorExtensions.cs | Replaces Json.More using with MeshWeaver.Json. |
| src/MeshWeaver.Layout/DataGrid/PropertyViewBuilder.cs | Replaces Json.More using with MeshWeaver.Json. |
| src/MeshWeaver.Layout/Client/ModelParameter.cs | Switches JSON patch using to MeshWeaver.Json. |
| src/MeshWeaver.Layout/Client/LayoutClientExtensions.cs | Switches JSON patch/pointer usings to MeshWeaver.Json. |
| src/MeshWeaver.Graph/MeshWeaver.Graph.csproj | Declares Humanizer.Core explicitly (no longer a transitive). |
| src/MeshWeaver.Graph/MeshDataSource.cs | Switches JSON patch using to MeshWeaver.Json. |
| src/MeshWeaver.Data/WorkspaceOperations.cs | Switches JSON patch using to MeshWeaver.Json. |
| src/MeshWeaver.Data/StandardReducers.cs | Switches JSON patch/pointer usings to MeshWeaver.Json. |
| src/MeshWeaver.Data/Serialization/JsonSynchronizationStream.cs | Switches JSON patch/pointer usings and fixes fallback move/copy arg ordering + result serialization + pointer decode. |
| src/MeshWeaver.Data/Serialization/InstanceCollectionConverter.cs | Replaces Json.More using with MeshWeaver.Json. |
| src/MeshWeaver.Data/Serialization/EntityStoreConverter.cs | Replaces Json.More using with MeshWeaver.Json. |
| src/MeshWeaver.Data/Serialization/DataChangedEventConverter.cs | Updates commented-out using to MeshWeaver.Json. |
| src/MeshWeaver.Data/ReduceManager.cs | Switches JSON patch using to MeshWeaver.Json. |
| src/MeshWeaver.Data/MeshWeaver.Data.csproj | Removes JsonPatch.Net + JsonPath.Net package references. |
| src/MeshWeaver.Data/DataExtensions.cs | Switches JSON patch using to MeshWeaver.Json. |
| src/MeshWeaver.Data.Contract/MeshWeaver.Data.Contract.csproj | Removes JsonPatch.Net and adds MeshWeaver.Utils reference for MeshWeaver.Json. |
| src/MeshWeaver.Data.Contract/LayoutAreaReference.cs | Switches JSON pointer using to MeshWeaver.Json. |
| src/MeshWeaver.Blazor/Components/ListBase.cs | Switches JSON pointer using to MeshWeaver.Json. |
| src/MeshWeaver.AI/MeshWeaver.AI.csproj | Declares Humanizer.Core explicitly (no longer a transitive). |
| MeshWeaver.slnx | Adds the new MeshWeaver.Json.Test project to the solution. |
| Directory.Packages.props | Pins Humanizer.Core and removes json-everything package versions. |
| .github/scripts/shard-assign.sh | Adds shard weight entry for the new MeshWeaver.Json.Test project. |
| .github/scripts/check-licenses.py | Removes json-everything exceptions from the license gate. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Test Results (shard 0)722 tests +15 722 ✅ +15 11m 50s ⏱️ - 2m 14s Results for commit 09d2082. ± Comparison against base commit ab1ada9. This pull request removes 36 and adds 51 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Test Results (shard 5)1 885 tests +68 1 693 ✅ +68 6m 37s ⏱️ - 1m 50s Results for commit 09d2082. ± Comparison against base commit ab1ada9. This pull request removes 328 and adds 396 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Test Results (shard 2)2 290 tests +176 2 289 ✅ +176 7m 14s ⏱️ +22s Results for commit 09d2082. ± Comparison against base commit ab1ada9. This pull request removes 188 and adds 364 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Test Results (shard 3) 11 files ± 0 11 suites ±0 8m 12s ⏱️ +24s Results for commit 09d2082. ± Comparison against base commit ab1ada9. This pull request removes 371 and adds 41 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Test Results (shard 4)1 809 tests +489 1 799 ✅ +489 12m 46s ⏱️ +23s Results for commit 09d2082. ± Comparison against base commit ab1ada9. This pull request removes 27 and adds 516 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Test Results (shard 1)1 323 tests - 32 1 323 ✅ - 32 8m 10s ⏱️ -4s Results for commit 09d2082. ± Comparison against base commit ab1ada9. This pull request removes 65 and adds 33 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
Two real defects, both on paths the differential harness did not reach: 1. GetNumber cast a raw CLR double/float straight to decimal, which throws OverflowException for NaN, +/-infinity and any magnitude past decimal's range — turning an equality check into a crash. It now returns null for those, so the pair falls through to the boxed comparison and still answers correctly. Only reachable for a JsonValue holding a CLR double rather than a parsed JsonElement, which is why neither the fixtures nor the 8,000 generated documents hit it. json-everything had the identical bug, so this diverges only where it used to throw. 2. JsonPointerSegment.Equals(string?) threw ArgumentNullException on null even though the signature permits it, and the == / != operators reached straight for the span. Null is now simply "no match", per normal Equals semantics. Both are pinned by new tests: RawDoubleValues_CompareWithoutThrowing / RawDoubleValues_DiffWithoutThrowing and Segment_ComparedWithNull_IsFalseNotAThrow. Worth recording what those tests taught us — NaN compares EQUAL to NaN here (the fallback is object.Equals, and Double.Equals deliberately differs from ==), which is the right answer for a diff, and System.Text.Json refuses to serialize +/-infinity at all, so the typed CreatePatch overload cannot be exercised with it. Differential re-run after the change: 18,490 assertions, 0 mismatches — the wire shape is unaffected. Refs #1231. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Closes #1231. Supersedes #1257 (which dropped only the dead
JsonPath.Netreference).Replaces the whole json-everything family —
JsonPatch.Net,JsonPath.Net, and the transitivesJson.More.Net/JsonPointer.Net— with an in-tree implementation, and deletes their fourEXCEPTIONSentries from the licence gate.What the packages were actually doing
The issue text (and a widely-repeated claim in the codebase) said
JsonPatch.Netwas "the RFC 7396merge-patch path behind every cross-hub
stream.Update". That is false, and it is why this jobwas mis-sized as core-risk:
System.Text.Json.NodesinDataExtensions.MergePatchRecursiveandMeshNodePatchMerge. Neither imports anything fromjson-everything. Untouched by this PR.
JsonSynchronizationStream,precisely because the library's applier is wrong (below). Also untouched.
Full consumer list
git grep "using Json\.\(Patch\|Pointer\|More\)"→ 21 files, all nowusing MeshWeaver.Json;:MeshWeaver.DataDataExtensions,ReduceManager,StandardReducers,WorkspaceOperations,JsonSynchronizationStream,EntityStoreConverter,InstanceCollectionConverter,DataChangedEventConverter(comment)JsonPatch,PatchOperation,OperationType,JsonPointer,CreatePatch,AsNodeMeshWeaver.LayoutLayoutClientExtensions,ModelParameter,LayoutExtensions,EditorExtensions,PropertyViewBuilderJsonPatch,PatchOperation,JsonPointer,Apply,Type.IsNumberMeshWeaver.BlazorListBaseJsonPointerMeshWeaver.GraphMeshDataSourceJsonPatch(one signature)MeshWeaver.Data.ContractLayoutAreaReference:187JsonPointer.CreateonlyMeshWeaver.Messaging.HubImmutableDictionaryConverter:35AsNode()onlyEntityUpdateDedupTest,Playground,DomainLayoutServiceTest,LayoutTestsamples/,content/andmodules/were swept too — no in-mesh source references any of thesenamespaces, so no NodeType breaks.
What was implemented
New
MeshWeaver.Jsonnamespace insideMeshWeaver.Utils— a zero-dependency project bothMeshWeaver.Data.ContractandMeshWeaver.Messaging.Hubcan reach, so no new NuGet package isminted.
MeshWeaver.Data.Contractgains oneProjectReference.JsonPointer(RFC 6901) —readonly structbacked by the escaped pointer string, plusJsonPointerSegment(zero-allocref structview). Parse /Create/Combine/Evaluate/TryEvaluate/ segment access / JSON converter.JsonPatch,PatchOperation,OperationType,PatchResult+ converters (RFC 6902).PatchExtensions.CreatePatch(the diff) andApply.JsonEquivalence.IsEquivalentTo— value-wise JSON equality, the diff's "changed?" predicate.JsonElementNodeExtensions.AsNode,JsonTypeExtensions.IsNumber/IsInteger/IsFloatingPoint.Public type names are unchanged (
JsonPatch,PatchOperation,JsonPointer,OperationType) —the
$typediscriminator is the SHORT type name andtypeof(JsonPatch)is registered in the hubTypeRegistry.Wire-compatibility evidence
A patch leaves the process as raw RFC 6902 JSON inside
DataChangedEvent.Change; the React,gRPC-web and Python clients parse those bytes and are not built by this repo's CI. Three
independent pieces of evidence:
1. A differential harness ran both implementations side by side — 18,472 assertions, 0 mismatches.
Built while both were still present (a throwaway project; not shipped). Identical pointer
parse/segments/
Create/Evaluate/TryEvaluate/Combine; identical operation serialization underthree serializer option sets; identical deserialization including member-order permutations, unknown
members and every malformed-operation rejection by exception type; and identical
CreatePatchoutput over 73 hand-picked cases plus 8,000 randomly generated document pairs.
2. The diff algorithm was decompiled, not guessed.
ilspycmdonJsonPatch.Net 5.0.3gave theexact walk, reproduced verb-for-verb: object members in declaration order (recurse, else
remove),then the target's new members as
add; arrays whole-replaced when exactly one side is empty,otherwise positional — ascending-with-
addwhen growing, descending-with-removewhenshrinking. Deliberately not an LCS diff; never emits
move/copy/test.3. A committed golden fixture (
test/MeshWeaver.Json.Test/Fixtures/json-everything-golden.json,132 KB) holds json-everything's literal output for 31 pointer parses, 17
Creates, 35Evaluates,961
Combines, 14 operation serializations and 73 diffs. Its provenance is recorded in the file.JsonPatchWireFormatTestand friends assert against it byte-for-byte, so a later refactor cannotdrift the shape silently.
Property order (
op,path, thenvalueorfrom; nothing more forremove) and thenaming-policy invariance of the verbs have their own dedicated tests.
Test coverage
New
test/MeshWeaver.Json.Test(registered inMeshWeaver.slnx+shard-assign.sh):JsonPointerTest— parse, verbatim round-trip, malformed rejection, URI-fragment form, segmentescaping/decoding,
Create,Combine, resolution, array-index rules (-, leading zeros,negatives, out of range), equality, serialization, plus four golden-fixture conformance tests.
Edge cases include keys containing
/,~,~0,~1, empty segments, digits,-, unicode,emoji, quotes and backslashes.
JsonPatchDiffTest— objects, arrays (append/truncate/reorder/whole-replace), null-vs-missing,numeric equivalence (
1≡1.0≡1e0,0≡-0.0), type changes, escaped paths, the goldencorpus, and property-style checks:
apply(diff(a,b)) == bover 8,000 generated documents,1,000 wire round-trips and 1,000 identity diffs — fixed seeds, so a failure reproduces.
JsonPatchApplyTest— RFC 6902 semantics per verb, failure messages and the failing-operationindex, source immutability, operand detachment, and the escaped-key cases the old library got wrong.
PointerSegmentCodecTest(inMeshWeaver.Data.Test) pins theDecodePointerSegmentfix below.MeshWeaver.Data.Test,MeshWeaver.Layout.Test,MeshWeaver.Serialization.TestandMeshWeaver.Graph.Testare the regression net for the sync stream.Performance
BenchmarkDotNet, .NET 10,
-c Release, 3 warmup + 7 iterations,[MemoryDiagnoser]. Documents arethe realistic ones, not toys: a MeshNode content document (markdown body, front matter, tags,
children), a layout-area snapshot (control tree + a
/data/rowsgrid), and an entity-storeprojection whose ids are JSON-encoded paths like
"acme/Docs/One"— i.e. the shapes whose keysactually need RFC 6901 escaping.
“naive ours” is the first working implementation; “ours” is after one optimization pass (below).
Baseline was captured while the package was still referenced — it cannot be reproduced now.
JsonPatch.NetJsonPatch.NetallocReading this honestly. The host was running several concurrent builds from other sessions, and
the baseline re-measured differently between the two runs —
Diff — MeshNodemoved 2,936→2,536 nsand
Diff + serializemoved 6,911→8,081 ns (the latter with StdDev 796 ns). So the time ratioscarry maybe ±15% of noise and should be read within a run, not across. The one time result I would
defend without caveat is
Diff + serialize, which is 2.4–2.9× across both runs — the diff itself isonly modestly faster, and the win is in the serializer (writing
op/pathas UTF-8 literals with ahand-written converter instead of routing every operation and pointer through a source-generated
type-info chain). Allocations are deterministic and repeated exactly across both runs, so the
right-hand columns are the solid numbers.
Diff — entity-store projectionis the honest weak spot: 1.02× — parity, inside the noise. Itwas 1.26× in the first run and 1.02× in the second; the truthful claim is "no slower, ~18% fewer
allocations", not "faster".
What the optimization pass changed. Only
JsonPointer.Parse/Validate:Parse(string)grew aninline fast path for the ordinary
/a/bform (skipping the#-fragment handling and theTryParseout-parameter round trip), andValidatenow counts separators with the vectorisedMemoryExtensions.Count('/')and only walks characters when the pointer actually contains a~.That moved exactly the benchmarks that parse — parse 24.0→9.4 ns, combine 20.1→8.7 ns, segment
enumeration 42.9→31.5 ns — and left the diff benchmarks unchanged within noise, which is what it
should do since the diff builds pointers by
Combinerather than parsing them.The structural reasons ours is cheaper at all: the pointer is a
readonly structover the escapedstring (so
ToString(), equality and slicing allocate nothing),Evaluateresolves in a singleforward pass with
JsonElement.TryGetProperty(ReadOnlySpan<char>)and only allocates when a segmentactually contains an escape — json-everything re-derives each segment with an O(n) scan per step,
making evaluation O(n²) in pointer length — and
Create/Combinewrite their result in onestring.Createinstead of aparamsarray plus an intermediate escaped string per segment.Re-running it. The harness is a throwaway (not shipped): a console project referencing both
implementations, driven by the same corpus as the differential check. Everything needed to rebuild
it is in this PR's fixture file plus
JsonPatch.Net 5.0.3/JsonPointer.Net 7.0.1.Three latent defects fixed on the way
Each sits in code the replacement necessarily takes ownership of, and each is on a path that in
practice never fires — which is why nothing had surfaced:
PatchOperation.Move/Copyarguments were swapped at both call sites inJsonSynchronizationStream: the factory signature is(from, path)and both passed(path, from).PatchResultobject instead ofresult.Result,which would have written
{"Result":…,"IsSuccess":…}into the stream's state. It now also failsloudly instead of silently corrupting.
DecodePointerSegmentunescaped in the wrong order —Replace("~0","~").Replace("~1","/")manufactures a
~1that the second pass then eats, so an entity id containing the literal text~1decoded to a slash. RFC 6901 §4 is~1first, and it must be a single pass; it now usesJsonPointerSegment.Decode.MeshWeaver's own diff emits only
add/remove/replace, so (1) and (2) were unreachable from anypatch this codebase produces. The hand-rolled hot-path applier in
JsonSynchronizationStreamisdeliberately left exactly as is — its lenient semantics (auto-creating intermediate objects,
StaleStreamStateExceptionon an out-of-range array index) are intentional for aneventually-consistent stream and are not RFC behaviour.
Bonus: an accidental dependency, now declared
JsonPointer.Netwas transitively supplying Humanizer.Core 3.0.10 — the only copy in the graphwith
net10.0compile assets — and that was the sole reasonusing Humanizer;compiled inMeshWeaver.GraphandMeshWeaver.AI. Roslyn's ownHumanizer.Core 2.14.1tops out atnet6.0andcontributes none. Removing json-everything exposed it, so
Humanizer.Core(MIT) is now pinned inDirectory.Packages.propsand referenced by the two projects that callDateTime.Humanize().A full package-closure diff of every
project.assets.jsonagainstorigin/mainconfirms the onlychanges are the four json-everything packages leaving and that Humanizer resolution:
Licence gate
.github/scripts/check-licenses.pyno longer carriesjsonpatch.net,jsonpath.net,json.more.netorjsonpointer.net. With them removed:Verification
All touched projects built INDIVIDUALLY with CI's flags (
-c Release -warnaserror) —MeshWeaver.Utils,.Messaging.Hub,.Data.Contract,.Data,.Layout,.Blazor,.Graph,.AI,.Hosting.Monolith,Memex.Portal.Distributed, and the five touched test projects:0 Warning(s), 0 Error(s) on every one.
Review follow-up
Copilot's automatic review raised two findings, both real, both on paths the differential harness
did not reach. Fixed in
09d2082, each pinned by a new test:GetNumbercast a raw CLRdouble/floatstraight todecimal, which throwsOverflowExceptionfor NaN, ±∞ and any magnitude past decimal's range — an equality check thatcrashes. It now returns null for those and the pair falls through to the boxed comparison, which
still answers correctly. Reachable only for a
JsonValueholding a CLR double rather than aparsed
JsonElement, which is why neither the fixtures nor the 8,000 generated documents hit it.json-everything had the identical bug, so this diverges only where it used to throw.
JsonPointerSegment.Equals(string?)threwArgumentNullExceptionon null though thesignature permits it (and
==/!=reached straight for the span). Null is now simply "no match".Two things those tests turned up, recorded because they are counter-intuitive: NaN compares equal
to NaN here — the fallback is
object.Equals, andDouble.Equalsdeliberately differs from==—which is the right answer for a diff; and
System.Text.Jsonrefuses to serialize ±∞ at all, so thetyped
CreatePatchoverload cannot be exercised with it regardless of this code.Differential re-run after the change: 18,490 assertions, 0 mismatches — the wire shape is
unaffected.
What's New
No entry. This is an internal dependency replacement with no user-visible behaviour change: the
serialized patch bytes are byte-identical, and the three defects fixed above sit on paths no
MeshWeaver-produced patch reaches.