"use strict"; // "Try it": replays a REAL recorded run (data/experience.js, made by scripts/make_experience_data.py). // The visitor picks what goes wrong and whether Savepoint is on; nothing is staged by hand. const FAULTS = [ ["none", "Nothing goes wrong", "The agent follows the instructions exactly."], ["stop_at", "It stops halfway", "The agent gives up before finishing the job."], ["wrong_value", "It types a wrong value", "A slipped decimal: 125000.00 instead of 1250.00."], ["skip_save", "It skips the last Save", "It types the note but never saves it, then says done."], ["done_early", "It says done too early", "It reports done after doing only half the work."], ]; const PROTECTION = [ ["off", "No protection", "The agent runs on its own, with nothing watching."], ["savepoint", "Savepoint", "Saves checkpoints, checks the result, and restores on any failure."], ["retry", "Savepoint + retry", "Same, and the agent gets another try from the last good state."], ]; const CHECK_TEXT = { amount_under_cap: "the amount stays under 100,000", no_negative_amounts: "no amount is negative", no_orphan_notes: "no note is left without a claim", amount_set: "the amount is 1250.00", note_added: "a note was added", frame: "nothing else changed", }; const WANT = { amount: 1250.0, noteWord: "adjusted" }; const money = (n) => Number(n).toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 }); const tryState = { fault: "skip_save", prot: "off", timer: null, token: 0 }; function problems(st) { const p = []; if (Math.abs(st.amount - WANT.amount) > 0.001) p.push(st.amount === X.initial.amount ? "the amount was never changed" : `the amount is ${money(st.amount)}, not ${money(WANT.amount)}`); if (!st.notes.some((n) => n.toLowerCase().includes(WANT.noteWord))) p.push("the note was never saved"); return p; } function verdict(run) { const wrong = problems(run.events[run.events.length - 1].state); const cls = run.oracle; let head, body, notice; if (cls === "VS" && run.retries) { head = "Caught, undone, and finished correctly."; body = "Savepoint noticed the problem, restored the last good state, and the agent finished the job on its second try."; notice = "Without retry this run would have ended as a safe fail. Retry turned it into a correct result."; } else if (cls === "VS") { head = "The job was done correctly."; body = "The record has the new amount and the note. Savepoint checked both before accepting the agent’s “done”."; notice = "Nothing went wrong here, so Savepoint stayed out of the way. Pick a failure above to see it act."; } else if (cls === "VF") { head = "It failed, but safely."; body = "The job did not finish, but Savepoint restored the record to exactly how it was. Nothing is left half-done."; notice = "Compare the record before and after: they are identical. Rows different after restore: 0."; } else if (cls === "IS") { head = "The agent said “done”, but the record is wrong."; body = `Nobody was warned. In the record: ${wrong.join(" and ")}. This is the failure Savepoint exists to stop.`; notice = "Turn Savepoint on and replay the same failure to see the difference."; } else { head = "It failed and left a mess."; body = `The agent stopped and the record is half-finished: ${wrong.join(" and ")}. Someone has to clean it up by hand.`; notice = "Turn Savepoint on and replay the same failure to see the difference."; } return { cls, head, body, notice }; } function recHtml(st, flash, banner) { const prev = X.initial; return `
ClaimDesk 98 — Claim ${esc(X.claim)}
Amount${money(st.amount)}
Status${esc(st.status)}
Notes (${st.notes.length})${st.notes.length ? esc(st.notes.join(" · ")) : "none"}
${banner || ""}
`; } function viewTry(query) { if (!X) return pageShell({ title: "Try it", body: `
${icon("alert")}

EXPERIENCE_MISSING data/experience.js did not load.

` }); if (query && FAULTS.some((f) => f[0] === query.fault)) tryState.fault = query.fault; if (query && PROTECTION.some((p) => p[0] === query.prot)) tryState.prot = query.prot; const seg = (items, key) => items.map(([v, label]) => ``).join(""); const body = `
${icon("info")}

The task the agent was given

${esc(X.instruction)}

Below is a recording of the real Savepoint software running this task on a real (fake-data) claims app. You choose what goes wrong. The replay is real, not an animation.

Step 1. What goes wrong?
${seg(FAULTS, "fault")}
Step 2. Protection
${seg(PROTECTION, "prot")}

The record

What is stored in the app. It changes as the agent works.

What happened

