Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions apps/api/src/endpoints.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@
taxonomyElementId: "dimension:dependency-currency",
});

expect(res.status).toBe(201);

Check failure on line 286 in apps/api/src/endpoints.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (22)

Failed Test: API Endpoints > POST /api/v1/criteria > creates an observation criterion with a taxonomy element

API Endpoints > POST /api/v1/criteria > creates an observation criterion with a taxonomy element: expected 400 to be 201 // Object.is equality - AssertionError: expected 400 to be 201 // Object.is equality at /home/runner/work/scope/scope/apps/api/src/endpoints.test.ts:286:26 at processTicksAndRejections (node:internal/process/task_queues:103:5) at file:///home/runner/work/scope/scope/node_modules/.pnpm/@vitest+runner@4.1.0/node_modules/@vitest/runner/dist/index.js:1258:20

Check failure on line 286 in apps/api/src/endpoints.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (22)

Failed Test: API Endpoints > POST /api/v1/criteria > creates an observation criterion with a taxonomy element

API Endpoints > POST /api/v1/criteria > creates an observation criterion with a taxonomy element: expected 400 to be 201 // Object.is equality - AssertionError: expected 400 to be 201 // Object.is equality at /home/runner/work/scope/scope/apps/api/src/endpoints.test.ts:286:26 at processTicksAndRejections (node:internal/process/task_queues:103:5) at file:///home/runner/work/scope/scope/node_modules/.pnpm/@vitest+runner@4.1.0/node_modules/@vitest/runner/dist/index.js:1258:20

Check failure on line 286 in apps/api/src/endpoints.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (22)

apps/api/src/endpoints.test.ts > API Endpoints > POST /api/v1/criteria > creates an observation criterion with a taxonomy element

AssertionError: expected 400 to be 201 // Object.is equality - Expected + Received - 201 + 400 ❯ apps/api/src/endpoints.test.ts:286:26
expect(res.body).toHaveProperty("kind", "observation");
expect(res.body).toHaveProperty("taxonomyElementId", "dimension:dependency-currency");
});
Expand All @@ -305,7 +305,7 @@
.post("/api/v1/criteria")
.send({ id: "obs_subj", prompt: "Did the agent add then remove a dep?", dependsOn: [], kind: "observation" });

expect(res.status).toBe(201);

Check failure on line 308 in apps/api/src/endpoints.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (22)

Failed Test: API Endpoints > POST /api/v1/criteria > defaults an observation's subject to 'run'

API Endpoints > POST /api/v1/criteria > defaults an observation's subject to 'run': expected 400 to be 201 // Object.is equality - AssertionError: expected 400 to be 201 // Object.is equality at /home/runner/work/scope/scope/apps/api/src/endpoints.test.ts:308:26 at processTicksAndRejections (node:internal/process/task_queues:103:5) at file:///home/runner/work/scope/scope/node_modules/.pnpm/@vitest+runner@4.1.0/node_modules/@vitest/runner/dist/index.js:1258:20

Check failure on line 308 in apps/api/src/endpoints.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (22)

Failed Test: API Endpoints > POST /api/v1/criteria > defaults an observation's subject to 'run'

API Endpoints > POST /api/v1/criteria > defaults an observation's subject to 'run': expected 400 to be 201 // Object.is equality - AssertionError: expected 400 to be 201 // Object.is equality at /home/runner/work/scope/scope/apps/api/src/endpoints.test.ts:308:26 at processTicksAndRejections (node:internal/process/task_queues:103:5) at file:///home/runner/work/scope/scope/node_modules/.pnpm/@vitest+runner@4.1.0/node_modules/@vitest/runner/dist/index.js:1258:20

Check failure on line 308 in apps/api/src/endpoints.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (22)

apps/api/src/endpoints.test.ts > API Endpoints > POST /api/v1/criteria > defaults an observation's subject to 'run'

AssertionError: expected 400 to be 201 // Object.is equality - Expected + Received - 201 + 400 ❯ apps/api/src/endpoints.test.ts:308:26
expect(res.body).toHaveProperty("subject", "run");
});

