Buyer-visible integrity gap
Protected develop@622e5e6c3d534f230c390f10e3832efadfc01825 makes etl-service ChangeRecord top-level before / after / pk maps unmodifiable and snapshots those map objects, but nested JSON-shaped Map and List values remain aliased to caller-owned mutable objects. A connector or adapter can therefore observe a different normalized record after construction if an upstream caller mutates a nested object/array, contradicting the class-level promise that callers cannot mutate a record after it enters the connector pipeline.
This matters for plugin/connector determinism, equality/hash stability, replay/audit reasoning, and cross-service handoff integrity. The live Debezium/ObjectMapper path represents nested JSON objects/arrays as ordinary Java maps/lists, so this is a real supported data shape rather than an exotic arbitrary-object case.
Scope
Keep the repair bounded to etl-service ChangeRecord and focused tests. Do not modify active CDC CanonicalChangeRecord PR #222, connector registry work, provider implementations, database migrations, or serialization contracts.
Test-first acceptance
- Add a failing regression first using nested mutable
LinkedHashMap and ArrayList values inside after (and, where useful, before/pk).
- Prove both mutation paths fail closed from the caller perspective:
- mutating the original nested containers after construction cannot change the record;
- nested containers reachable through getters are unmodifiable.
- Preserve nested
null values and list elements.
- Preserve current scalar/object identity semantics for non-container values; do not pretend arbitrary mutable third-party objects can be cloned safely.
- Implement the narrowest recursive snapshot for JSON-shaped
Map<?, ?> and List<?> containers, with beginner-readable Javadocs explaining the boundary.
- Run focused and full applicable tests and keep the PR Draft until shared literal-source, scanner-completeness, non-vacuous coverage, and independent-review gates are satisfied.
Non-goals
Buyer-visible integrity gap
Protected
develop@622e5e6c3d534f230c390f10e3832efadfc01825makesetl-serviceChangeRecordtop-levelbefore/after/pkmaps unmodifiable and snapshots those map objects, but nested JSON-shapedMapandListvalues remain aliased to caller-owned mutable objects. A connector or adapter can therefore observe a different normalized record after construction if an upstream caller mutates a nested object/array, contradicting the class-level promise that callers cannot mutate a record after it enters the connector pipeline.This matters for plugin/connector determinism, equality/hash stability, replay/audit reasoning, and cross-service handoff integrity. The live Debezium/ObjectMapper path represents nested JSON objects/arrays as ordinary Java maps/lists, so this is a real supported data shape rather than an exotic arbitrary-object case.
Scope
Keep the repair bounded to
etl-serviceChangeRecordand focused tests. Do not modify active CDCCanonicalChangeRecordPR #222, connector registry work, provider implementations, database migrations, or serialization contracts.Test-first acceptance
LinkedHashMapandArrayListvalues insideafter(and, where useful,before/pk).nullvalues and list elements.Map<?, ?>andList<?>containers, with beginner-readable Javadocs explaining the boundary.Non-goals