/
deka
/
buffer
Обзор
Документация
Войти
/
deka
/
buffer
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
dev
tests/converters/goal-diff.test.mjs
90 строк
5 KB
Maksim Ratnikov
feat: сверка версий цели вместо вкладки review
29 июл 2026, 11:28
29 июл 2026, 11:28
74bebb7
Код
Авторство
О чём код?
import assert from "node:assert/strict"; import { diffGoals, riskyChanges, itemKey } from "../../src/converters/goal-diff.js"; const confirmed = () => ({ status: "confirmed", confidence: "high", source_ref_ids: ["src_01"] }); function goal(overrides = {}) { return { schema_version: "goal-template.v1", schema_minor_version: "1.0", goal_identity: { id: "goal_demo", title: { value: "Демо-цель", state: confirmed() }, period: "2026", source_status: "confirmed" }, source_refs: [{ id: "src_01", type: "manual_note", title: "Методика" }], goal_meaning: { description: { value: "Смысл", state: confirmed() } }, applicability: { target_entity_types: ["team"] }, obstacles: [{ obstacle_id: "obs_one", title: "Блокер", kind: "data_conflict", scope: "goal_execution", state: confirmed() }], ...overrides }; } // --- одинаковые версии -------------------------------------------------------- const same = diffGoals(goal(), goal()); assert.deepEqual(same.changes, [], "identical goals produce no changes"); assert.equal(same.summary.removed, 0); // --- добавление элемента массива ---------------------------------------------- const withNewObstacle = goal({ obstacles: [ { obstacle_id: "obs_one", title: "Блокер", kind: "data_conflict", scope: "goal_execution", state: confirmed() }, { obstacle_id: "obs_two", title: "Новый блокер", kind: "process_blocker", scope: "goal_execution", state: confirmed() } ] }); const added = diffGoals(goal(), withNewObstacle); assert.equal(added.summary.added, 1, "a new array element is reported once"); assert.equal(added.changes[0].kind, "added"); assert.equal(added.changes[0].subject, "Новый блокер", "the change is labelled by the element title"); assert.equal(added.summary.removed, 0, "adding does not look like a removal"); // --- потеря элемента: главный детектор ---------------------------------------- const lost = diffGoals(withNewObstacle, goal()); assert.equal(lost.summary.removed, 1, "a dropped element is reported as removed"); assert.equal(riskyChanges(lost).length, 1, "removals are the risky changes"); assert.equal(riskyChanges(lost)[0].subject, "Новый блокер"); // --- перестановка элементов не считается изменением --------------------------- const reordered = goal({ obstacles: [ { obstacle_id: "obs_two", title: "Второй", kind: "process_blocker", scope: "goal_execution", state: confirmed() }, { obstacle_id: "obs_one", title: "Блокер", kind: "data_conflict", scope: "goal_execution", state: confirmed() } ] }); const reorderedBack = goal({ obstacles: [reordered.obstacles[1], reordered.obstacles[0]] }); assert.deepEqual(diffGoals(reordered, reorderedBack).changes, [], "reordering by stable ids is not a change"); // --- изменение значения и статуса --------------------------------------------- const edited = goal({ goal_meaning: { description: { value: "Уточнённый смысл", state: { status: "requires_review", confidence: "low", source_ref_ids: ["src_02"] } } } }); const editedDiff = diffGoals(goal(), edited); const valueChange = editedDiff.changes.find((change) => change.kind === "changed"); assert.ok(valueChange, "a rewritten value is reported"); assert.equal(valueChange.before, "Смысл"); assert.equal(valueChange.after, "Уточнённый смысл"); const statusChange = editedDiff.changes.find((change) => change.kind === "status"); assert.ok(statusChange, "a status shift is reported separately from the value"); assert.equal(statusChange.before, "confirmed"); assert.equal(statusChange.after, "requires_review"); // --- источники: новые и сломанные --------------------------------------------- const withNewSource = goal({ source_refs: [ { id: "src_01", type: "manual_note", title: "Методика" }, { id: "src_02", type: "manual_note", title: "Протокол 01.06" } ] }); const sourceDiff = diffGoals(goal(), withNewSource); assert.deepEqual(sourceDiff.summary.newSources, ["src_02: Протокол 01.06"], "new source segments are listed"); assert.deepEqual(sourceDiff.summary.brokenSources, [], "keeping old sources intact is not a break"); const renamedSource = goal({ source_refs: [{ id: "src_01", type: "manual_note", title: "Другая методика" }] }); const renameDiff = diffGoals(goal(), renamedSource); assert.deepEqual(renameDiff.summary.brokenSources, ["src_01: Методика"], "a renamed source id breaks provenance and is flagged"); const renumbered = goal({ source_refs: [{ id: "src_09", type: "manual_note", title: "Методика" }] }); assert.deepEqual(diffGoals(goal(), renumbered).summary.brokenSources, ["src_01: Методика"], "renumbering sources is flagged too"); // --- ключи сопоставления ------------------------------------------------------ assert.equal(itemKey({ obstacle_id: "o1", title: "x" }, 0), "obstacle_id=o1", "stable id wins over the title"); assert.equal(itemKey({ title: "Веха" }, 0), "title=Веха", "a human label is used when there is no id"); assert.equal(itemKey("строка", 3), "#3:строка", "plain strings fall back to their position"); console.log("goal-diff test passed");