Expand All @@ -316,7 +316,7 @@
.post("/api/v1/criteria")
.send({ id: "obs_iter", prompt: "x", dependsOn: [], kind: "observation", subject: "iteration" });

expect(res.status).toBe(201);

Check failure on line 319 in apps/api/src/endpoints.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (22)

Failed Test: API Endpoints > POST /api/v1/criteria > creates an observation with an explicit subject:'iteration' override

API Endpoints > POST /api/v1/criteria > creates an observation with an explicit subject:'iteration' override: expected 400 to be 201 // Object.is equality - AssertionError: expected 400 to be 201 // Object.is equality at /home/runner/work/scope/scope/apps/api/src/endpoints.test.ts:319:26 at processTicksAndRejections (node:internal/process/task_queues:103:5) at file:///home/runner/work/scope/scope/node_modules/.pnpm/@vitest+runner@4.1.0/node_modules/@vitest/runner/dist/index.js:1258:20

Check failure on line 319 in apps/api/src/endpoints.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (22)

Failed Test: API Endpoints > POST /api/v1/criteria > creates an observation with an explicit subject:'iteration' override

API Endpoints > POST /api/v1/criteria > creates an observation with an explicit subject:'iteration' override: expected 400 to be 201 // Object.is equality - AssertionError: expected 400 to be 201 // Object.is equality at /home/runner/work/scope/scope/apps/api/src/endpoints.test.ts:319:26 at processTicksAndRejections (node:internal/process/task_queues:103:5) at file:///home/runner/work/scope/scope/node_modules/.pnpm/@vitest+runner@4.1.0/node_modules/@vitest/runner/dist/index.js:1258:20

Check failure on line 319 in apps/api/src/endpoints.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests (22)

apps/api/src/endpoints.test.ts > API Endpoints > POST /api/v1/criteria > creates an observation with an explicit subject:'iteration' override

AssertionError: expected 400 to be 201 // Object.is equality - Expected + Received - 201 + 400 ❯ apps/api/src/endpoints.test.ts:319:26
expect(res.body).toHaveProperty("subject", "iteration");
});

Expand Down Expand Up @@ -1955,6 +1955,44 @@
expect(res.status).toBe(201);
const doc = (mocks.collection.insertOne as any).mock.calls[0][0];
expect(doc).toHaveProperty("reasoningEffort", "high");
expect(doc).toHaveProperty("submissionExpectedRequestCount", 1);
const submissionInsert = (mocks.submissionCollection.updateOne as any).mock.calls[0][1].$setOnInsert;
expect(submissionInsert.requestIds).toEqual([doc._id]);
expect(submissionInsert.run.requests).toEqual([
{ requestId: doc._id, runId: doc.run._id },
]);
});

it("creates one complete submission vector for count fan-out", async () => {
const res = await request(testServer())
.post(`/api/v1/requests?worker=coder-acp-copilot&projectId=${TEST_PROJECT_ID}`)
.send({
scenario: { task: "Build something", criteria: ["works"] },
count: 3,
});

expect(res.status).toBe(201);
const docs = (mocks.collection.insertMany as any).mock.calls[0][0];
expect(docs).toHaveLength(3);
expect(docs.every((doc: { submissionExpectedRequestCount: number }) =>
doc.submissionExpectedRequestCount === 3)).toBe(true);
expect(
docs.map((doc: { submissionRequestIndex: number }) => doc.submissionRequestIndex),
).toEqual([0, 1, 2]);
expect(
docs.every(
(doc: { submissionInitialRunId: string; run: { _id: string } }) =>
doc.submissionInitialRunId === doc.run._id,
),
).toBe(true);
const submissionInsert = (mocks.submissionCollection.updateOne as any).mock.calls[0][1].$setOnInsert;
expect(submissionInsert.requestIds).toEqual(docs.map((doc: { _id: string }) => doc._id));
expect(submissionInsert.run.requests).toEqual(
docs.map((doc: { _id: string; run: { _id: string } }) => ({
requestId: doc._id,
runId: doc.run._id,
})),
);
});

