Коли інтерфейс показує &, " або зламані літери, природною реакцією є додати ще один decode call. Такий fix може приховати симптом і поглибити проблему. Encoding bugs зазвичай означають, що різні layers не погодилися, чим є value: semantic Unicode text, HTML source чи вже escaped presentation output.

Canonical stored value потрібно визначити заздалегідь

Для імен, описів і повідомлень database зазвичай повинна зберігати plain Unicode text. Значення «A & B» на рівні змісту залишається текстом з ampersand. HTML template escape-ить його за HTML rules, JSON serializer — за JSON rules, а plain-text email показує без додаткового перетворення.

Якщо database зберігає HTML entity, representation стає залежним від одного output format. Це ускладнює editing, search, export і повторне використання даних в інших каналах.

Rich HTML є окремим типом даних

Коли продукт справді зберігає formatted HTML, поле повинно бути явно назване й трактуватися як markup. Його sanitization policy, allowed elements та rendering path відрізняються від plain text. Воно не має випадково проходити через generic decode або raw rendering без відомого contract.

Schema, naming conventions і типи можуть зробити цю різницю видимою. Розробник не повинен дивитися на string і вгадувати, чи безпечно його показувати raw.

Decode виправданий лише явним input contract

Entity decoding правильний, коли upstream прямо передає HTML character references. Застосований до довільного user text, він може перетворити harmless visible sequence на markup-significant characters. Повторний decoding особливо небезпечний, бо nested encoding зрештою може створити executable HTML.

API field має чітко називати, чи містить plain text або sanitized HTML. Client не повинен визначати тип за наявністю angle brackets або entities: звичайний текст також може законно містити ці символи.

Double encoding означає дубльованого власника

Якщо backend escape-ить value, а template повторює операцію, entity syntax стає видимим. Правильний fix зазвичай полягає не в decoding у browser, а у визначенні layer, який відповідає за final output escaping, і видаленні раннього presentation transformation.

Auto-escaping templates найкраще працюють із unescaped semantic values. Raw output повинен бути винятком лише для trusted sanitized markup.

Character encoding і entities є різними проблемами

HTML entities представляють characters усередині markup grammar. UTF-8 визначає, як characters перетворюються на bytes. Текст на кшталт café зазвичай означає, що bytes прочитали з неправильним charset. Entity decoder не відновить таку помилку надійно.

Database connections, files, HTTP headers і serializers повинні послідовно використовувати UTF-8. Перед масовими replacements потрібно дослідити byte-level mismatch, інакше cleanup може знищити вже правильні дані.

Legacy migration потребує класифікації

Стара колонка іноді містить суміш plain text, entities і double-encoded values. Blind repeated decode небезпечний: користувач міг навмисно написати entity-looking text. Migration повинна аналізувати patterns, перевіряти representative samples, зберігати backup і мати rollback.

Після cleanup один canonical representation потрібно enforce на write boundary. Інакше нові записи швидко повернуть змішаний стан.

Брудне representation псує пошук і аналітику

Plain та encoded варіанти однакового видимого слова не є однаковими для database чи search index. Double encoding заважає deduplication, sorting, matching і статистиці. Canonical semantic text дозволяє інструментам працювати зі змістом, який бачить користувач.

Presentation escaping відбувається після retrieval і не повинно записуватися назад як редагування underlying value.

Round-trip tests показують справжнього власника

Representative values варто провести через input, storage, API, editor і final rendering, а потім перевірити, що користувач бачить очікуваний текст. Набір має містити ampersands, quotes, non-Latin characters, entity-looking sequences і дозволений rich markup.

Надійна система чітко розрізняє plain Unicode text, sanitized HTML, URL і serialized data. Encoding та decoding є boundary operations, а не універсальними cleanup tools. Коли ownership очевидний, більшість entity artifacts зникає разом із небезпечними припущеннями.

Export повинен називати representation

CSV, feed, webhook і backup часто стають новим джерелом даних для іншої системи. Якщо export мовчки містить HTML-encoded text, consumer може зберегти entities як content або небезпечно decode-ити поле перед rendering. Documentation має пояснювати, чи поле є plain text, HTML або іншим serialized format.

Коли потрібні і reusable text, і server-rendered presentation, краще передавати їх окремими fields. Один перевантажений string змушує кожного client повторювати крихку логіку визначення типу.

Редактор не повинен змінювати дані без дії користувача

WYSIWYG editor може normalize markup, замінювати entities та переставляти attributes одразу після відкриття документа. Якщо просте відкриття й збереження створює великий diff, система втрачає можливість відрізнити реальне редагування від технічного переформатування.

Для plain-text fields editor повинен працювати з semantic value. Для rich content варто документувати normalization policy, тестувати allowed markup і показувати preview того самого sanitized output, який побачить читач.

Data repair потребує provenance

Під час cleanup важливо знати, з якого source і в який період прийшли записи. Одна integration могла надсилати plain text, інша — entities, а старий importer — double-encoded HTML. Provenance дозволяє застосувати точне правило замість ризикованого global decode.

Metrics і sampling після migration повинні підтвердити, що search, exports та rendering стали послідовними. Якість тексту є властивістю всього повного lifecycle даних, а не одного виклику encoder.

Нові write paths після repair потрібно контролювати окремо. Інакше старі записи стануть чистими, але наступний importer знову почне додавати presentation encoding у canonical field.