Files
PaperClipAI/packages/paperclip-runner/scripts/qualify-cursor-native-usage.mjs
DottaandPaperclip 986f8cc534 Verify Cursor child usage lifecycle and fence profile v9
Mark missing and invalid child run ordinals as partial observations. Exercise the pinned vendor child construction and reuse methods on all three platforms and regenerate the Cursor-only execution identity.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-09-30 05:33:44 -05:00

143 lines
9.8 KiB
JavaScript

import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { readFile } from "node:fs/promises";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { runInNewContext } from "node:vm";
import { CURSOR_RUNTIME_PATCH_PINS, patchCursorRuntimeSource } from "./cursor-runtime-patch.mjs";
const hash = value => createHash("sha256").update(value).digest("hex");
const plain = value => JSON.parse(JSON.stringify(value));
const event = counters => ({ message: { case: "turnEnded", value: counters } });
function segment(source, start, end) {
const first = source.indexOf(start); assert.ok(first >= 0, `Missing ${start}`);
const last = source.indexOf(end, first + start.length); assert.ok(last > first, `Missing ${end}`);
return source.slice(first, last);
}
function awaiter(self, args, _promise, fn) {
const generator = fn.apply(self, args ?? []);
const advance = (method, value) => {
let step; try { step = generator[method](value); } catch (error) { return Promise.reject(error); }
return step.done ? Promise.resolve(step.value) : Promise.resolve(step.value).then(
value => advance("next", value), error => advance("throw", error));
};
return advance("next");
}
const deferred = () => { let resolve; const promise = new Promise(done => { resolve = done; }); return { promise, resolve }; };
/** Actual pinned method/expression execution with transport and surrounding
* session dependencies doubled. No provider entrypoint or inference is run. */
export async function qualifyCursorNativeUsage(vendorRoot) {
const platforms = [];
for (const [platform, pin] of Object.entries(CURSOR_RUNTIME_PATCH_PINS)) {
const original = await readFile(join(vendorRoot, platform, "dist-package", pin.file), "utf8");
assert.equal(hash(original), pin.before);
const source = patchCursorRuntimeSource(original, platform);
assert.equal(hash(source), pin.after);
assert.throws(() => patchCursorRuntimeSource(original + "\n", platform), /digest mismatch/);
const exported = {}; runInNewContext(source, { exports: exported });
assert.ok(exported.modules["./src/acp/agent-session.ts"]);
const collector = runInNewContext(segment(source, "const paperclipCreateCursorUsage=", ";const paperclipCursorResponseError=") + ";paperclipCreateCursorUsage");
let ids = 0;
const scope = { V: awaiter, G: 10, paperclipCreateCursorUsage: collector,
crypto: { randomUUID: () => `00000000-0000-0000-0000-${String(++ids).padStart(12, "0")}` } };
const handlePrompt = runInNewContext(`({${segment(source, "handlePrompt(e){", "claimTaskToolCall(e,t){")}}).handlePrompt`, scope);
const invocationSource = segment(source, "D=async e=>", ",yield D(y)");
const childUpdate = runInNewContext(`({${segment(source, "onInteractionUpdate(e,t){", "onSessionCompleted(e,t){")}}).onInteractionUpdate`);
// Execute the vendor's object construction and reuse transition, rather
// than assuming a hand-built child's fields match the pinned implementation.
const childLifecycle = runInNewContext(`(class {${segment(source, "beginOrUpdateRun(e,t){", "announce(e,t){")}}).prototype`);
assert.ok(source.includes("yield this.processPrompt(e,s,l,paperclipUsage)"));
assert.ok(source.includes("processPrompt(e,t,n,paperclipUsage){"));
const checks = [];
const createHost = backend => {
const publisher = { turn: 0, children: new Map(), enabled: true,
beginTurn() { return ++this.turn; }, runIdsForTurn() { return []; }, whenAllTerminal: async () => true,
enqueue(_child, fn) { return fn(); }, turnFor() { return this.turn; },
beginOrUpdateRun: childLifecycle.beginOrUpdateRun, resolveParentSession: childLifecycle.resolveParentSession,
startNewRun: childLifecycle.startNewRun, onInteractionUpdate: childUpdate };
const host = {
subagentPublisher: publisher, subagentsEnabled: true, backgroundWorkRegistry: { abortWork() {} },
ctx: { withCancel() { const abort = new AbortController(); return [{ signal: abort.signal, get canceled() { return abort.signal.aborted; } }, () => abort.abort()]; } },
agentStore: { getConversationStateStructure: () => ({}), getBlobStore: () => ({}) }, resources: {},
sharedServices: { agentClient: { run: backend } },
async processPrompt(request, context, turn, usage) {
const invoke = runInNewContext(`(function(){let D;${invocationSource};return D;})`, {
paperclipUsage: usage, t: context, b: { modelDetails: {} }, $: { sendUpdate: async () => {} }, u: {}, x: [], A: [], M: {}, k: {},
}).call(this);
await request.execute({ invoke, usage, context, turn, publisher });
},
};
return { host, publisher, run: request => handlePrompt.call(host, request) };
};
const successful = createHost(async (_context, _state, action, _model, callbacks) => {
await callbacks.sendUpdate({}, event(action));
});
const first = await successful.run({ execute: async ({ invoke }) => { await invoke({ inputTokens: 12n }); await invoke({ outputTokens: 3n }); } });
const envelope = first._meta.paperclipCursorUsage;
assert.equal(first.stopReason, "end_turn"); assert.equal(first.usage, undefined);
assert.equal(envelope.completeness, "partial");
assert.deepEqual(plain(envelope.observations.map(row => row.counters)), [{ inputTokens: 12 }, { outputTokens: 3 }]);
assert.equal(successful.publisher.paperclipUsageCollectors.size, 0);
checks.push("exact_parent_invocation_capture", "separate_followups", "no_standard_usage");
const second = await successful.run({ execute: async ({ invoke }) => { await invoke({ outputTokens: 1 }); } });
assert.notEqual(second._meta.paperclipCursorUsage.promptId, envelope.promptId);
assert.equal(second._meta.paperclipCursorUsage.observations.length, 1);
checks.push("warm_prompt_isolation");
const childHost = createHost(async () => {});
const childResult = await childHost.run({ execute: async ({ publisher, turn }) => {
const child = publisher.beginOrUpdateRun("native-child", { toolCallId: "native-tool", parentAgentId: "parent", name: "worker" });
assert.equal(child.runs, 1); assert.equal(child.turn, turn); assert.equal(child.terminal, false);
assert.equal(publisher.children.get("native-child"), child);
child.presenter = { presentInteractionUpdate() {} };
publisher.onInteractionUpdate("native-child", event({ inputTokens: 7n }));
child.terminal = true;
const reused = publisher.beginOrUpdateRun("native-child", { toolCallId: "native-tool-2", parentAgentId: "parent", name: "worker" });
assert.equal(reused, child); assert.equal(reused.runs, 2); assert.equal(reused.terminal, false);
assert.equal(reused.sessionId, "native-child.2"); assert.equal(reused.turn, turn);
child.presenter = { presentInteractionUpdate() {} };
publisher.onInteractionUpdate("native-child", event({ inputTokens: 8n }));
publisher.onInteractionUpdate("unknown-history-child", event({ inputTokens: 999n }));
child.terminal = true; publisher.onInteractionUpdate("native-child", event({ inputTokens: 999n }));
} });
const childEnvelope = childResult._meta.paperclipCursorUsage;
assert.deepEqual(plain(childEnvelope.observations.map(row => [row.role, row.nativeRun, row.counters.inputTokens])), [["child", 1, 7]]);
assert.ok(childEnvelope.reasons.includes("child_run_attribution_unverified"));
childHost.publisher.children.get("native-child").terminal = false;
childHost.publisher.onInteractionUpdate("native-child", event({ inputTokens: 999n }));
assert.equal(childEnvelope.observations.length, 1);
checks.push("vendor_child_creation_and_reuse", "child_run_attribution", "history_and_late_child_isolation");
const started = deferred(), release = deferred(); let oldCallback;
const overlapping = createHost(async (_context, _state, action, _model, callbacks) => {
if (action === "first") { oldCallback = callbacks; started.resolve(); await release.promise; }
await callbacks.sendUpdate({}, event({ inputTokens: action === "first" ? 10 : 20 }));
});
const pending = overlapping.run({ execute: async ({ invoke }) => invoke("first") });
await started.promise;
const next = await overlapping.run({ execute: async ({ invoke }) => invoke("second") });
release.resolve(); const cancelled = await pending;
assert.equal(cancelled.stopReason, "cancelled");
assert.deepEqual(plain(cancelled._meta.paperclipCursorUsage.observations.map(row => row.counters.inputTokens)), [10]);
assert.deepEqual(plain(next._meta.paperclipCursorUsage.observations.map(row => row.counters.inputTokens)), [20]);
await oldCallback.sendUpdate({}, event({ inputTokens: 999 }));
assert.equal(cancelled._meta.paperclipCursorUsage.observations.length, 1);
assert.equal(overlapping.publisher.paperclipUsageCollectors.size, 0);
checks.push("overlapping_cancellation", "late_parent_callback_isolation");
const failure = createHost(async () => { throw new Error("fixture transport failure"); });
await assert.rejects(failure.run({ execute: async ({ invoke }) => invoke({}) }), /fixture transport failure/);
assert.equal(failure.publisher.paperclipUsageCollectors.size, 0);
checks.push("exception_cleanup");
platforms.push({ platform, vendorSha256: hash(original), candidateSha256: hash(source), checks });
}
return { schema: "paperclip.cursor.native-usage-offline-proof.v1", providerCalls: 0, standardUsageEmitted: false,
boundary: "digest-pinned handlePrompt, native invocation, child creation/reuse and child update methods; surrounding session/transport doubled", platforms };
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
assert.equal(process.argv.length, 3, "Usage: node qualify-cursor-native-usage.mjs VENDOR_RESEARCH_ROOT");
console.log(JSON.stringify(await qualifyCursorNativeUsage(process.argv[2]), null, 2));
}