Files
andrey 7d788404f8 Фаза 4: персистентность, полная суита и полировка
- index.html: реальная персистентность (loadSave/applySave/persist/freshSave,
  SAVE_VERSION=1, форма сейва v1, base64-поле, миграции), резюм незавершённой
  партии после reload, авто-пауза при visibilitychange без перезаписи сейва;
  полировка: modeForState вместо мёртвого mode, валидация FIELD_SIZES,
  setFieldSize игнорирует чужие значения, согласованный дефолт fieldH,
  сброс hoverCell на pointerup/cancel, актуализирован комментарий mode.
- tests/test.js: расширена 65 -> 123 проверок (резюм R1/R2/R3, миграция/битый
  сейв, настройки, resize, клики DOM-кнопок, applyIntent, паритет сохранён).
- tools/old-ref/: harness паритета перенесён в репозиторий (old_ref.cpp,
  reference*.json, генераторы, diff-our.js, ref-*.txt, ce1.txt, README).
- AGENTS.md/README.md: форма сейва, миграции, резюм, harness, структура.
- .gitignore: секрет .gitea_token и бинарники/логи harness.
- Прогоны: check: OK; npm test — ИТОГ 123/123; паритет clean 273/273.
- Ревью-гейт 4 (Oracle): PASS; minor/mit закрыты.
2026-10-11 09:29:20 +03:00

57 lines
2.3 KiB
JavaScript

'use strict';
/* Генерация эталона ЧИСТОГО правила (--clean) для всех кейсов reference.json.
Использует CLI-режим harness: ./old_ref <file.txt> <steps> --clean
Пишет reference-clean.json в той же структуре: [{name,w,h,steps:[ascii0..asciiN]}].
Запуск: node gen-clean.js
*/
const { execFileSync } = require('child_process');
const fs = require('fs');
const path = require('path');
const DIR = __dirname;
const refPath = path.join(DIR, 'reference.json');
const outPath = path.join(DIR, 'reference-clean.json');
const tmpPath = path.join(DIR, '.tmp-case.txt');
const ref = JSON.parse(fs.readFileSync(refPath, 'utf8'));
const out = [];
for (const c of ref) {
const init = c.steps[0]; // ASCII начального поля (строки\n)
fs.writeFileSync(tmpPath, init);
const n = c.steps.length - 1; // число шагов
const res = execFileSync(path.join(DIR, 'old_ref'), [tmpPath, String(n), '--clean'], {
encoding: 'utf8',
});
// res = ascii0 + ("--- step k ---\n" + asciiK)*
const parts = res.split(/--- step \d+ ---\n/);
if (parts.length !== n + 1) {
throw new Error(`case ${c.name}: ожидалось ${n + 1} полей, получено ${parts.length}`);
}
out.push({ name: c.name, w: c.w, h: c.h, steps: parts });
}
// Санити-проверка: шаг 0 clean == шаг 0 proto (начальное поле одинаково).
for (let i = 0; i < ref.length; i++) {
if (ref[i].steps[0] !== out[i].steps[0]) {
throw new Error(`шаг 0 расходится для ${ref[i].name}`);
}
}
fs.writeFileSync(outPath, JSON.stringify(out, null, 1) + '\n');
try { fs.unlinkSync(tmpPath); } catch (e) {}
// Сводка: сколько (кейс×шаг) разошлось proto vs clean.
let diff = 0, total = 0;
const diffCases = new Set();
for (let i = 0; i < ref.length; i++) {
for (let k = 1; k < ref[i].steps.length; k++) {
total++;
if (ref[i].steps[k] !== out[i].steps[k]) { diff++; diffCases.add(ref[i].name); }
}
}
console.log('reference-clean.json записан:', outPath);
console.log(`кейсов: ${out.length}, сравнений proto-vs-clean: ${total}, расхождений: ${diff}`);
console.log('кейсы с расхождениями proto≠clean:', [...diffCases].join(', ') || '(нет)');