#!/usr/bin/env node
/**
 * judge-watermark (K6, §11/§2; F2 per-session) — анти-откатная монотонная зарубка.
 * Журнал/план/указатель шага лежат в runtime и ПОДПИСАНЫ, но СТАРАЯ подпись валидна
 * → подмена на раннюю валидную пару файлов = откат (спрятать прошлое / отмотать шаг).
 * verifyChain это НЕ ловит (печать цела, просто старая). Лечение: max(seq/шаг),
 * виденный судьёй, хранится в OS-keychain рядом с ключом судьи — ВНЕ откатываемого
 * runtime. current < виденного → откат → блок. Per-session: свежая сессия = генезис 0
 * (это не обход — там отката нет). keychainGet/Set инъектируются (тесты).
 */
const SERVICE = 'router-mentor-judge-watermark';

function account(sessionId) { return `wm:${sessionId}`; }

export function readWatermark({ sessionId, keychainGet }) {
  let raw = null;
  try { raw = keychainGet({ service: SERVICE, account: account(sessionId) }); } catch { raw = null; }
  const n = Number.parseInt(String(raw ?? ''), 10);
  return Number.isFinite(n) && n >= 0 ? n : 0; // genesis 0 при отсутствии/мусоре
}

/** Поднять зарубку ТОЛЬКО вверх (монотонно). */
export function bumpWatermark({ sessionId, value, keychainGet, keychainSet }) {
  const cur = readWatermark({ sessionId, keychainGet });
  const next = Math.max(cur, Number.isFinite(value) ? value : cur);
  if (next !== cur) keychainSet({ service: SERVICE, account: account(sessionId), value: next });
  return next;
}

/** current ниже виденного → откат → блок. */
export function checkNoRollback({ sessionId, current, keychainGet }) {
  const seen = readWatermark({ sessionId, keychainGet });
  const cur = Number.isFinite(current) ? current : 0;
  const rolledBack = cur < seen;
  return { ok: !rolledBack, rolledBack, seen };
}

export const _internals = { SERVICE };