it("profile reasoningEffort takes precedence over client-provided effort", async () => {
Expand Down Expand Up @@ -2259,6 +2297,7 @@
new Set(["base-profile", "var-profile"]),
);
for (const doc of docs) {
expect(doc.submissionExpectedRequestCount).toBe(2);
expect(Array.isArray(doc.gates)).toBe(true);
const selectGate = doc.gates.find((g: { gate: string }) => g.gate === "select");
const buildGate = doc.gates.find((g: { gate: string }) => g.gate === "build");
Expand All @@ -2269,6 +2308,10 @@
expect(buildGate.promptId).toBe("tp-build");
expect(buildGate.promptText).toBeUndefined();
}
const submissionInsert = (mocks.submissionCollection.updateOne as any).mock.calls[0][1].$setOnInsert;
expect(submissionInsert.requestIds).toEqual(
docs.map((doc: { _id: string }) => doc._id),
);
// Response surfaces the configured gate count.
expect(res.body.gates).toBe(2);
});
Expand Down Expand Up @@ -2426,6 +2469,9 @@
expect(insertCall[0]).toHaveProperty("taskPromptId", "tp-123");
expect(insertCall[0]).toHaveProperty("model", "gpt-4o");
expect(insertCall[0]).toHaveProperty("maxIterations", 5);
expect(insertCall[0]).toHaveProperty("submissionExpectedRequestCount", 1);
const submissionInsert = (mocks.submissionCollection.updateOne as any).mock.calls[0][1].$setOnInsert;
expect(submissionInsert.requestIds).toEqual([insertCall[0]._id]);
});

it("applies profile override: uses profile fields for worker, model, mcpServers, skillRevisions, extensions", async () => {
Expand Down Expand Up @@ -2802,11 +2848,13 @@
it("retries eligible requests and skips non-terminal ones", async () => {
const doc1 = {
_id: "req-1",
submissionId: "submission-1",
workerType: "coder-acp-copilot",
run: { _id: "run-1", attemptNumber: 1, status: "done", outcome: "failed" },
};
const doc2 = {
_id: "req-2",
submissionId: "submission-1",
workerType: "coder-acp-copilot",
run: { _id: "run-2", attemptNumber: 1, status: "processing" },
};
Expand All @@ -2832,6 +2880,22 @@
$set: expect.objectContaining({ agentVersion: "1.0.0" }),
}),
);
expect(mocks.submissionCollection.updateMany).toHaveBeenNthCalledWith(
1,
{ _id: { $in: ["submission-1"] } },
expect.objectContaining({
$set: expect.objectContaining({
"run.reconcileAfter": expect.any(Date),
}),
}),
);
expect(mocks.submissionCollection.updateMany).toHaveBeenNthCalledWith(
2,
{ _id: { $in: ["submission-1"] } },
expect.objectContaining({
$unset: { "run.reconcileAfter": "" },
}),
);
});

