The asset UID swap in lookupAssets regex-escaped the UID and then handed
it to String.split, which matches literally. A UID holding a regex
metacharacter never matched the serialized entry, so the source UID
survived the swap and the CMA rejected the entry with "Asset(s) does not
exists" - a message that points at the export rather than at the failed
rewrite. Escaping now matches the encoding the search actually runs
against (JSON), so UIDs with a backslash or a quote work as well, and a
swap that changes nothing is recorded as unmatched rather than matched,
which keeps a silent failure out of matched-asset-uids.json.
updateUids carried the same escape-then-literal-split mismatch for entry
UIDs in HTML RTE. It now builds a single alternation from every matching
UID, longest first, so a UID that is a prefix of another cannot clobber
it and a replacement value cannot be re-scanned by a later pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The asset UID swap in lookupAssets regex-escaped the UID and then handed it to String.split, which matches literally. A UID holding a regex metacharacter never matched the serialized entry, so the source UID survived the swap and the CMA rejected the entry with "Asset(s) does not exists" - a message that points at the export rather than at the failed rewrite. Escaping now matches the encoding the search actually runs against (JSON), so UIDs with a backslash or a quote work as well, and a swap that changes nothing is recorded as unmatched rather than matched, which keeps a silent failure out of matched-asset-uids.json.
updateUids carried the same escape-then-literal-split mismatch for entry UIDs in HTML RTE. It now builds a single alternation from every matching UID, longest first, so a UID that is a prefix of another cannot clobber it and a replacement value cannot be re-scanned by a later pass.