/** * apps/worker — ASSIGN_USER executor (TASK-0112 §5). * * Set a PERSON property on a record to a resolved user (literal cuid | * trigger_user | automation_creator). Re-checks at runtime that the property * exists, belongs to the record's database, and is of type PERSON (fatal * otherwise — the API verified at save, the worker re-verifies). Delegates to * the shared record-write tail (permission + coercion + record.updated). */ import { resolveRecordId, writeRecordPropertyById } from "./record-write.js"; import { resolveUserId } from "./helpers.js"; import { FatalError } from "./classify.js"; import type { ActionExecutor, ActionResult } from "./types.js"; const executor: ActionExecutor = { type: "ASSIGN_USER", async execute(cfg, ctx, deps): Promise { const recordId = resolveRecordId(cfg, ctx); const propertyId = cfg.propertyId as string; const userId = resolveUserId(cfg.userId as string, ctx); // Re-check the property type (the API verified at save; drift is fatal). const prop = await deps.prisma.databaseProperty.findFirst({ where: { id: propertyId, deletedAt: null }, select: { id: true, type: true } }); if (!prop) throw new FatalError("PROPERTY_UNKNOWN", `property ${propertyId} not found`); if (prop.type !== "PERSON") { throw new FatalError("PROPERTY_TYPE_MISMATCH", `property ${propertyId} is ${prop.type}, not PERSON`); } const result = await writeRecordPropertyById(deps, ctx, recordId, propertyId, [userId]); return { output: { recordId: result.recordId, propertyId, userId, eventEmitted: result.eventEmitted }, emittedEvents: result.eventEmitted ? ["record.updated"] : [], audit: { action: "automation.user_assigned", resourceType: "record", resourceId: result.recordId, metadata: { userId, propertyId } } }; } }; export default executor;