encode method
Encodes a pre-redacted snapshot for the wire — the snapshot-based path for
inspection/agent consumers that already hold a SemanticInspectionSnapshot
(the serve render loop instead uses encodeTree, which redacts on demand).
Returns null when the exposed semantics are unchanged since the last send.
delta names the changed nodes (in wire-id space); on a patch frame the
encoder re-serializes only those instead of flattening the whole snapshot.
A fresh snapshot may still build its lazy O(tree) id index on the first
lookup. A debug-only oracle asserts the incrementally-maintained _sent
still equals a full flatten, so any gap fails loudly in tests.
Implementation
Uint8List? encode(
SemanticInspectionSnapshot snapshot, {
SemanticWireDelta? delta,
}) {
_rejection = null;
final rootId = snapshot.root.id;
if (!_sentFull) {
final flat = _flatten(snapshot.root);
return _encodeFull(flat, rootId: rootId, flattenedNodes: flat.length);
}
if (delta == null) {
// No changed-set: fall back to the full flatten + structural compare.
final flat = _flatten(snapshot.root);
final encoded = _encodeFlattenedPatch(
flat,
rootId: rootId,
flattenedNodes: flat.length,
);
if (_sentFull) _assertSnapshotOracle(snapshot);
return encoded;
}
final staged = <String, Map<String, Object?>>{};
var flattened = 0;
for (final id in delta.changed) {
final node = snapshot.nodeById(id);
if (node == null) continue; // named-changed but not in the tree.
flattened++;
final json = _flattenNode(node);
final prior = staged[id] ?? _sent[id];
if (prior == null || !_jsonEquals(prior, json)) staged[id] = json;
}
final removed = <String>{};
for (final id in delta.removed) {
// A contradictory delta is invalid. Removal wins in the staged candidate;
// the debug oracle below still makes the producer bug loud in tests.
staged.remove(id);
if (_sent.containsKey(id)) removed.add(id);
}
final encoded = _finishPatch(
rootId: rootId,
staged: staged,
removed: removed,
flattenedNodes: flattened,
);
if (_sentFull) _assertSnapshotOracle(snapshot);
return encoded;
}