From 456140a1bfce72e325f3f50fadd744b3bf94751e Mon Sep 17 00:00:00 2001 From: Kevin Date: Tue, 3 Nov 2026 12:05:33 -0500 Subject: [PATCH] CI: drift avoids every content item the round touched on the sending side #259 only skipped items the round edited with content/edit. A list swap saves both items it moves (new versions), and so do publishes, so drift could still pick a copy of one and grade a change on both sides (seed 799975145, round 1: list swap of Posts #112, drift on its copy #16). Drift now skips the copies of every content item named by the round's content and ordering changes. Co-Authored-By: Claude Opus 5.5 --- ci/permutation/run.mjs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/ci/permutation/run.mjs b/ci/permutation/run.mjs index e0f1f4e..a738975 100644 --- a/ci/permutation/run.mjs +++ b/ci/permutation/run.mjs @@ -251,10 +251,13 @@ for (let i = 0; i < plan.length; i++) { let drifted = null; try { - // The receiving side's copies of items this round edited on the sending side + // The receiving side's copies of content items this round touched on the sending side: edits, + // list swaps (which save both items), publishes and deletes. Page and model changes name page IDs + // or none, so only the content and ordering areas count. const editedThere = applied - .filter((a) => a.area === "content" && a.change === "edit") - .map((a) => mapped(forward)(Number(/#(\d+)/.exec(a.detail)?.[1]))) + .filter((a) => a.area === "content" || a.area === "ordering") + .flatMap((a) => [...String(a.detail ?? "").matchAll(/#(\d+)/g)].map((m) => Number(m[1]))) + .map((id) => mapped(forward)(id)) .filter(Boolean); drifted = await drift(toCtx, new Set(editedThere)); if (drifted) applied.push({ name: "drift", ...drifted, area: "drift" });