jacquardSnapshot

← snapshot

3297 bytes
/**
 * Exercises the judged path without a key by intercepting /judge.
 *
 * This proves the client, the constraint layer, and the rendering — not the
 * model's taste. Two checks matter: a sound judgement merges the two
 * spellings, and a hostile one (inventing ids, trying to swallow the file
 * that stands alone) changes nothing.
 */
import { chromium } from "@playwright/test";
const [from, into, paths] = process.argv.slice(2);
const url = `http://localhost:3000/lab/diff?from=${from}&into=${into}&paths=${encodeURIComponent(paths)}`;

async function run(label, judgement, expectMerge) {
  const b = await chromium.launch();
  const p = await b.newPage({ viewport: { width: 1500, height: 1000 }, colorScheme: "dark" });
  const errs = [];
  p.on("pageerror", e => errs.push(e.message));

  let sawPayload = null;
  await p.route("**/judge", async (route) => {
    const req = route.request();
    if (req.method() === "GET") {
      return route.fulfill({ json: { configured: true, model: "stub" } });
    }
    sawPayload = req.postData();
    // Answer with the ids the client actually sent, so the stub is honest.
    const sent = JSON.parse(sawPayload).groups.map(g => g.id);
    return route.fulfill({ json: judgement(sent) });
  });

  await p.goto(url, { waitUntil: "networkidle" });
  await p.waitForSelector(".jac-diffm", { timeout: 20000 });
  try {
    await p.waitForFunction(
      () => !document.body.innerText.includes("reading ") && !document.body.innerText.includes("judging"),
      { timeout: 25000 },
    );
  } catch {
    console.log("STUCK ON:", (await p.evaluate(() => document.body.innerText)).slice(0, 300));
  }
  await p.waitForTimeout(500);

  const info = await p.evaluate(() => ({
    rail: document.querySelector(".jac-diffm-rail-label")?.textContent?.trim(),
    folds: [...document.querySelectorAll(".jac-diffm-fold")].map(f => ({
      badge: f.querySelector(".jac-diffm-fold-badge")?.textContent,
      label: f.querySelector(".jac-diffm-file-name")?.textContent,
      judged: f.dataset.judged,
    })),
    singles: [...document.querySelectorAll(".jac-diffm-file:not(.jac-diffm-fold)")]
      .map(f => f.querySelector(".jac-diffm-file-name")?.textContent),
  }));

  console.log(`\n--- ${label} ---`);
  console.log("payload leaked a path:", /\.rs/.test(sawPayload ?? ""));
  console.log(JSON.stringify(info, null, 2));
  const mergedCount = info.folds.filter(f => f.judged === "true").length;
  console.log(expectMerge ? `merged: ${mergedCount === 1 ? "yes" : "NO"}` : `refused: ${mergedCount === 0 ? "yes" : "NO"}`);
  console.log("upload.rs still alone:", info.singles.includes("upload.rs"));
  if (expectMerge) await p.screenshot({ path: "tour/lab/diff-judge.png" });
  console.log("errors:", errs.length ? errs.slice(0,2) : "none");
  await b.close();
}

// 1. A sound judgement: the two spellings are one change.
await run("sound judgement", (ids) => ({
  clusters: [{ ids, label: "jitter every retry", why: "Both rename the retry helper to a jittered variant; only the wording differs." }],
}), true);

// 2. A hostile one: invented ids, and an attempt to swallow the lone file.
await run("hostile judgement", () => ({
  clusters: [{ ids: ["made-up-a", "made-up-b", "src/net/upload.rs"], label: "everything", why: "trust me" }],
}), false);