From 2e47c42fad91df8c040b33d3bda301f4a35264cf Mon Sep 17 00:00:00 2001 From: Devin Foley Date: Sun, 25 Oct 2026 04:21:50 -0700 Subject: [PATCH] perf(runner): omit unused launch context from tool authority reads (#17591) Omit nine unused named launch values from the unlocked Native authority query. Preserve complete wake payloads, other context, result receipts, stored input, and locked execution and mutation readers. Verified with full build and typecheck, 2,359 affected tests across 20 suites, real PostgreSQL byte/retention/cancellation checks, a counterfactual, complete exact-head CI, and Greptile 5/5 Medium with no unresolved comments. An existing cleanup scheduling test passed on CI retry after its suite passed locally with both base and branch source. Co-Authored-By: Paperclip --- doc/DATABASE.md | 5 ++- .../paperclip-runner-tool-authority.test.ts | 36 +++++++++++++++++++ .../paperclip-runner-tool-authority.ts | 6 +++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/doc/DATABASE.md b/doc/DATABASE.md index 762ea37f2d9..4f16a6e4d87 100644 --- a/doc/DATABASE.md +++ b/doc/DATABASE.md @@ -127,7 +127,10 @@ Native tool authority lookups select current run identity, status, invocation, responsible user, context, and receipt data. Saved profiles and output excerpts stay in storage and are omitted from that read. Task and agent binding, current status, budget, and task privacy checks retain their existing predicates. -Mutation transactions still lock and read complete run records. +Mutation transactions still lock and read complete run records. The unlocked +authority read also omits named launch renderings and preparation data that its +tools do not consume. Full wake payloads, other context, and result receipts +remain available; the complete saved context stays in storage for execution. WebSocket delivery uses one fresh authorization batch for an event's task and run bindings. When both bindings name the same task, the batch reads its current diff --git a/server/src/services/native-runtime/paperclip-runner-tool-authority.test.ts b/server/src/services/native-runtime/paperclip-runner-tool-authority.test.ts index 76815a76482..2558b813555 100644 --- a/server/src/services/native-runtime/paperclip-runner-tool-authority.test.ts +++ b/server/src/services/native-runtime/paperclip-runner-tool-authority.test.ts @@ -244,6 +244,42 @@ describe("PaperclipRunnerToolAuthority", () => { } }); + it("reads tool authority without transferring unused launch renderings", async () => { + const binding = { companyId, agentId, issueId, runId }; + const authority = new PaperclipRunnerToolAuthority(db, binding); + const contextCall = { tool: "get_task_context", callId: "launch-context-read", arguments: {} }; + const apiCall = { tool: "search_api", callId: "launch-api-read", arguments: { query: "read task" } }; + const expectedContext = await authority.execute(contextCall), expectedApi = await authority.execute(apiCall); + const [original] = await db.select().from(heartbeatRuns).where(eq(heartbeatRuns.id, runId)); + const payload = "retained-launch-rendering🙂".repeat(8192); + const context = { ...original.contextSnapshot, executionContinuation: { savedInput: payload }, paperclipTaskMarkdown: payload, + paperclipTaskMarkdownCompact: payload, paperclipTaskMarkdownAssignment: payload, paperclipTaskMarkdownAssignmentCompact: payload, + paperclipWorkspace: { savedInput: payload }, paperclipEnvironment: { savedInput: payload }, + paperclipContinuationSummary: payload, paperclipWakeComment: payload }; + await db.update(heartbeatRuns).set({ contextSnapshot: context }).where(eq(heartbeatRuns.id, runId)); + const [expanded] = await db.select().from(heartbeatRuns).where(eq(heartbeatRuns.id, runId)); + const observed = createDb(temporary!.connectionString), events: Array> = [], now = Date.now(); + const capture = createDatabaseResponseCapture({ start: now - 100, end: now + 59_000 }, event => events.push(event)); + installDatabaseResponseCapture(observed, { heartbeatRuns, issues, agents, companies }, capture); + try { + const reader = new PaperclipRunnerToolAuthority(observed, binding); + const actualContext = await reader.execute(contextCall), actualApi = await reader.execute(apiCall); + capture.flush(); + const reads = events.filter(event => event.table === "heartbeat_runs" && event.operation === "select"); + expect(reads.length).toBeGreaterThan(0); + expect(reads.reduce((bytes, event) => bytes + Number(event.responseValueBytes), 0)).toBeLessThan(16 * 1024); + expect(actualContext).toEqual(expectedContext); + expect(actualApi).toEqual(expectedApi); + expect((await db.select().from(heartbeatRuns).where(eq(heartbeatRuns.id, runId)))[0]).toEqual(expanded); + await db.update(heartbeatRuns).set({ status: "cancelled" }).where(eq(heartbeatRuns.id, runId)); + await expect(reader.execute(contextCall)).rejects.toThrow("paperclip_runner_tool_binding_not_authorized"); + await expect(reader.execute(apiCall)).rejects.toThrow("paperclip_runner_tool_binding_not_authorized"); + } finally { + capture.flush(); await observed.$client.end(); + await db.update(heartbeatRuns).set({ contextSnapshot: original.contextSnapshot, status: original.status }).where(eq(heartbeatRuns.id, runId)); + } + }); + it("preserves platform receipt provenance in both mixed task history readers", async () => { const at = new Date("2026-10-10T12:00:00Z"); const commentIds = Array.from({ length: 4 }, () => randomUUID()); diff --git a/server/src/services/native-runtime/paperclip-runner-tool-authority.ts b/server/src/services/native-runtime/paperclip-runner-tool-authority.ts index 40b140f01b2..e257744e545 100644 --- a/server/src/services/native-runtime/paperclip-runner-tool-authority.ts +++ b/server/src/services/native-runtime/paperclip-runner-tool-authority.ts @@ -1235,7 +1235,11 @@ export class PaperclipRunnerToolAuthority { status: heartbeatRuns.status, invocationSource: heartbeatRuns.invocationSource, responsibleUserId: heartbeatRuns.responsibleUserId, - contextSnapshot: heartbeatRuns.contextSnapshot, + contextSnapshot: sql | null>`case when jsonb_typeof(${heartbeatRuns.contextSnapshot}) = 'object' + then ${heartbeatRuns.contextSnapshot} - array['executionContinuation', 'paperclipTaskMarkdown', + 'paperclipTaskMarkdownCompact', 'paperclipTaskMarkdownAssignment', 'paperclipTaskMarkdownAssignmentCompact', + 'paperclipWorkspace', 'paperclipEnvironment', 'paperclipContinuationSummary', 'paperclipWakeComment'] + else ${heartbeatRuns.contextSnapshot} end`, resultJson: heartbeatRuns.resultJson, } }) .from(heartbeatRuns)