From 221e36ec4a47d1340ae4447ec9ad8e1da48b040c Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 29 May 2026 18:54:53 +0800 Subject: [PATCH] fix: persist rejected device pod jobs --- internal/cloud/access-control.test.ts | 9 +++++++++ internal/cloud/access-control.ts | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/internal/cloud/access-control.test.ts b/internal/cloud/access-control.test.ts index 6e390627..5e0ff10e 100644 --- a/internal/cloud/access-control.test.ts +++ b/internal/cloud/access-control.test.ts @@ -133,6 +133,15 @@ test("cloud api access control grants visible device pods and requires device-po assert.equal(mutatingWithoutLease.body.profileHash, visible.body.devicePods[0].profileHash); assert.equal(mutatingWithoutLease.body.blocker.code, "device_lease_required"); assert.equal(mutatingWithoutLease.body.freshness.stale, true); + const rejectedJob = await getJson(port, `/v1/device-pods/device-pod-71-freq/jobs/${mutatingWithoutLease.body.job.id}`, aliceCookie); + assert.equal(rejectedJob.status, 200); + assert.equal(rejectedJob.body.job.id, mutatingWithoutLease.body.job.id); + assert.equal(rejectedJob.body.status, "blocked"); + assert.equal(rejectedJob.body.blocker.code, "device_lease_required"); + const rejectedOutput = await getJson(port, `/v1/device-pods/device-pod-71-freq/jobs/${mutatingWithoutLease.body.job.id}/output`, aliceCookie); + assert.equal(rejectedOutput.status, 200); + assert.equal(rejectedOutput.body.truncation.truncated, false); + assert.match(rejectedOutput.body.output.error, /requires an active device lease/u); const mutatingWithoutReason = await postJson(port, "/v1/device-pods/device-pod-71-freq/jobs", { intent: "debug.reset" diff --git a/internal/cloud/access-control.ts b/internal/cloud/access-control.ts index 954651bd..32338304 100644 --- a/internal/cloud/access-control.ts +++ b/internal/cloud/access-control.ts @@ -758,9 +758,9 @@ class AccessController { sendJson(response, dispatched.httpStatus, this.jobPayload(dispatched.job, pod, { lease })); } - rejectDevicePodJob(response, pod, actor, { httpStatus, intent, reason = "", args = {}, blocker }) { + async rejectDevicePodJob(response, pod, actor, { httpStatus, intent, reason = "", args = {}, blocker }) { const now = this.now(); - const job = normalizeJob({ + const job = await this.store.createDevicePodJob({ id: `job_devicepod_${randomUUID()}`, devicePodId: pod.id, ownerUserId: actor.id,