chore: initial commit with Phase 0 setup

This commit is contained in:
OG T
2026-06-06 22:55:45 +08:00
commit 9e79e58f87
56 changed files with 16088 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { logAuditEvent } from "@/lib/audit";
import { TaskStatus } from "@agent-bounty/contracts";
// Optional: restrict to cron secret
// export const maxDuration = 60; // Next.js edge/serverless config
export async function GET(req: Request) {
// Find all claims that have expired, but the task is still EXECUTING
const now = new Date();
const expiredClaims = await prisma.claim.findMany({
where: {
status: TaskStatus.EXECUTING,
expires_at: { lt: now },
},
include: {
task: true,
}
});
const rolledBackIds: string[] = [];
for (const claim of expiredClaims) {
if (claim.task.status === TaskStatus.EXECUTING) {
await prisma.$transaction(async (tx) => {
// Rollback Task
await tx.task.update({
where: { id: claim.task_id },
data: {
status: TaskStatus.OPEN,
error_classification: "claim_timeout",
}
});
// Rollback Claim
await tx.claim.update({
where: { id: claim.id },
data: { status: "CANCELLED" }
});
await logAuditEvent(tx, {
actorType: "SYSTEM",
action: "CLAIM_TIMEOUT_REAPER",
entityType: "TASK",
entityId: claim.task_id,
beforeState: { status: TaskStatus.EXECUTING },
afterState: { status: TaskStatus.OPEN },
reason: `Claim ${claim.id} expired at ${claim.expires_at.toISOString()}`,
});
});
rolledBackIds.push(claim.task_id);
}
}
return NextResponse.json({
swept: rolledBackIds.length,
task_ids: rolledBackIds,
});
}