fix(tracker): mark_read шлётся на КАЖДЫЙ клик пилюли (идемпотентно)
Старый syncPending-баг успел залить локальный localState.read данными, которых нет на сервере. После фиксов firstTime=false для всех ключей в localState.read, и mark_read иначе никогда не уходил → каталог показывал 0 даже после реальных кликов. Решение: убрать оптимизацию firstTime. Слать mark_read КАЖДЫЙ раз — серверный код if(!arr.includes(mark_read)) arr.push(...) не добавит дубликат. Лишний POST стоит копейки, зато система самовосстанавливается без зависимости от загрузочного backfill.
This commit is contained in:
@@ -214,23 +214,24 @@
|
||||
localState.read.forEach(k => { refreshPillUI(k); refreshCheckUI(k); });
|
||||
}
|
||||
|
||||
/* ── 7. Pill click → last_para + (первый раз) mark_read ────────
|
||||
Объединяем оба обновления в один POST, чтобы syncPending-guard
|
||||
в syncToServer не дропнул второй вызов в том же тике. */
|
||||
/* ── 7. Pill click → ВСЕГДА шлём last_para + mark_read одним POST
|
||||
Идемпотентно: на сервере `if (!arr.includes(mark_read)) arr.push(...)`
|
||||
не добавит дубликат. Эта «избыточность» лечит самовосстановлением
|
||||
ситуации, когда localState.read был засорён старым syncPending-багом
|
||||
(есть ключ локально, нет на сервере, mark_read иначе никогда не уйдёт). */
|
||||
function wirePillTracking() {
|
||||
document.body.addEventListener('click', e => {
|
||||
const pill = e.target.closest('.para-pill[data-para]');
|
||||
if (!pill) return;
|
||||
const key = pill.dataset.para;
|
||||
localState.last = key;
|
||||
const firstTime = !localState.read.includes(key);
|
||||
if (firstTime) {
|
||||
if (!localState.read.includes(key)) {
|
||||
localState.read.push(key);
|
||||
refreshPillUI(key);
|
||||
refreshCheckUI(key);
|
||||
}
|
||||
refreshPillUI(key);
|
||||
refreshCheckUI(key);
|
||||
persist();
|
||||
syncToServer(firstTime ? { mark_read: key } : {});
|
||||
syncToServer({ mark_read: key });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user