Blue lines are Savepoint. Grey lines are the agent. Green and red lines are checks.

    The result appears here when the replay finishes.

    Keep going

    See all 600 test runs ${icon("arrowRight", "s")}See the numbers ${icon("arrowRight", "s")}How it works ${icon("arrowRight", "s")}

    The agent here is a script that fails on purpose, not an AI model. The same checks ran on two real open-source apps, OpenMRS and iDempiere, in the test results.

    `; return pageShell({ title: "Try it: break an AI agent, then undo it", lede: "Pick a failure, switch Savepoint on or off, and watch what happens to the data.", body }); } function evHtml(e) { const li = (cls, ic, word, text) => `
  1. ${icon(ic, "s")}${word}${text}
  2. `; if (e.t === "step") return li("", "arrowRight", "Agent", esc(e.text)); if (e.t === "checkpoint") return li("cp", "diamond", "Savepoint", e.kind === "initial" ? "saved a checkpoint of the record at the start" : "saved a checkpoint before a risky click"); if (e.t === "agent") return li("", e.status === "done" ? "check" : "x", "Agent", e.status === "done" ? "says done" : "gives up: it cannot finish"); if (e.t === "restore") return li("rs", "undo", "Savepoint", `restored the record to ${esc(e.to)}. Rows different after restore: ${e.rows_differ}${e.exact ? " (exact)" : ""}`); if (e.t === "check") { const bad = e.results.filter((r) => !r.passed); const what = e.phase === "invariant" ? "safety checks after the change" : e.phase === "goal" ? "checking the result against the task" : "checking that nothing else changed"; if (!bad.length) return li("ok", "check", "Check passed", `${what}: all passed`); return li("bad", "x", "Check failed", `${what} — ${bad.map((r) => esc(CHECK_TEXT[r.id] || r.id) + (r.observed != null && r.id !== "frame" ? ` (found ${esc(Array.isArray(r.observed) ? r.observed.join(", ") : r.observed)})` : "")).join("; ")}`); } return ""; } function shotsHtml(run) { if (!run.shots || run.shots.length < 2) return ""; return `
    ${icon("chevronDown", "s")} Show the real screens before and after the restore
    Screen before the restore
    Before the restore
    Screen after the restore
    After the restore
    `; } function showVerdict(run) { const v = verdict(run); const again = run.protection === "off" && v.cls !== "VS" ? `
    ` : ""; $("#try-verdict").innerHTML = `
    ${icon(OUT[v.cls].icon)}${OUT[v.cls].word}

    ${esc(v.head)}

    ${esc(v.body)}

    ${esc(v.notice)}

    ${again}${shotsHtml(run)}`; const on = $("#try-on"); if (on) on.addEventListener("click", () => { tryState.prot = "savepoint"; syncSeg(); playTry(false); }); } function syncSeg() { $$("[data-fault]").forEach((b) => b.setAttribute("aria-pressed", String(b.dataset.fault === tryState.fault))); $$("[data-prot]").forEach((b) => b.setAttribute("aria-pressed", String(b.dataset.prot === tryState.prot))); $("#hint-fault").textContent = FAULTS.find((f) => f[0] === tryState.fault)[2]; $("#hint-prot").textContent = PROTECTION.find((p) => p[0] === tryState.prot)[2]; history.replaceState(null, "", `#/try?fault=${tryState.fault}&prot=${tryState.prot}`); } function playTry(instant) { const run = X.runs[`${tryState.fault}|${tryState.prot}`]; clearTimeout(tryState.timer); const token = ++tryState.token; const list = $("#ev"), wrap = $("#rec-wrap"); const label = $("#try-play span"), status = $("#try-status"); label.textContent = "Replaying…"; status.textContent = "Watch the record and the log below."; if (!instant) $("#try-anchor").scrollIntoView({ behavior: "smooth", block: "start" }); list.innerHTML = ""; $("#try-verdict").innerHTML = `

    Replaying…

    `; wrap.innerHTML = recHtml(run.events[0].state, false, "Original record"); const events = run.events.slice(1); const reduce = window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches; let i = 0, last = run.events[0].state, lastBanner = ""; const step = () => { if (token !== tryState.token || i >= events.length) return; const e = events[i++]; const html = evHtml(e); if (html) list.insertAdjacentHTML("beforeend", html); if (e.state) { const changed = JSON.stringify(e.state) !== JSON.stringify(last); const banner = e.t === "restore" ? `${icon("undo", "s")} Restored by Savepoint` : e.t === "checkpoint" ? `${icon("diamond", "s")} Checkpoint saved` : ""; wrap.innerHTML = recHtml(e.state, changed, banner); last = e.state; if (e.t === "restore") lastBanner = banner; } if (e.t === "end") { wrap.innerHTML = recHtml(e.state, false, lastBanner); showVerdict(run); label.textContent = "Play again"; status.textContent = "Done. Change a choice above, or play again."; return; } if (instant || reduce) step(); else tryState.timer = setTimeout(step, e.t === "check" || e.t === "restore" ? 1100 : 700); }; step(); } function bindTry() { if (!X) return; $$("[data-fault]").forEach((b) => b.addEventListener("click", () => { tryState.fault = b.dataset.fault; syncSeg(); playTry(false); })); $$("[data-prot]").forEach((b) => b.addEventListener("click", () => { tryState.prot = b.dataset.prot; syncSeg(); playTry(false); })); $("#try-play").addEventListener("click", () => playTry(false)); $("#try-skip").addEventListener("click", () => playTry(true)); syncSeg(); playTry(false); }