Merge commit 'db3a9aecf4' into codex/boat-environment

* commit 'db3a9aecf4':
  fix(boat): resolve prior workspace authority to recorded lease
  Allow bounded Boat connection probes before saving an agent

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-10-10 11:17:16 -05:00
commit d9d308aead
5 files changed
+77 -23

No files matched your search

@@ -621,6 +621,35 @@ with open(output,'wb') as out,open(error,'wb') as err:
rmSync(temp, { recursive: true, force: true });
}
});
it("admits an unsaved-agent probe in a bounded company-scoped temporary home", async () => {
const f = fixture();
await f.attach();
const probe = await f.service.admitProbe({ ...f.scope, probeId: "unsaved", idleTimeoutMs: 60_000 });
const record = await f.repository.get(f.scope);
const owner = record.ledger.owners.find((entry) => entry.id === probe.owner.ownerId)!;
expect(owner.agentId).toBeUndefined();
expect(owner.runId).toBeUndefined();
expect(owner.probeId).toBe("unsaved");
expect(probe.remoteCwd).toBe(`/home/user/paperclip/${f.scope.companyId}/probes/unsaved`);
expect(probe.agentHome).toBe(probe.remoteCwd);
expect(Object.keys(record.ledger.placements)).toEqual(["probe-unsaved"]);
await expect(f.service.realizeWorkspace({ ...f.scope, owner: probe.owner, mode: "shared" }))
.resolves.toMatchObject({ remoteCwd: probe.remoteCwd, agentHome: probe.agentHome });
await expect(f.service.realizeWorkspace({ ...f.scope, owner: probe.owner, mode: "shared", projectId: "project" }))
.rejects.toMatchObject({ code: "conflict" });
await expect(f.service.admitProbe({ ...f.scope, companyId: "foreign", probeId: "other", idleTimeoutMs: 60_000 }))
.rejects.toMatchObject({ code: "not_found" });
f.advance(60_001);
await f.service.reconcile();
expect(f.repository.runState).not.toHaveBeenCalled();
expect(f.backend.retire).toHaveBeenCalledOnce();
});
it("still requires an agent for a real heartbeat admission", async () => {
const f = fixture();
await f.attach();
await expect(f.service.admit({ ...f.scope, runId: "run", sessionKey: "session", idleTimeoutMs: 60_000 }))
.rejects.toMatchObject({ code: "invalid" });
});
it("gives harness probes a finite owner without fabricating a heartbeat run", async () => {
const f = fixture();
await f.attach();
@@ -358,14 +358,16 @@ finally:
}
async function admit(
input: Scope & {
agentId: string;
agentId?: string;
runId?: string;
probeId?: string;
sessionKey: string;
idleTimeoutMs: number;
},
) {
segment(input.agentId);
if (input.agentId) segment(input.agentId);
if (!input.agentId && !input.probeId)
throw new ComputerError("invalid", "A computer run requires an agent");
if ((!input.runId && !input.probeId) || (input.runId && input.probeId))
throw new ComputerError(
"invalid",
@@ -414,17 +416,22 @@ finally:
};
record.ledger.owners.push(owner);
}
record.ledger.placements[input.agentId] ??= {
id: randomUUID(),
root: `${base(record)}/agents/${input.agentId}`,
cwd: `${base(record)}/agents/${input.agentId}`,
};
const agentHome = input.agentId
? `${base(record)}/agents/${input.agentId}`
: `${base(record)}/probes/${input.probeId}`;
if (input.agentId) {
record.ledger.placements[input.agentId] ??= {
id: randomUUID(),
root: agentHome,
cwd: agentHome,
};
}
record.ledger.placements[input.sessionKey] ??= {
id: randomUUID(),
root: `${base(record)}/agents/${input.agentId}`,
root: agentHome,
cwd: input.probeId
? `${base(record)}/probes/${input.probeId}`
: `${base(record)}/agents/${input.agentId}`,
: agentHome,
};
return { record: structuredClone(record), owner: structuredClone(owner) };
});
@@ -795,7 +802,7 @@ finally:
},
) {
const { record, owner } = await scoped(input);
if (!owner.agentId || owner.phase !== "active")
if (owner.phase !== "active" || (!owner.agentId && input.projectId))
throw new ComputerError("conflict", "Workspace owner is not active");
const placement = record.ledger.placements[owner.sessionKey!]!;
if (!input.projectId)
@@ -976,7 +983,7 @@ finally:
admit,
admitProbe(
input: Scope & {
agentId: string;
agentId?: string;
probeId: string;
idleTimeoutMs: number;
},
@@ -45,13 +45,13 @@ export function createComputerEnvironmentDriver(db: Db): EnvironmentRuntimeDrive
driver: "computer",
async acquireRunLease(input) {
if (!(await instanceSettingsService(db).getExperimental()).enableBoatEnvironments) throw new Error("boat_environments_disabled");
if (!input.agentId) throw new Error("computer_agent_required");
if (input.heartbeatRunId && !input.agentId) throw new Error("computer_agent_required");
const idleTimeoutMs = resolvePaperclipRunnerIdleTimeoutMs(input.environment.config.runnerIdleTimeoutMs);
const binding = input.heartbeatRunId ? await computers.admit({ companyId: input.companyId, environmentId: input.environment.id,
agentId: input.agentId, runId: input.heartbeatRunId, idleTimeoutMs,
agentId: input.agentId ?? undefined, runId: input.heartbeatRunId, idleTimeoutMs,
sessionKey: createHash("sha256").update(JSON.stringify([input.agentId, input.executionWorkspaceId ?? input.issueId, input.adapterType, input.executionConfigurationKey])).digest("hex") })
: await computers.admitProbe({ companyId: input.companyId, environmentId: input.environment.id,
agentId: input.agentId, probeId: randomUUID(), idleTimeoutMs });
agentId: input.agentId ?? undefined, probeId: randomUUID(), idleTimeoutMs });
try {
// The durable owner advanced generation; prior retained bookkeeping no
// longer owns the process and must not be reaped as an allocation.
@@ -13445,6 +13445,8 @@ describe("runnerd provider runtime wiring", () => {
it.each([
{ condition: "retired", expected: "verified" },
{ condition: "workspace-coordinate", expected: "verified" },
{ condition: "wrong-workspace-run", expected: "scope_mismatch" },
{ condition: "uncertain", expected: "terminal_state_indeterminate" },
{ condition: "stale-generation", expected: "terminal_state_indeterminate" },
{ condition: "wrong-placement", expected: "scope_mismatch" },
@@ -13460,20 +13462,23 @@ describe("runnerd provider runtime wiring", () => {
const descriptor = { kind: "remote-persistent", leaseId: "prior-lease", providerLeaseId: owner.ownerId,
remoteCwd: "/remote/agent", computerId: owner.computerId, ownerGeneration: owner.generation,
listenerPort: owner.listenerPort, placementId: "placement" };
const db = { select: () => ({ from: (table: unknown) => ({ where: () => ({ limit: async () =>
let leaseQuery: SQL | undefined;
const workspaceCoordinate = ["workspace-coordinate", "wrong-workspace-run"].includes(condition);
const db = { select: () => ({ from: (table: unknown) => ({ where: (query: SQL) => { if (table === environmentLeases) leaseQuery = query; return ({ limit: async () =>
table === environmentLeases ? condition === "wrong-lease" ? [] : [{
providerLeaseId: owner.ownerId,
heartbeatRunId: condition === "wrong-workspace-run" ? "unrelated-run" : prior.binding.runId,
metadata: { agentId: prior.binding.agentId, computerOwner: { ...owner, generation: 1 } },
}] : [{ status: condition === "active-run" ? "running" : "succeeded",
runnerProfileJson: { nativeExecutionInput: prior, nativeComputerWorkspace: descriptor } }],
}) }) }) } as unknown as Db;
}); } }) }) } as unknown as Db;
computerRetirement.isRetired.mockReset().mockImplementation(async ({ owner: requested }) => {
if (condition === "unavailable") throw new Error("ledger unavailable");
return condition !== "uncertain" && requested.generation === (condition === "stale-generation" ? 3 : 2);
});
const input = { db, root, execution: current, identity: { runId: prior.binding.runId,
normalizedSessionId: prior.session.normalizedSessionId!, runnerInstanceId: "prior-runner",
environmentLeaseId: condition === "wrong-lease" ? "other-lease" : "initial-physical-lease" },
environmentLeaseId: workspaceCoordinate ? prior.binding.executionWorkspaceId : condition === "wrong-lease" ? "other-lease" : "initial-physical-lease" },
allowVerifiedBackup: false, remoteRunnerState: true,
runnerExecutionTarget: { kind: "remote", transport: "computer", environmentId: "environment",
remoteCwd: "/remote/agent", resourceAuthority: { ...owner, ownerId: "successor-owner", generation: 1 },
@@ -13493,12 +13498,17 @@ describe("runnerd provider runtime wiring", () => {
expect(computerRetirement.isRetired).not.toHaveBeenCalled();
}
expect(await verifyPriorRunnerdStateForSessionScope({ ...input, allowRetainedWarmRunner: false })).toBe(expected);
if (["retired", "uncertain", "stale-generation", "unavailable"].includes(condition)) {
if (["retired", "workspace-coordinate", "uncertain", "stale-generation", "unavailable"].includes(condition)) {
expect(computerRetirement.isRetired).toHaveBeenCalledExactlyOnceWith({
companyId: current.binding.companyId, environmentId: "environment", agentId: current.binding.agentId,
runId: prior.binding.runId, owner,
});
} else expect(computerRetirement.isRetired).not.toHaveBeenCalled();
if (workspaceCoordinate) {
const query = new PgDialect().sqlToQuery(leaseQuery!);
expect(query.params).toContain(descriptor.leaseId);
expect(query.params).not.toContain(prior.binding.executionWorkspaceId);
}
} finally { await rm(root, { recursive: true, force: true }); }
});
@@ -4368,20 +4368,28 @@ export async function verifyPriorRunnerdStateForSessionScope(input: {
// are authoritative even though no local runner-state.json exists.
// This read cannot retire a live owner or accept a newer generation.
try {
// Warm turns advance the attempt lease while the physical runner keeps
// its initial PRP lease identity. Verify that original lease belongs to
// this exact owner lineage instead of requiring the latest attempt id.
// PRP historically calls the immutable execution-workspace coordinate
// environmentLeaseId. Computer placement records the actual lease. Only
// this exact prior workspace coordinate may resolve through that record.
// Explicit physical lease identities still preserve their warm lineage.
const workspaceCoordinate = input.identity.environmentLeaseId ===
priorExecution.binding.executionWorkspaceId;
const physicalLeaseId = workspaceCoordinate
? priorWorkspace.leaseId
: input.identity.environmentLeaseId;
const [physicalLease] = await input.db.select({
providerLeaseId: environmentLeases.providerLeaseId,
heartbeatRunId: environmentLeases.heartbeatRunId,
metadata: environmentLeases.metadata,
}).from(environmentLeases).where(and(
eq(environmentLeases.id, input.identity.environmentLeaseId),
eq(environmentLeases.id, physicalLeaseId),
eq(environmentLeases.companyId, input.execution.binding.companyId),
eq(environmentLeases.environmentId, target.environmentId),
)).limit(1);
const leaseMetadata = record(physicalLease?.metadata);
const leaseOwner = record(leaseMetadata.computerOwner);
if (physicalLease?.providerLeaseId !== priorWorkspace.computerOwner.ownerId ||
if ((workspaceCoordinate && physicalLease?.heartbeatRunId !== input.identity.runId) ||
physicalLease?.providerLeaseId !== priorWorkspace.computerOwner.ownerId ||
leaseMetadata.agentId !== input.execution.binding.agentId ||
leaseOwner.computerId !== priorWorkspace.computerOwner.computerId ||
leaseOwner.ownerId !== priorWorkspace.computerOwner.ownerId ||