it("returns 400 when ids array is empty", async () => {
Expand Down
14 changes: 14 additions & 0 deletions apps/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { registerInsightsRoutes } from "./routes/insights.js";
import { registerSecretsRoutes } from "./routes/secrets.js";
import { registerProfilesRoutes } from "./routes/profiles.js";
import { registerProjectsRoutes } from "./routes/projects.js";
import { registerSubmissionsRoutes } from "./routes/submissions.js";
import { ProjectScopeError } from "./utils/project-scope.js";
import { registerUsersRoutes } from "./routes/users.js";
import { shutdownPortalCopilotClientPool } from "./copilot-client-pool.js";
Expand All @@ -59,6 +60,8 @@ import type {
InsightDocument,
RequestDocument,
RunHistoryDocument,
SubmissionDocument,
SubmissionRunHistoryDocument,
CodingAgentDocument,
ModelDocument,
McpServerDocument,
Expand Down Expand Up @@ -97,6 +100,8 @@ let mongoClient: MongoClient;
let db: Db;
let collection: Collection<RequestDocument>;
let runsCol: Collection<RunHistoryDocument>;
let submissionCollection: Collection<SubmissionDocument>;
let submissionRunsCollection: Collection<SubmissionRunHistoryDocument>;
let projectCollection: Collection<ProjectDocument>;
let projectStore: ProjectStore;
let criteriaCollection: Collection<CriteriaDocument>;
Expand Down Expand Up @@ -144,6 +149,8 @@ async function initializeClients(): Promise<void> {
db = mongoClient.db(mongoDatabase);
collection = db.collection<RequestDocument>(mongoCollection);
runsCol = db.collection<RunHistoryDocument>("runs");
submissionCollection = db.collection<SubmissionDocument>("submissions");
submissionRunsCollection = db.collection<SubmissionRunHistoryDocument>("submission-runs");
projectCollection = db.collection<ProjectDocument>("projects");
projectStore = new ProjectStore(projectCollection);
criteriaCollection = db.collection<CriteriaDocument>("criteria");
Expand Down Expand Up @@ -277,6 +284,8 @@ const routeCtx: RouteContext = {
get db() { return db; },
get requestCollection() { return collection; },
get runsCollection() { return runsCol; },
get submissionCollection() { return submissionCollection; },
get submissionRunsCollection() { return submissionRunsCollection; },
get projectCollection() { return projectCollection; },
get criteriaCollection() { return criteriaCollection; },
get promptFeatureCollection() { return promptFeatureCollection; },
Expand Down Expand Up @@ -338,6 +347,7 @@ app.use(createUserAccessMiddleware(() => userAccessResolver));
registerSecretsRoutes(routeCtx);
registerSystemRoutes(routeCtx);
registerProjectsRoutes(routeCtx);
registerSubmissionsRoutes(routeCtx);
registerRequestsRoutes(routeCtx);
registerRequestsCancelRoutes(routeCtx);
registerRequestsLogsRoutes(routeCtx);
Expand Down Expand Up @@ -424,6 +434,8 @@ export interface TestDependencies {
db?: Db;
collection?: Collection<RequestDocument>;
runsCollection?: Collection<RunHistoryDocument>;
submissionCollection?: Collection<SubmissionDocument>;
submissionRunsCollection?: Collection<SubmissionRunHistoryDocument>;
criteriaCollection?: Collection<CriteriaDocument>;
promptFeatureCollection?: Collection<PromptFeatureDocument>;
reportCollection?: Collection<ReportDocument>;
Expand Down Expand Up @@ -465,6 +477,8 @@ export function _injectTestDependencies(deps: TestDependencies): void {
if (deps.db) db = deps.db;
if (deps.collection) collection = deps.collection;
if (deps.runsCollection) runsCol = deps.runsCollection;
if (deps.submissionCollection) submissionCollection = deps.submissionCollection;
if (deps.submissionRunsCollection) submissionRunsCollection = deps.submissionRunsCollection;
if (deps.criteriaCollection) criteriaCollection = deps.criteriaCollection;
if (deps.promptFeatureCollection) promptFeatureCollection = deps.promptFeatureCollection;
if (deps.reportCollection) reportCollection = deps.reportCollection;
Expand Down
6 changes: 6 additions & 0 deletions apps/api/src/route-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ import type {
ReportTemplateResponseSchema,
RequestResponseSchema,
RunHistoryDocumentSchema,
SubmissionDocumentSchema,
SubmissionRunHistoryDocumentSchema,
} from "shared";

// ─── Document types (inferred from Zod schemas) ─────────────────────────────
Expand All @@ -74,6 +76,8 @@ export type ReportTrigger = z.infer<typeof ReportTriggerSchema>;
export type ReportTemplateDocument = Omit<z.infer<typeof ReportTemplateResponseSchema>, "_id">;
export type RequestDocument = z.infer<typeof RequestResponseSchema>;
export type RunHistoryDocument = z.infer<typeof RunHistoryDocumentSchema>;
export type SubmissionDocument = z.infer<typeof SubmissionDocumentSchema>;
export type SubmissionRunHistoryDocument = z.infer<typeof SubmissionRunHistoryDocumentSchema>;

export type WorkerType = string;

Expand All @@ -92,6 +96,8 @@ export interface RouteContext {
db: Db;
requestCollection: Collection<RequestDocument>;
runsCollection: Collection<RunHistoryDocument>;
submissionCollection: Collection<SubmissionDocument>;
submissionRunsCollection: Collection<SubmissionRunHistoryDocument>;
projectCollection: Collection<ProjectDocument>;
criteriaCollection: Collection<CriteriaDocument>;
promptFeatureCollection: Collection<PromptFeatureDocument>;
Expand Down
97 changes: 96 additions & 1 deletion apps/api/src/routes/requests/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
isCriterionCompatibleWithGate,
orderGates,
computeTaskPromptId,
ensureNativeSubmission,
} from "shared";
import type {
ProfileDocument,
Expand Down Expand Up @@ -844,6 +845,7 @@ apiRoute(ctx.app, ctx.registry, {
const variationResults: Array<{ profileId: string; label?: string; ids: string[] }> = [];
const agentsMdPromptId = await resolveAgentsMdPromptId();
const agentsMdFields = buildAgentsMdFields(agentsMdPromptId);
const expectedRequestCount = resolved.length * count;

for (const r of resolved) {
const newIds: string[] = [];
Expand Down Expand Up @@ -878,6 +880,9 @@ apiRoute(ctx.app, ctx.registry, {
profileVersionId: r.profileVersion.ref ?? r.profileVersion._id,
...(persistedVariationGates ? { gates: persistedVariationGates } : {}),
submissionId,
submissionExpectedRequestCount: expectedRequestCount,
submissionRequestIndex: newDocs.length,
submissionInitialRunId: runId,
...agentsMdFields,
run: { _id: runId, attemptNumber: 1, status: "pending", logsUrl: ctx.blobStorage.getLogsBlobUrl(`${requestId}/runs/${runId}/run.jsonl`) },
};
Expand All @@ -891,6 +896,20 @@ apiRoute(ctx.app, ctx.registry, {
}

await ctx.requestCollection.insertMany(newDocs);
await ensureNativeSubmission({
collections: { submissions: ctx.submissionCollection },
submissionId,
projectId,
requests: newDocs.map((doc) => ({
requestId: doc._id,
runId: doc.run!._id,
})),
createdAt: newDocs[0]?.createdAt,
});
await ctx.requestCollection.updateMany(
{ _id: { $in: allNewIds }, submissionId },
{ $set: { submissionFinalizedAt: new Date() } },
);

res.status(201).json({
ids: allNewIds,
Expand Down Expand Up @@ -1274,7 +1293,7 @@ apiRoute(ctx.app, ctx.registry, {
: undefined;

// Persisted observation-criteria selection (issue #1156); deduped, evaluated
// by the pp-taxonomy post-processor. Absent/empty = no observations evaluated.
// by the pp-observations post-processor. Absent/empty = no observations evaluated.
const persistedObservations: string[] | undefined = observationsProvided
? [...new Set(resolvedObservations)]
: undefined;
Expand Down Expand Up @@ -1316,6 +1335,9 @@ apiRoute(ctx.app, ctx.registry, {
...(persistedGates ? { gates: persistedGates } : {}),
...(persistedObservations ? { observations: persistedObservations } : {}),
submissionId,
submissionExpectedRequestCount: count,
submissionRequestIndex: i,
submissionInitialRunId: runId,
...agentsMdFields,
// Mint a distinct run id for the first attempt. Blob artifacts
// are scoped under `{requestId}/runs/{runId}/...` so retries
Expand All @@ -1327,6 +1349,20 @@ apiRoute(ctx.app, ctx.registry, {

// Bulk insert all documents — scheduler will dispatch to queues
await ctx.requestCollection.insertMany(newDocs);
await ensureNativeSubmission({
collections: { submissions: ctx.submissionCollection },
submissionId,
projectId,
requests: newDocs.map((doc) => ({
requestId: doc._id,
runId: doc.run!._id,
})),
createdAt: newDocs[0]?.createdAt,
});
await ctx.requestCollection.updateMany(
{ _id: { $in: newIds }, submissionId },
{ $set: { submissionFinalizedAt: new Date() } },
);

console.log(`Created ${count} ${mode} requests for ${workerType} (priority: ${requestedPriority ?? 0})`);

Expand Down Expand Up @@ -1379,6 +1415,9 @@ apiRoute(ctx.app, ctx.registry, {
...(persistedGates ? { gates: persistedGates } : {}),
...(persistedObservations ? { observations: persistedObservations } : {}),
submissionId,
submissionExpectedRequestCount: 1,
submissionRequestIndex: 0,
submissionInitialRunId: runId,
...agentsMdFields,
// Mint a distinct run id for the first attempt. Blob artifacts
// are scoped under `{requestId}/runs/{runId}/...` so retries
Expand All @@ -1388,6 +1427,17 @@ apiRoute(ctx.app, ctx.registry, {

// Store in MongoDB — scheduler will dispatch to queue
await ctx.requestCollection.insertOne(requestDoc);
await ensureNativeSubmission({
collections: { submissions: ctx.submissionCollection },
submissionId,
projectId,
requests: [{ requestId, runId }],
createdAt: requestDoc.createdAt,
});
await ctx.requestCollection.updateOne(
{ _id: requestId, submissionId },
{ $set: { submissionFinalizedAt: new Date() } },
);

console.log(`Created ${mode} request ${requestId} for ${workerType} (priority: ${requestedPriority ?? 0})`);

Expand Down Expand Up @@ -2206,6 +2256,9 @@ apiRoute(ctx.app, ctx.registry, {
...(original.agentsMdPromptId ? { agentsMdPromptId: original.agentsMdPromptId } : {}),
...(original.agentsMdParentIds && original.agentsMdParentIds.length > 0 ? { agentsMdParentIds: original.agentsMdParentIds } : {}),
submissionId,
submissionExpectedRequestCount: originalRuns.length * count,
submissionRequestIndex: newDocs.length,
submissionInitialRunId: runId,
// Bulk re-submit creates a brand-new request — mint a distinct
// run id for the first attempt so blob artifacts live under
// `{requestId}/runs/{runId}/...` (independent of the original run).
Expand All @@ -2219,6 +2272,20 @@ apiRoute(ctx.app, ctx.registry, {
// Insert all new documents — scheduler will dispatch to queues
if (newDocs.length > 0) {
await ctx.requestCollection.insertMany(newDocs);
await ensureNativeSubmission({
collections: { submissions: ctx.submissionCollection },
submissionId,
projectId: newDocs[0].projectId,
requests: newDocs.map((doc) => ({
requestId: doc._id,
runId: doc.run!._id,
})),
createdAt: newDocs[0].createdAt,
});
await ctx.requestCollection.updateMany(
{ _id: { $in: newIds }, submissionId },
{ $set: { submissionFinalizedAt: new Date() } },
);
}

console.log(`Bulk re-submitted ${newIds.length} runs from ${originalRuns.length} originals (count=${count})`);
Expand Down Expand Up @@ -3129,6 +3196,24 @@ apiRoute(ctx.app, ctx.registry, {
{ _id: { $in: ids }, deletedAt: { $exists: false } },
).toArray();
const requestMap = new Map(requests.map((r) => [r._id, r]));
const affectedSubmissionIds = [
...new Set(
requests.flatMap((request) =>
request.submissionId ? [request.submissionId] : [],
),
),
];
if (affectedSubmissionIds.length > 0) {
await ctx.submissionCollection.updateMany(
{ _id: { $in: affectedSubmissionIds } },
{
$set: {
"run.reconcileAfter": new Date(Date.now() + 60_000),
updatedAt: new Date(),
},
},
);
}

const results: Array<{ requestId: string; runId?: string; attemptNumber?: number; error?: string }> = [];
let retried = 0;
Expand Down Expand Up @@ -3210,6 +3295,16 @@ apiRoute(ctx.app, ctx.registry, {
retried++;
}

if (affectedSubmissionIds.length > 0) {
await ctx.submissionCollection.updateMany(
{ _id: { $in: affectedSubmissionIds } },
{
$unset: { "run.reconcileAfter": "" },
$set: { updatedAt: new Date() },
},
);
}

res.status(201).json({ retried, skipped, results });
},
});
Expand Down
Loading
Loading