@mastra/factory 0.1.0-alpha.5 → 0.1.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/factory.d.ts +2 -1
- package/dist/factory.d.ts.map +1 -1
- package/dist/factory.js +141 -9
- package/dist/factory.js.map +1 -1
- package/dist/index.js +141 -9
- package/dist/index.js.map +1 -1
- package/dist/integrations/github/integration.js +108 -1
- package/dist/integrations/github/integration.js.map +1 -1
- package/dist/integrations/github/pat.d.ts +38 -0
- package/dist/integrations/github/pat.d.ts.map +1 -0
- package/dist/integrations/github/pat.js +48 -0
- package/dist/integrations/github/pat.js.map +1 -0
- package/dist/integrations/github/provenance.js.map +1 -1
- package/dist/integrations/github/routes.d.ts.map +1 -1
- package/dist/integrations/github/routes.js +94 -1
- package/dist/integrations/github/routes.js.map +1 -1
- package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
- package/dist/integrations/github/session-subscriptions.js +30 -0
- package/dist/integrations/github/session-subscriptions.js.map +1 -1
- package/dist/integrations/github/token-refresh.d.ts +6 -0
- package/dist/integrations/github/token-refresh.d.ts.map +1 -1
- package/dist/integrations/github/token-refresh.js +10 -0
- package/dist/integrations/github/token-refresh.js.map +1 -1
- package/dist/integrations/platform/github/integration.d.ts.map +1 -1
- package/dist/integrations/platform/github/integration.js +110 -2
- package/dist/integrations/platform/github/integration.js.map +1 -1
- package/dist/routes/surface.js +7 -1
- package/dist/routes/surface.js.map +1 -1
- package/dist/routes/work-items.js.map +1 -1
- package/dist/rules/start-coordinator.d.ts.map +1 -1
- package/dist/rules/start-coordinator.js +7 -1
- package/dist/rules/start-coordinator.js.map +1 -1
- package/dist/workspace.d.ts +5 -0
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +64 -5
- package/dist/workspace.js.map +1 -1
- package/package.json +4 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/routes/work-items.ts","../../src/rules/start-coordinator.ts","../../src/rules/types.ts","../../src/storage/domains/queue-health/base.ts","../../src/storage/domains/work-items/base.ts","../../src/storage/domains/work-items/metrics.ts","../../src/routes/route.ts"],"sourcesContent":["/**\n * Mastra `apiRoutes` for Factory work items (the kanban board).\n *\n * Registered alongside the other `/web/*` routes behind the host auth gate.\n * The board is org-wide: every route re-resolves the caller's `(orgId, userId)`\n * tenant and scopes reads/writes by `orgId`, so any org member sees and moves\n * the same cards while `created_by` / stage history record who acted.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport type {\n FactoryStartCoordinator,\n FactoryStartPreparedResult,\n FactoryStartRequest,\n} from '../rules/start-coordinator.js';\nimport { FactoryStartTransitionError } from '../rules/start-coordinator.js';\nimport type { FactoryTransitionRequest, FactoryTransitionService } from '../rules/transition-service.js';\nimport type { FactoryRuleBoard, FactoryRuleStage } from '../rules/types.js';\nimport { FACTORY_RULE_BOARDS, FACTORY_RULE_STAGES } from '../rules/types.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport { thresholdsOrDefault } from '../storage/domains/queue-health/base.js';\nimport type {\n CreateWorkItemInput,\n ExternalWorkItemSource,\n FactoryDeferredDecisionRecord,\n FactoryDispatchStatus,\n UpdateWorkItemInput,\n WorkItemPriorState,\n WorkItemRow,\n WorkItemSessionInput,\n WorkItemStage,\n WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport { WorkItemRelationError } from '../storage/domains/work-items/base.js';\nimport { computeFactoryMetrics, parseMetricsRange } from '../storage/domains/work-items/metrics.js';\nimport type { RouteDependencies } from './route.js';\nimport { Route } from './route.js';\n\nexport interface WorkItemRoutesDeps extends RouteDependencies {\n audit: AuditEmitter;\n /** Factory projects domain — validates the `:id` project belongs to the caller's org. */\n projects: FactoryProjectsStorage;\n /** Work-items domain backing the kanban board. */\n workItems: WorkItemsStorage;\n /** Per-project queue-health threshold config. */\n queueHealth: QueueHealthStorage;\n /** Governed stage-transition service. Stage moves 503 when absent. */\n transitionService?: Pick<FactoryTransitionService, 'transition' | 'ruleSetVersion'>;\n /** Coordinator that binds a Factory run before dispatching its kickoff. */\n startCoordinator?: Pick<FactoryStartCoordinator, 'prepare'>;\n}\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nconst MAX_STAGES = 16;\nconst MAX_STAGE_LENGTH = 64;\nconst MAX_METADATA_BYTES = 16 * 1024;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction validStages(value: unknown): value is WorkItemStage[] {\n return (\n Array.isArray(value) &&\n value.length > 0 &&\n value.length <= MAX_STAGES &&\n value.every(\n stage => typeof stage === 'string' && stage.length <= MAX_STAGE_LENGTH && /^[a-z0-9][a-z0-9_-]*$/i.test(stage),\n ) &&\n new Set(value).size === value.length\n );\n}\n\nfunction validMetadata(value: unknown): value is Record<string, unknown> | null {\n if (value === null) return true;\n if (!isRecord(value)) return false;\n try {\n return JSON.stringify(value).length <= MAX_METADATA_BYTES;\n } catch {\n return false;\n }\n}\n\nfunction parseExternalSource(value: unknown): ExternalWorkItemSource | null | undefined {\n if (value === undefined || value === null) return value;\n if (!isRecord(value)) return undefined;\n const { integrationId, type, externalId, url } = value;\n if (typeof integrationId !== 'string' || integrationId.length === 0 || integrationId.length > 128) return undefined;\n if (typeof type !== 'string' || type.length === 0 || type.length > 128) return undefined;\n if (typeof externalId !== 'string' || externalId.length === 0 || externalId.length > 512) return undefined;\n if (url !== undefined && (typeof url !== 'string' || url.length > 2048)) return undefined;\n return { integrationId, type, externalId, ...(url !== undefined ? { url } : {}) };\n}\n\nfunction parseParentWorkItemId(value: unknown): string | null | undefined {\n if (value === null) return null;\n if (typeof value !== 'string' || !UUID_RE.test(value)) return undefined;\n return value;\n}\n\nfunction parseSessions(value: unknown): Record<string, WorkItemSessionInput> | undefined {\n if (!isRecord(value)) return undefined;\n const out: Record<string, WorkItemSessionInput> = {};\n for (const [role, session] of Object.entries(value)) {\n if (!role || role.length > 64 || !isRecord(session)) return undefined;\n const { sessionId, branch, threadId } = session;\n if (typeof sessionId !== 'string' || sessionId.length === 0 || sessionId.length > 512) return undefined;\n if (typeof branch !== 'string' || branch.length === 0 || branch.length > 512) return undefined;\n if (typeof threadId !== 'string' || threadId.length === 0 || threadId.length > 512) return undefined;\n out[role] = { sessionId, branch, threadId };\n }\n return out;\n}\n\n/** Validate an untrusted create body. Unknown keys are dropped. */\nexport function parseCreateWorkItem(body: unknown): CreateWorkItemInput | null {\n if (!isRecord(body)) return null;\n const { externalSource, title, stages, sessions, metadata } = body;\n if (typeof title !== 'string' || title.trim().length === 0 || title.length > 500) return null;\n\n const hasParentWorkItemId = 'parentWorkItemId' in body;\n const parentWorkItemId = hasParentWorkItemId ? parseParentWorkItemId(body.parentWorkItemId) : undefined;\n if (hasParentWorkItemId && parentWorkItemId === undefined) return null;\n const parsedSource = parseExternalSource(externalSource);\n if (externalSource !== undefined && parsedSource === undefined) return null;\n if (stages !== undefined && !validStages(stages)) return null;\n const parsedSessions = sessions === undefined ? undefined : parseSessions(sessions);\n if (sessions !== undefined && parsedSessions === undefined) return null;\n if (metadata !== undefined && !validMetadata(metadata)) return null;\n\n return {\n title: title.trim(),\n ...(parsedSource !== undefined ? { externalSource: parsedSource } : {}),\n ...(hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {}),\n ...(stages !== undefined ? { stages } : {}),\n ...(parsedSessions !== undefined ? { sessions: parsedSessions } : {}),\n ...(metadata !== undefined ? { metadata } : {}),\n };\n}\n\n/** Validate an untrusted patch body. Unknown keys are dropped. */\nexport function parseUpdateWorkItem(body: unknown): UpdateWorkItemInput | null {\n if (!isRecord(body)) return null;\n const { title, stages, sessions, metadata } = body;\n const hasParentWorkItemId = 'parentWorkItemId' in body;\n if (\n title === undefined &&\n stages === undefined &&\n sessions === undefined &&\n metadata === undefined &&\n !hasParentWorkItemId\n )\n return null;\n const parentWorkItemId = hasParentWorkItemId ? parseParentWorkItemId(body.parentWorkItemId) : undefined;\n if (hasParentWorkItemId && parentWorkItemId === undefined) return null;\n if (title !== undefined && (typeof title !== 'string' || title.trim().length === 0 || title.length > 500))\n return null;\n if (stages !== undefined && !validStages(stages)) return null;\n const parsedSessions = sessions === undefined ? undefined : parseSessions(sessions);\n if (sessions !== undefined && parsedSessions === undefined) return null;\n if (metadata !== undefined && !validMetadata(metadata)) return null;\n\n return {\n ...(hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {}),\n ...(title !== undefined ? { title: title.trim() } : {}),\n ...(stages !== undefined ? { stages } : {}),\n ...(parsedSessions !== undefined ? { sessions: parsedSessions } : {}),\n ...(metadata !== undefined ? { metadata } : {}),\n };\n}\n\nasync function readJson(c: Context): Promise<unknown | undefined> {\n try {\n return await c.req.json();\n } catch {\n return undefined;\n }\n}\n\n/** Fields a PATCH touched, for the bounded `updated` event summary. */\nfunction patchedFields(patch: Record<string, unknown>): string[] {\n return Object.keys(patch).filter(key => patch[key] !== undefined);\n}\n\nfunction boundedText(value: unknown, max: number): string | undefined {\n if (typeof value !== 'string') return undefined;\n const normalized = value.trim();\n return normalized.length > 0 && normalized.length <= max ? normalized : undefined;\n}\n\nfunction parseTransitionBody(\n body: unknown,\n): Omit<FactoryTransitionRequest, 'orgId' | 'factoryProjectId' | 'workItemId' | 'actor'> | null {\n if (!isRecord(body)) return null;\n const board = FACTORY_RULE_BOARDS.includes(body.board as FactoryRuleBoard)\n ? (body.board as FactoryRuleBoard)\n : undefined;\n const stage = FACTORY_RULE_STAGES.includes(body.stage as FactoryRuleStage)\n ? (body.stage as FactoryRuleStage)\n : undefined;\n const requestId = boundedText(body.requestId, 256);\n const cause = boundedText(body.cause, 256);\n if (\n !board ||\n !stage ||\n !requestId ||\n !UUID_RE.test(requestId) ||\n !cause ||\n !Number.isInteger(body.expectedRevision) ||\n Number(body.expectedRevision) < 1\n ) {\n return null;\n }\n return {\n board,\n stage,\n expectedRevision: Number(body.expectedRevision),\n ingress: { type: 'human', identity: requestId },\n cause,\n };\n}\n\nfunction parseInvocation(value: unknown): FactoryStartRequest['invocation'] | undefined | null {\n if (value === undefined) return undefined;\n if (!isRecord(value)) return null;\n if (value.type === 'prompt') {\n const prompt = boundedText(value.prompt, 16_384);\n return prompt ? { type: 'prompt', prompt } : null;\n }\n if (value.type === 'skill') {\n const skillName = boundedText(value.skillName, 64);\n const args = typeof value.arguments === 'string' && value.arguments.length <= 16_384 ? value.arguments : undefined;\n return skillName && args !== undefined ? { type: 'skill', skillName, arguments: args } : null;\n }\n return null;\n}\n\nfunction parseStartBody(\n body: unknown,\n tenant: { orgId: string; userId: string },\n factoryProjectId: string,\n): FactoryStartRequest | null {\n if (!isRecord(body) || !isRecord(body.workItem)) return null;\n const input = parseCreateWorkItem(body.workItem.input);\n const sessionId = boundedText(body.sessionId, 256);\n const threadTitle = boundedText(body.threadTitle, 512);\n const kickoffKey = boundedText(body.kickoffKey, 256);\n const invocation = parseInvocation(body.invocation);\n const destinationStage = FACTORY_RULE_STAGES.includes(body.destinationStage as FactoryRuleStage)\n ? (body.destinationStage as FactoryRuleStage)\n : undefined;\n const role = boundedText(body.workItem.role, 32);\n const id = body.workItem.id === undefined ? undefined : boundedText(body.workItem.id, 64);\n if (body.workItem.id !== undefined && (!id || !UUID_RE.test(id))) return null;\n if (\n !input ||\n !sessionId ||\n !UUID_RE.test(sessionId) ||\n !threadTitle ||\n !kickoffKey ||\n !UUID_RE.test(kickoffKey) ||\n invocation === null ||\n !destinationStage ||\n !role\n ) {\n return null;\n }\n const threadTags = isRecord(body.threadTags)\n ? Object.fromEntries(\n Object.entries(body.threadTags)\n .filter(\n (entry): entry is [string, string] =>\n boundedText(entry[0], 64) !== undefined && boundedText(entry[1], 256) !== undefined,\n )\n .map(([key, value]) => [key, value.trim()]),\n )\n : undefined;\n return {\n ...tenant,\n factoryProjectId,\n sessionId,\n threadTitle,\n threadTags,\n kickoffKey,\n invocation,\n destinationStage,\n workItem: { id, role, input },\n };\n}\n\nconst DECISION_STATUSES = new Set<FactoryDispatchStatus>(['pending', 'leased', 'retry', 'succeeded', 'failed']);\nconst DEFAULT_DECISION_PAGE_SIZE = 25;\nconst MAX_DECISION_PAGE_SIZE = 50;\n\nfunction parseDecisionStatuses(raw: string | undefined): FactoryDispatchStatus[] | undefined {\n if (!raw) return undefined;\n const statuses = [...new Set(raw.split(',').map(status => status.trim()))].filter(\n (status): status is FactoryDispatchStatus => DECISION_STATUSES.has(status as FactoryDispatchStatus),\n );\n return statuses.length > 0 ? statuses : undefined;\n}\n\nfunction parseDecisionLimit(raw: string | undefined): number {\n const parsed = raw ? Number.parseInt(raw, 10) : DEFAULT_DECISION_PAGE_SIZE;\n if (!Number.isFinite(parsed)) return DEFAULT_DECISION_PAGE_SIZE;\n return Math.max(1, Math.min(MAX_DECISION_PAGE_SIZE, parsed));\n}\n\nfunction encodeDecisionCursor(decision: FactoryDeferredDecisionRecord): string {\n return Buffer.from(JSON.stringify([decision.createdAt.toISOString(), decision.id]), 'utf8').toString('base64url');\n}\n\nfunction parseDecisionCursor(raw: string | undefined): { createdAt: Date; id: string } | undefined {\n if (!raw) return undefined;\n try {\n const decoded = JSON.parse(Buffer.from(raw, 'base64url').toString('utf8')) as unknown;\n if (\n !Array.isArray(decoded) ||\n decoded.length !== 2 ||\n typeof decoded[0] !== 'string' ||\n typeof decoded[1] !== 'string'\n ) {\n return undefined;\n }\n const createdAt = new Date(decoded[0]);\n if (Number.isNaN(createdAt.getTime()) || !UUID_RE.test(decoded[1])) return undefined;\n return { createdAt, id: decoded[1] };\n } catch {\n return undefined;\n }\n}\n\nfunction decisionSummary(decision: FactoryDeferredDecisionRecord) {\n const type = typeof decision.decision.type === 'string' ? decision.decision.type.slice(0, 64) : 'unknown';\n return {\n id: decision.id,\n evaluationId: decision.evaluationId,\n workItemId: decision.workItemId,\n type,\n status: decision.status,\n attempts: decision.attempts,\n lastError: decision.lastError?.slice(0, 512) ?? null,\n createdAt: decision.createdAt.toISOString(),\n updatedAt: decision.updatedAt.toISOString(),\n completedAt: decision.completedAt?.toISOString() ?? null,\n };\n}\n\nexport class WorkItemRoutes extends Route<WorkItemRoutesDeps> {\n /** Resolve the `(orgId, userId)` tenant or a ready-to-return error response. */\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.deps.auth.ensureUser(c);\n const tenant = this.deps.auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n { error: 'organization_required', message: 'The Factory board requires an organization.' },\n 403,\n ),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n\n /**\n * Resolve the tenant AND the org-owned project from the `:id` param. Work\n * items hang off a project, so listing/creating requires the project to\n * exist in the caller's org.\n */\n async #resolveProject(\n c: Context,\n ): Promise<{ orgId: string; userId: string; factoryProjectId: string } | { response: Response }> {\n const tenant = await this.#resolveTenant(c);\n if ('response' in tenant) return tenant;\n\n const projectId = c.req.param('id');\n if (!projectId || !UUID_RE.test(projectId)) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n const { projects } = this.deps;\n await projects.ensureReady();\n const project = await projects.get({ orgId: tenant.orgId, id: projectId });\n if (!project) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n return { ...tenant, factoryProjectId: projectId };\n }\n\n /**\n * Emit the audit events a successful work-item PATCH implies: always\n * `updated`, plus `stage_moved` when the stages actually changed and one\n * `run.started` per session role the patch introduced.\n */\n async #auditWorkItemPatch({\n context,\n item,\n previous,\n patch,\n }: {\n context: Context;\n item: WorkItemRow;\n previous: WorkItemPriorState;\n patch: Record<string, unknown>;\n }): Promise<void> {\n const { audit } = this.deps;\n const target = { type: 'work_item', id: item.id, name: item.title };\n await audit.emit({\n context,\n input: {\n action: 'factory.work_item.updated',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: { fields: patchedFields(patch) },\n },\n });\n\n const stagesChanged =\n patch.stages !== undefined &&\n (previous.stages.length !== item.stages.length || previous.stages.some((s, i) => s !== item.stages[i]));\n if (stagesChanged) {\n await audit.emit({\n context,\n input: {\n action: 'factory.work_item.stage_moved',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: { from: previous.stages, to: item.stages },\n },\n });\n }\n\n const newRoles = Object.keys(item.sessions).filter(role => !previous.sessionRoles.includes(role));\n for (const role of newRoles) {\n const session = item.sessions[role];\n await audit.emit({\n context,\n input: {\n action: 'factory.run.started',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: {\n role,\n branch: session?.branch,\n threadId: session?.threadId,\n sessionId: session?.sessionId,\n },\n },\n });\n }\n }\n\n /** Build the Factory work-item routes as Mastra `apiRoutes`. */\n routes(): ApiRoute[] {\n const { audit, workItems, queueHealth, transitionService, startCoordinator } = this.deps;\n return [\n // ── List the org's work items for a project ─────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({ workItems: items });\n },\n }),\n\n // ── Flow metrics aggregated over the project's work items ───────────────\n registerApiRoute('/web/factory/projects/:id/metrics', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const { windowStart, windowEnd } = parseMetricsRange(\n loose(c).req.query('from'),\n loose(c).req.query('to'),\n new Date(),\n );\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({ metrics: computeFactoryMetrics(items, { windowStart, windowEnd }) });\n },\n }),\n\n // ── Per-project queue-health age-threshold config (seconds) ─────────────\n registerApiRoute('/web/factory/projects/:id/health/thresholds', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await queueHealth.ensureReady();\n const stored = await queueHealth.getConfig(resolved.orgId, resolved.factoryProjectId);\n // Validate at the read choke point: `getConfig` round-trips a stored\n // JSONB row, and only `saveConfig` validates on write — a corrupted or\n // hand-edited row (empty / non-ascending) would otherwise flow to the\n // chart and invert bucket colors. Fall back to the default on invalid.\n return c.json({ thresholds: thresholdsOrDefault(stored) });\n },\n }),\n\n // ── Bounded durable rule-decision status ────────────────────────────────\n registerApiRoute('/web/factory/projects/:id/decisions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n\n const cursorRaw = context.req.query('before');\n const before = parseDecisionCursor(cursorRaw);\n if (cursorRaw && !before) return c.json({ error: 'invalid_cursor' }, 400);\n await workItems.ensureReady();\n const page = await workItems.listDeferredDecisionPage({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n statuses: parseDecisionStatuses(context.req.query('statuses')),\n before,\n limit: parseDecisionLimit(context.req.query('limit')),\n });\n const last = page.decisions.at(-1);\n return c.json({\n decisions: page.decisions.map(decisionSummary),\n ...(page.hasMore && last ? { nextCursor: encodeDecisionCursor(last) } : {}),\n });\n },\n }),\n\n registerApiRoute('/web/factory/projects/:id/decisions/:decisionId/retry', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const decisionId = context.req.param('decisionId');\n if (!decisionId || !UUID_RE.test(decisionId)) return c.json({ error: 'invalid_decision_id' }, 422);\n await workItems.ensureReady();\n const decision = await workItems.retryDeferredDecision(\n resolved.orgId,\n resolved.factoryProjectId,\n decisionId,\n new Date(),\n );\n if (!decision) return c.json({ error: 'decision_not_retryable' }, 409);\n return c.json({ decision: decisionSummary(decision) });\n },\n }),\n\n // ── Create (upsert on sourceKey) a work item ─────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const input = parseCreateWorkItem(body);\n if (!input) return c.json({ error: 'invalid_work_item' }, 400);\n if ((input.stages ?? ['intake']).length !== 1 || (input.stages ?? ['intake'])[0] !== 'intake') {\n return c.json(\n { error: 'governed_transition_required', message: 'New work items must enter through Factory intake.' },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const result = await workItems.upsert({\n orgId: resolved.orgId,\n userId: resolved.userId,\n factoryProjectId: resolved.factoryProjectId,\n input,\n reuseMode: 'non-stage',\n });\n let item = result.item;\n if (result.created) {\n if (!transitionService) {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ error: 'factory_transitions_unavailable' }, 503);\n }\n const entered = await transitionService.transition({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId: item.id,\n board: item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: 'intake',\n expectedRevision: item.revision,\n actor: { type: 'human', id: resolved.userId },\n ingress: { type: 'human', identity: `work-item:${item.id}:initial-entry` },\n cause: 'work_item_created',\n initialEntry: true,\n });\n if (entered.status === 'rejected') {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ status: 'rejected', code: entered.code, reason: entered.reason }, 422);\n }\n item = (await workItems.getForProject(resolved.orgId, resolved.factoryProjectId, item.id)) ?? item;\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.created',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: item.id, name: item.title }],\n metadata: { externalSource: item.externalSource, stages: item.stages },\n },\n });\n } else {\n // Source-key reuse: the POST updated an existing card, so audit it\n // as an update (plus stage/run events) instead of a false creation.\n const { stages: _stages, sessions: _sessions, ...boundedPatch } = input;\n await this.#auditWorkItemPatch({\n context: loose(c),\n item,\n previous: result.previous,\n patch: boundedPatch as unknown as Record<string, unknown>,\n });\n }\n return c.json({ workItem: item });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Authoritative stage transition ──────────────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items/:workItemId/transition', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const workItemId = loose(c).req.param('workItemId');\n if (!workItemId || !UUID_RE.test(workItemId)) return c.json({ error: 'Work item not found' }, 404);\n const parsed = parseTransitionBody(await readJson(loose(c)));\n if (!parsed) return c.json({ error: 'invalid_transition_request' }, 400);\n if (!transitionService) {\n return c.json({ error: 'factory_transition_unavailable' }, 503);\n }\n await workItems.ensureReady();\n const result = await transitionService.transition({\n ...parsed,\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId,\n actor: { type: 'human', id: resolved.userId },\n ingress: {\n ...parsed.ingress,\n identity: `human:${resolved.userId}:${parsed.ingress.identity}`,\n },\n });\n await audit.emit({\n context: loose(c),\n input: {\n action:\n result.status === 'accepted'\n ? 'factory.work_item.stage_moved'\n : 'factory.work_item.transition_rejected',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: workItemId }],\n metadata: {\n transitionId: result.transitionId,\n ingressType: parsed.ingress.type,\n ruleSetVersion: transitionService.ruleSetVersion,\n ...(result.status === 'accepted'\n ? { to: result.stage, revision: result.revision }\n : { code: result.code, reason: result.reason }),\n },\n },\n });\n if (result.status === 'accepted') return c.json({ result });\n return c.json({ result }, result.code === 'stale' ? 409 : 422);\n },\n }),\n\n // ── Bind a Factory run before dispatching its kickoff ────────────────────\n registerApiRoute('/web/factory/projects/:id/runs/start', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n if (!startCoordinator) {\n return c.json({ error: 'factory_start_unavailable' }, 503);\n }\n const input = parseStartBody(await readJson(loose(c)), resolved, resolved.factoryProjectId);\n if (!input) return c.json({ error: 'invalid_factory_start' }, 400);\n input.requestContext = loose(c).get('requestContext');\n if (\n !input.workItem.id &&\n ((input.workItem.input.stages ?? ['intake']).length !== 1 ||\n (input.workItem.input.stages ?? ['intake'])[0] !== 'intake')\n ) {\n return c.json(\n { error: 'governed_transition_required', message: 'Create the work item in Intake before starting it.' },\n 409,\n );\n }\n await workItems.ensureReady();\n let prepared: FactoryStartPreparedResult;\n try {\n prepared = await startCoordinator.prepare(input);\n } catch (error) {\n if (error instanceof FactoryStartTransitionError) {\n return c.json({ result: error.result }, error.result.code === 'stale' ? 409 : 422);\n }\n throw error;\n }\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.run.started',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: prepared.workItemId }],\n metadata: {\n role: input.workItem.role,\n branch: prepared.branch,\n threadId: prepared.threadId,\n sessionId: prepared.sessionId,\n bindingId: prepared.bindingId,\n },\n },\n });\n return c.json({ prepared }, 202);\n },\n }),\n\n // ── Patch non-stage metadata / sessions / title ──────────────────────────\n registerApiRoute('/web/factory/work-items/:id', {\n method: 'PATCH',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const id = loose(c).req.param('id');\n if (!id || !UUID_RE.test(id)) return c.json({ error: 'Work item not found' }, 404);\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const patch = parseUpdateWorkItem(body);\n if (!patch) return c.json({ error: 'invalid_work_item_patch' }, 400);\n if (patch.stages !== undefined) {\n return c.json(\n { error: 'governed_transition_required', message: 'Use the Factory transition endpoint to move stages.' },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const updated = await workItems.update({ orgId: tenant.orgId, id, userId: tenant.userId, patch });\n if (!updated) return c.json({ error: 'Work item not found' }, 404);\n await this.#auditWorkItemPatch({\n context: loose(c),\n item: updated.item,\n previous: updated.previous,\n patch: patch as Record<string, unknown>,\n });\n return c.json({ workItem: updated.item });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Remove a work item ───────────────────────────────────────────────────\n registerApiRoute('/web/factory/work-items/:id', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const id = loose(c).req.param('id');\n if (!id || !UUID_RE.test(id)) return c.json({ error: 'Work item not found' }, 404);\n\n await workItems.ensureReady();\n const deleted = await workItems.delete({ orgId: tenant.orgId, id });\n if (!deleted) return c.json({ error: 'Work item not found' }, 404);\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.deleted',\n factoryProjectId: deleted.factoryProjectId,\n targets: [{ type: 'work_item', id: deleted.id, name: deleted.title }],\n },\n });\n return c.json({ ok: true });\n },\n }),\n ];\n }\n}\n","import type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { formatSkillActivation } from '@mastra/core/workspace';\n\nimport type { SourceControlSession, SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\nimport type { CreateWorkItemInput, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { FactoryTransitionService } from './transition-service.js';\nimport type { FactoryRuleStage, FactoryTransitionResult } from './types.js';\n\nexport interface FactoryStartRequest {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n sessionId: string;\n threadTitle: string;\n threadTags?: Record<string, string>;\n kickoffKey: string;\n invocation?: { type: 'prompt'; prompt: string } | { type: 'skill'; skillName: string; arguments: string };\n destinationStage: FactoryRuleStage;\n workItem: {\n id?: string;\n role: string;\n input: CreateWorkItemInput;\n };\n requestContext?: RequestContext;\n}\n\nexport class FactoryStartTransitionError extends Error {\n readonly result: Extract<FactoryTransitionResult, { status: 'rejected' }>;\n\n constructor(result: Extract<FactoryTransitionResult, { status: 'rejected' }>) {\n super(result.reason);\n this.name = 'FactoryStartTransitionError';\n this.result = result;\n }\n}\n\nexport interface FactoryStartPreparedResult {\n workItemId: string;\n bindingId: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n branch: string;\n revision: number;\n kickoffStatus: 'pending' | 'leased' | 'retry' | 'sent' | 'failed';\n replayed: boolean;\n}\n\ntype FactoryController = AgentController<MastraCodeState>;\ntype FactorySession = Awaited<ReturnType<FactoryController['createSession']>>;\n\nfunction escapeSkillBoundary(value: string): string {\n return value.replaceAll('</skill>', '</skill>');\n}\n\nasync function resolveKickoffMessage(\n session: FactorySession,\n invocation: FactoryStartRequest['invocation'],\n): Promise<string | null> {\n if (!invocation) return null;\n if (invocation.type === 'prompt') return invocation.prompt;\n\n const skills = session.getWorkspace().skills;\n await skills?.maybeRefresh();\n const skill = await skills?.get(invocation.skillName);\n if (!skill || skill['user-invocable'] === false) {\n throw new Error(`Skill not found: ${invocation.skillName}.`);\n }\n const args = invocation.arguments.trim();\n const content = `${formatSkillActivation(skill)}${args ? `\\n\\nARGUMENTS: ${args}` : ''}`.trim();\n return `<skill name=\"${skill.name}\">\\n${escapeSkillBoundary(content)}\\n</skill>`;\n}\n\nasync function resolveSourceSession(\n storage: SourceControlStorageHandle,\n request: FactoryStartRequest,\n): Promise<SourceControlSession> {\n const session = await storage.sessions.getBySessionId(request.sessionId);\n if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {\n throw new Error('Factory session not found');\n }\n const projectRepository = await storage.projectRepositories.get({\n orgId: request.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error('Factory session repository not found');\n const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });\n if (!connection || connection.factoryProjectId !== request.factoryProjectId) {\n throw new Error('Factory session does not belong to this project');\n }\n return session;\n}\n\nasync function configureThread(session: FactorySession, request: FactoryStartRequest): Promise<string> {\n const threadId = session.thread.requireId();\n await session.thread.rename({ title: request.threadTitle });\n const settings = { ...(request.threadTags ?? {}), factorySessionId: request.sessionId };\n await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));\n return threadId;\n}\n\nexport class FactoryStartCoordinator {\n readonly #controller: FactoryController;\n readonly #storage: WorkItemsStorage;\n readonly #transitionService?: Pick<FactoryTransitionService, 'transition'>;\n readonly #sourceControl?: SourceControlStorageHandle;\n\n constructor(\n controller: FactoryController,\n storage: WorkItemsStorage,\n transitionService?: Pick<FactoryTransitionService, 'transition'>,\n sourceControl?: SourceControlStorageHandle,\n ) {\n this.#controller = controller;\n this.#storage = storage;\n this.#transitionService = transitionService;\n this.#sourceControl = sourceControl;\n }\n\n async prepare(request: FactoryStartRequest): Promise<FactoryStartPreparedResult> {\n const storage = this.#storage;\n if (!this.#sourceControl) throw new Error('Factory source control storage is unavailable');\n const sourceSession = await resolveSourceSession(this.#sourceControl, request);\n const requestContext = request.requestContext ?? new RequestContext();\n if (!request.requestContext) {\n requestContext.set('user', { workosId: request.userId, organizationId: request.orgId });\n }\n const session = await this.#controller.createSession({\n id: sourceSession.sessionId,\n ownerId: request.userId,\n resourceId: sourceSession.sessionId,\n threadId: sourceSession.sessionId,\n requestContext,\n });\n const threadId = await configureThread(session, request);\n const kickoffMessage = await resolveKickoffMessage(session, request.invocation);\n const prepared = await storage.prepareRunStart({\n orgId: request.orgId,\n userId: request.userId,\n factoryProjectId: request.factoryProjectId,\n workItem: { id: request.workItem.id, input: request.workItem.input },\n role: request.workItem.role,\n session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },\n resourceId: sourceSession.sessionId,\n kickoffKey: request.kickoffKey,\n kickoffMessage,\n });\n await session.thread.setSetting({ key: 'factoryWorkItemId', value: prepared.item.id });\n\n let revision = prepared.item.revision;\n if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {\n if (!this.#transitionService) throw new Error('Factory transition service is unavailable.');\n const transition = await this.#transitionService.transition({\n orgId: request.orgId,\n factoryProjectId: request.factoryProjectId,\n workItemId: prepared.item.id,\n board: prepared.item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: request.destinationStage,\n expectedRevision: prepared.item.revision,\n actor: { type: 'human', id: request.userId },\n ingress: { type: 'human', identity: `start:${request.kickoffKey}:transition` },\n cause: 'run_start',\n });\n if (transition.status === 'rejected') {\n await storage.markPendingStart(prepared.binding.id, 'failed', transition.reason);\n throw new FactoryStartTransitionError(transition);\n }\n revision = transition.revision;\n }\n\n if (kickoffMessage === null) {\n await storage.markPendingStart(prepared.binding.id, 'sent');\n prepared.pendingStart.status = 'sent';\n }\n\n return {\n workItemId: prepared.item.id,\n bindingId: prepared.binding.id,\n threadId,\n resourceId: sourceSession.sessionId,\n sessionId: sourceSession.sessionId,\n branch: sourceSession.branch,\n revision,\n kickoffStatus: prepared.pendingStart.status,\n replayed: prepared.replayed,\n };\n }\n}\n","export type WorkItemSource = 'github-issue' | 'github-pr' | 'linear-issue' | 'manual';\n\nexport const FACTORY_RULE_STAGES = ['intake', 'triage', 'planning', 'execute', 'review', 'done', 'canceled'] as const;\nexport type FactoryRuleStage = (typeof FACTORY_RULE_STAGES)[number];\n\nexport const FACTORY_RULE_BOARDS = ['work', 'review'] as const;\nexport type FactoryRuleBoard = (typeof FACTORY_RULE_BOARDS)[number];\n\nexport const FACTORY_RULE_SOURCES = ['issue', 'pullRequest', 'linearIssue', 'manual'] as const;\nexport type FactoryRuleSource = (typeof FACTORY_RULE_SOURCES)[number];\n\nexport const FACTORY_GITHUB_EVENTS = [\n 'issueOpened',\n 'pullRequestOpened',\n 'pullRequestUpdated',\n 'pullRequestReviewRequested',\n 'pullRequestMerged',\n] as const;\nexport type FactoryGithubEventName = (typeof FACTORY_GITHUB_EVENTS)[number];\n\nexport const FACTORY_LINEAR_EVENTS = ['issueObserved'] as const;\nexport type FactoryLinearEventName = (typeof FACTORY_LINEAR_EVENTS)[number];\n\nexport type FactoryRuleJsonValue =\n null | boolean | number | string | FactoryRuleJsonValue[] | { [key: string]: FactoryRuleJsonValue };\n\nexport interface FactoryRuleItemContext {\n id: string;\n source: WorkItemSource;\n sourceKey: string | null;\n parentWorkItemId: string | null;\n title: string;\n url: string | null;\n stages: readonly string[];\n}\n\nexport type FactoryRuleActor =\n | { type: 'human'; id: string }\n | { type: 'agent'; bindingId: string; role: string }\n | { type: 'github'; login: string; trusted: boolean; factoryAuthored: boolean }\n | { type: 'system'; id: string };\n\nexport interface FactoryRuleIngressIdentity {\n type: 'human' | 'agent' | 'toolResult' | 'github' | 'linear' | 'rule';\n id: string;\n}\n\nexport interface FactoryRuleCausalEntry {\n ingressId: string;\n decisionType: FactoryCommitDecision['type'];\n}\n\nexport interface FactoryRuleContextBase {\n tenant: { orgId: string; projectId: string };\n actor: FactoryRuleActor;\n ingress: FactoryRuleIngressIdentity;\n cause: string;\n causalChain: readonly FactoryRuleCausalEntry[];\n ruleSetVersion: string;\n}\n\nexport interface FactoryBoundRuleContext extends FactoryRuleContextBase {\n item: FactoryRuleItemContext;\n board: FactoryRuleBoard;\n itemRevision: number;\n}\n\nexport interface FactoryStageRuleContext extends FactoryBoundRuleContext {\n source: FactoryRuleSource;\n stage: FactoryRuleStage;\n fromStage: FactoryRuleStage;\n toStage: FactoryRuleStage;\n}\n\nexport interface FactoryToolResultRuleContext extends FactoryBoundRuleContext {\n toolName: string;\n threadId: string;\n assistantMessageId: string;\n toolCallId: string;\n result: {\n status: 'success' | 'error';\n value: FactoryRuleJsonValue;\n };\n}\n\nexport interface FactoryGithubRuleContext extends FactoryRuleContextBase {\n item?: FactoryRuleItemContext;\n board?: FactoryRuleBoard;\n itemRevision?: number;\n event: FactoryGithubEventName;\n deliveryId: string;\n factory: { createdAt: string };\n repository: { id: number; fullName: string };\n issue?: { number: number; title: string; url: string; createdAt?: string };\n pullRequest?: {\n number: number;\n title: string;\n url: string;\n createdAt?: string;\n state: 'open' | 'closed';\n merged: boolean;\n headBranch: string;\n baseBranch: string;\n };\n}\n\nexport interface FactoryLinearRuleContext extends FactoryRuleContextBase {\n item?: FactoryRuleItemContext;\n board?: FactoryRuleBoard;\n itemRevision?: number;\n event: FactoryLinearEventName;\n issue: {\n id: string;\n identifier: string;\n title: string;\n url: string;\n state: string;\n stateType: string;\n priorityLabel: string;\n assignee: string | null;\n team: string | null;\n labels: readonly string[];\n createdAt: string;\n updatedAt: string;\n };\n}\n\nexport type FactoryRuleHandler<TContext> = (\n context: Readonly<TContext>,\n) => FactoryRuleDecision | void | Promise<FactoryRuleDecision | void>;\n\nexport interface FactoryBoardRuleLeaf {\n onEnter?: FactoryRuleHandler<FactoryStageRuleContext>;\n onExit?: FactoryRuleHandler<FactoryStageRuleContext>;\n}\n\nexport interface FactoryToolRuleLeaf {\n onResult?: FactoryRuleHandler<FactoryToolResultRuleContext>;\n}\n\nexport interface FactoryGithubRuleLeaf {\n onEvent?: FactoryRuleHandler<FactoryGithubRuleContext>;\n}\n\nexport interface FactoryLinearRuleLeaf {\n onEvent?: FactoryRuleHandler<FactoryLinearRuleContext>;\n}\n\nexport type FactoryBoardRules = Partial<\n Record<FactoryRuleStage, Partial<Record<FactoryRuleSource, FactoryBoardRuleLeaf>>>\n>;\n\nexport interface FactoryRules {\n version: string;\n work: FactoryBoardRules;\n review: FactoryBoardRules;\n tools: Record<string, FactoryToolRuleLeaf>;\n github: Partial<Record<FactoryGithubEventName, FactoryGithubRuleLeaf>>;\n linear: Partial<Record<FactoryLinearEventName, FactoryLinearRuleLeaf>>;\n}\n\nexport interface FactoryRulesOverrides {\n work?: FactoryBoardRules;\n review?: FactoryBoardRules;\n tools?: Record<string, FactoryToolRuleLeaf>;\n github?: Partial<Record<FactoryGithubEventName, FactoryGithubRuleLeaf>>;\n linear?: Partial<Record<FactoryLinearEventName, FactoryLinearRuleLeaf>>;\n}\n\nexport type FactoryRuleRejectionCode =\n | 'forbidden'\n | 'invalid_transition'\n | 'missing_binding'\n | 'stale'\n | 'timeout'\n | 'rule_error'\n | 'causal_depth_exceeded'\n | 'repeated_transition';\n\nexport interface FactoryRuleRejectDecision {\n type: 'reject';\n code: FactoryRuleRejectionCode;\n reason: string;\n}\n\ninterface FactoryCommitDecisionBase {\n idempotencyKey: string;\n}\n\nexport interface FactoryTransitionDecision extends FactoryCommitDecisionBase {\n type: 'transition';\n board: FactoryRuleBoard;\n stage: FactoryRuleStage;\n}\n\nexport interface FactoryUpsertLinkedWorkItemDecision extends FactoryCommitDecisionBase {\n type: 'upsertLinkedWorkItem';\n board: FactoryRuleBoard;\n source: WorkItemSource;\n sourceKey: string;\n title: string;\n url: string | null;\n stage: FactoryRuleStage;\n metadata?: Record<string, FactoryRuleJsonValue>;\n}\n\nexport interface FactoryInvokeSkillDecision extends FactoryCommitDecisionBase {\n type: 'invokeSkill';\n role: string;\n skillName: string;\n arguments?: string;\n precedingMessage?: string;\n}\n\nexport interface FactorySendMessageDecision extends FactoryCommitDecisionBase {\n type: 'sendMessage';\n role: string;\n message: string;\n priority?: 'medium' | 'high' | 'urgent';\n idleBehavior?: 'persist' | 'wake';\n prepareBinding?: boolean;\n}\n\nexport interface FactoryNotifyDecision extends FactoryCommitDecisionBase {\n type: 'notify';\n title: string;\n body?: string;\n level?: 'info' | 'warning' | 'error';\n}\n\nexport type FactoryCommitDecision =\n | FactoryTransitionDecision\n | FactoryUpsertLinkedWorkItemDecision\n | FactoryInvokeSkillDecision\n | FactorySendMessageDecision\n | FactoryNotifyDecision;\n\nexport type FactoryRuleDecision = FactoryRuleRejectDecision | FactoryCommitDecision;\n\nexport interface FactoryTransitionResultAccepted {\n status: 'accepted';\n transitionId: string;\n itemId: string;\n revision: number;\n stage: FactoryRuleStage;\n decisions: FactoryCommitDecision[];\n}\n\nexport interface FactoryTransitionResultRejected {\n status: 'rejected';\n transitionId: string;\n itemId: string;\n code: FactoryRuleRejectionCode;\n reason: string;\n}\n\nexport type FactoryTransitionResult = FactoryTransitionResultAccepted | FactoryTransitionResultRejected;\n\nexport function factoryRuleSourceForWorkItem(source: WorkItemSource): FactoryRuleSource {\n switch (source) {\n case 'github-issue':\n return 'issue';\n case 'github-pr':\n return 'pullRequest';\n case 'linear-issue':\n return 'linearIssue';\n case 'manual':\n return 'manual';\n }\n}\n","/**\n * Queue-health threshold configuration domain: per-project age buckets for the\n * Factory Overview queue-health chart.\n *\n * Stored per `(org, github_project)` — each connected GitHub project gets its\n * own age thresholds so a fast-moving automated pipeline and a slow human one\n * can bucket \"how old is the work\" differently. `thresholdsSeconds` is an\n * ordered-ascending list of age boundaries in seconds: an item younger than\n * the first boundary is green, younger than the second amber, younger than the\n * third orange, and red otherwise. Seconds (not hours) so sub-minute buckets\n * are representable for fast automated flows.\n */\n\nimport { FactoryStorageDomain, UniqueViolationError } from '@mastra/core/storage';\nimport type { CollectionSchema, FactoryStorageOps } from '@mastra/core/storage';\n\nexport interface QueueHealthConfig {\n /** Ordered-ascending age boundaries in seconds, e.g. `[14400, 86400, 259200]`. */\n thresholdsSeconds: number[];\n}\n\n/** Default: green <4h, amber <24h, orange <72h, red 72h+. */\nexport const DEFAULT_QUEUE_HEALTH_CONFIG: QueueHealthConfig = {\n thresholdsSeconds: [14400, 86400, 259200],\n};\n\n/**\n * Throw unless `thresholdsSeconds` is a non-empty ascending number list. A\n * descending config would silently invert bucket semantics, so validate at the\n * write boundary rather than trusting callers.\n */\nexport function assertValidThresholds(config: QueueHealthConfig): void {\n const t = config.thresholdsSeconds;\n if (!Array.isArray(t) || t.length === 0 || t.some(v => typeof v !== 'number' || !Number.isFinite(v))) {\n throw new Error('[QueueHealthStorage] thresholdsSeconds must be a non-empty array of finite numbers.');\n }\n for (let i = 1; i < t.length; i++) {\n if (t[i]! <= t[i - 1]!) {\n throw new Error('[QueueHealthStorage] thresholdsSeconds must be strictly ascending.');\n }\n }\n}\n\n/** Validate untrusted JSON into a `QueueHealthConfig`, or `null` when invalid. */\nexport function parseQueueHealthConfig(body: unknown): QueueHealthConfig | null {\n if (typeof body !== 'object' || body === null) return null;\n const config = body as { thresholdsSeconds?: unknown };\n if (!Array.isArray(config.thresholdsSeconds)) return null;\n try {\n assertValidThresholds(config as QueueHealthConfig);\n } catch {\n return null;\n }\n return { thresholdsSeconds: [...(config as QueueHealthConfig).thresholdsSeconds] };\n}\n\n/**\n * Return `config.thresholdsSeconds` when valid, else the default. Validation\n * lives at the `saveConfig` write boundary, but `getConfig` round-trips a\n * stored JSON row — a corrupted or hand-edited row (empty / non-ascending)\n * would otherwise reach the chart and invert bucket colors, so the read route\n * re-validates and falls back.\n */\nexport function thresholdsOrDefault(config: QueueHealthConfig): number[] {\n return parseQueueHealthConfig(config)?.thresholdsSeconds ?? DEFAULT_QUEUE_HEALTH_CONFIG.thresholdsSeconds;\n}\n\nexport const QUEUE_HEALTH_SETTINGS_SCHEMA: CollectionSchema = {\n name: 'queue_health_settings',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n config: { type: 'json' },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [{ name: 'queue_health_settings_org_project_unique', columns: ['org_id', 'factory_project_id'] }],\n};\n\n/**\n * Queue-health settings storage, written once against the generic\n * `FactoryStorageOps` surface — works on any `FactoryStorage` backend.\n */\nexport class QueueHealthStorage extends FactoryStorageDomain {\n constructor() {\n super('queue-health');\n }\n\n async init(): Promise<void> {\n await this.ensureCollections([QUEUE_HEALTH_SETTINGS_SCHEMA]);\n }\n\n async dangerouslyClearAll(): Promise<void> {\n await this.ops.deleteMany('queue_health_settings', {});\n }\n\n get #db(): FactoryStorageOps {\n return this.ops;\n }\n\n /** Read the project's queue-health config, falling back to {@link DEFAULT_QUEUE_HEALTH_CONFIG}. */\n async getConfig(orgId: string, factoryProjectId: string): Promise<QueueHealthConfig> {\n const row = await this.#db.findOne<{ config: unknown }>('queue_health_settings', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n });\n return structuredClone(parseQueueHealthConfig(row?.config) ?? DEFAULT_QUEUE_HEALTH_CONFIG);\n }\n\n /** Upsert the project's queue-health config (`created_at` is preserved on update). */\n async saveConfig(orgId: string, factoryProjectId: string, config: QueueHealthConfig): Promise<void> {\n assertValidThresholds(config);\n const where = { org_id: orgId, factory_project_id: factoryProjectId };\n const updateExisting = () =>\n this.#db.updateAtomic('queue_health_settings', where, () => ({ config, updated_at: new Date() }));\n if (await updateExisting()) return;\n\n const now = new Date();\n try {\n await this.#db.insertOne('queue_health_settings', { ...where, config, created_at: now, updated_at: now });\n } catch (error) {\n if (!(error instanceof UniqueViolationError)) throw error;\n // Lost the insert race — update the winning row under the backend's serialized write primitive.\n if (!(await updateExisting())) throw error;\n }\n }\n}\n","/**\n * Factory work-items storage domain.\n *\n * Work items belong to a first-class Factory project. External intake items use\n * a provider-neutral source reference; manual work items have no source.\n * Stage history is server-owned, while session and metadata patches merge\n * atomically so concurrent actors do not overwrite each other. The authoritative\n * Factory transition path keeps one exclusive current stage per item.\n */\n\nimport { createHash } from 'node:crypto';\n\nimport { FactoryStorageDomain, UniqueViolationError } from '@mastra/core/storage';\nimport type { CollectionSchema, FactoryStorageOps } from '@mastra/core/storage';\n\nexport type WorkItemStage = string;\n\nfunction stableJson(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`;\n if (value && typeof value === 'object') {\n return `{${Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)\n .join(',')}}`;\n }\n return JSON.stringify(value) ?? 'null';\n}\n\nexport function factoryDecisionHash(decision: Record<string, unknown>): string {\n return createHash('sha256').update(stableJson(decision)).digest('hex');\n}\n\nexport interface ExternalWorkItemSource {\n integrationId: string;\n type: string;\n externalId: string;\n url?: string;\n}\n\nexport interface WorkItemStageEntry {\n stage: WorkItemStage;\n enteredAt: string;\n exitedAt?: string;\n by: string;\n /**\n * Actor that closed this entry; absent on entries written before exit\n * stamping existed — treat as human.\n */\n exitedBy?: string;\n}\n\n/**\n * Sentinel actor ids that mark a stage transition as automation-driven (vs a\n * human's WorkOS user id): generic sentinels plus the system ids the Factory\n * rules engine stamps (see `actorId` in factory/rules/transition-service.ts).\n * Metrics treat any other actor — including a missing `exitedBy` on\n * pre-existing entries — as human.\n */\nexport const AUTOMATION_ACTORS = new Set([\n 'factory',\n 'system',\n 'automation',\n 'factory-rule-dispatcher',\n 'factory-tool-result-rule',\n]);\n\n/**\n * Whether an actor id marks a transition no human performed on the Factory\n * board: a sentinel automation id, an agent binding (`agent:*`), or an\n * external-webhook actor (`github:*` — a human may have acted on GitHub, but\n * the board move itself was automated).\n */\nexport function isAutomationActor(by: string | undefined): boolean {\n if (by === undefined) return false;\n return AUTOMATION_ACTORS.has(by) || by.startsWith('agent:') || by.startsWith('github:');\n}\n\nexport interface WorkItemSessionRef {\n sessionId: string;\n branch: string;\n threadId: string;\n startedBy: string;\n}\n\nexport interface FactoryRuleIngressRecord {\n id: string;\n orgId: string;\n factoryProjectId: string;\n identity: string;\n triggerType: string;\n transitionId: string;\n result: Record<string, unknown>;\n createdAt: Date;\n}\n\nexport interface CommitFactoryRuleEvaluationInput {\n orgId: string;\n factoryProjectId: string;\n workItemId: string | null;\n ingress: { identity: string; triggerType: string };\n ruleSetVersion: string;\n expectedRevision: number | null;\n actor: Record<string, unknown> | null;\n outcome: { status: 'accepted' | 'rejected'; code?: string; reason?: string };\n decisions: Record<string, unknown>[];\n causalChain: Array<{ ingressId: string; decisionType: string }>;\n now: Date;\n}\n\nexport type CommitFactoryRuleEvaluationResult =\n | { status: 'committed'; result: Record<string, unknown> }\n | { status: 'replayed'; result: Record<string, unknown> }\n | { status: 'missing' };\n\nexport interface FactoryToolResultCursorRecord {\n bindingId: string;\n orgId: string;\n factoryProjectId: string;\n lastMessageId: string;\n lastMessageCreatedAt: Date;\n updatedAt: Date;\n}\n\nexport interface FactoryRuleEvaluationRecord {\n id: string;\n ingressId: string;\n workItemId: string | null;\n ruleSetVersion: string;\n expectedRevision: number | null;\n outcome: 'accepted' | 'rejected';\n code: string | null;\n reason: string | null;\n causalChain: Array<{ ingressId: string; decisionType: string }>;\n createdAt: Date;\n}\n\nexport type FactoryDispatchStatus = 'pending' | 'leased' | 'retry' | 'succeeded' | 'failed';\n\nexport interface FactoryDeferredDecisionPageInput {\n orgId: string;\n factoryProjectId: string;\n statuses?: FactoryDispatchStatus[];\n before?: { createdAt: Date; id: string };\n limit: number;\n}\n\nexport interface FactoryDeferredDecisionPage {\n decisions: FactoryDeferredDecisionRecord[];\n hasMore: boolean;\n}\n\nexport interface FactoryDeferredDecisionRecord {\n id: string;\n orgId: string;\n factoryProjectId: string;\n evaluationId: string;\n workItemId: string | null;\n idempotencyKey: string;\n effectOrdinal: number;\n effectHash: string;\n causalChain: Array<{ ingressId: string; decisionType: string }>;\n actor: Record<string, unknown> | null;\n decision: Record<string, unknown>;\n status: FactoryDispatchStatus;\n attempts: number;\n availableAt: Date;\n leaseOwner: string | null;\n leaseExpiresAt: Date | null;\n lastError: string | null;\n completedAt: Date | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface FactoryRunBindingSessionAddress {\n factoryProjectId: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n}\n\nexport interface FactoryRunBindingAddress extends FactoryRunBindingSessionAddress {\n orgId: string;\n}\n\nexport interface RevokeFactoryRunBindingInput {\n orgId: string;\n factoryProjectId: string;\n bindingId: string;\n revokedAt: Date;\n}\n\nexport interface FactoryRunBindingRecord {\n id: string;\n orgId: string;\n factoryProjectId: string;\n workItemId: string;\n role: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n branch: string;\n status: 'active' | 'revoked';\n createdAt: Date;\n revokedAt: Date | null;\n}\n\nexport interface FactoryPendingStartRecord {\n id: string;\n orgId: string;\n factoryProjectId: string;\n bindingId: string;\n kickoffKey: string;\n message: string | null;\n status: 'pending' | 'leased' | 'retry' | 'sent' | 'failed';\n attempts: number;\n availableAt: Date;\n leaseOwner: string | null;\n leaseExpiresAt: Date | null;\n lastError: string | null;\n completedAt: Date | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface FactoryLeaseClaimInput {\n ownerId: string;\n now: Date;\n leaseExpiresAt: Date;\n limit: number;\n}\n\nexport interface FactoryLeaseIdentity {\n id: string;\n orgId: string;\n factoryProjectId: string;\n ownerId: string;\n}\n\nexport interface FactoryDispatchFailureInput extends FactoryLeaseIdentity {\n now: Date;\n availableAt: Date;\n lastError: string;\n terminal: boolean;\n}\n\nexport interface CommitFactoryTransitionInput {\n orgId: string;\n factoryProjectId: string;\n workItemId: string;\n expectedRevision: number;\n destinationStage: string;\n actorId: string;\n ingress: { identity: string; triggerType: string; transitionId: string };\n ruleSetVersion: string;\n causalChain: Array<{ ingressId: string; decisionType: string }>;\n evaluation:\n | { outcome: 'accepted'; decisions: Record<string, unknown>[] }\n | { outcome: 'rejected'; code: string; reason: string };\n}\n\nexport type CommitFactoryTransitionResult =\n | { status: 'committed'; item: WorkItemRow | null; result: Record<string, unknown> }\n | { status: 'replayed'; item: WorkItemRow | null; result: Record<string, unknown> }\n | { status: 'missing' };\n\nexport interface PrepareFactoryRunStartInput {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n workItem: { id?: string; input: CreateWorkItemInput };\n role: string;\n session: WorkItemSessionInput;\n resourceId: string;\n kickoffKey: string;\n kickoffMessage: string | null;\n}\n\nexport interface PrepareFactoryRunStartResult {\n item: WorkItemRow;\n binding: FactoryRunBindingRecord;\n pendingStart: FactoryPendingStartRecord;\n replayed: boolean;\n}\n\n/** Session ref as accepted from clients — `startedBy` is stamped server-side. */\nexport interface WorkItemSessionInput {\n sessionId: string;\n branch: string;\n threadId: string;\n}\n\nexport type WorkItemSessions = Record<string, WorkItemSessionRef>;\n\nexport interface WorkItemRow {\n id: string;\n orgId: string;\n factoryProjectId: string;\n externalSource: ExternalWorkItemSource | null;\n parentWorkItemId: string | null;\n title: string;\n stages: WorkItemStage[];\n stageHistory: WorkItemStageEntry[];\n sessions: WorkItemSessions;\n metadata: Record<string, unknown> | null;\n revision: number;\n createdBy: string;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateWorkItemInput {\n externalSource?: ExternalWorkItemSource | null;\n parentWorkItemId?: string | null;\n title: string;\n stages?: WorkItemStage[];\n sessions?: Record<string, WorkItemSessionInput>;\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface UpdateWorkItemInput {\n parentWorkItemId?: string | null;\n title?: string;\n stages?: WorkItemStage[];\n sessions?: Record<string, WorkItemSessionInput>;\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface WorkItemPriorState {\n stages: WorkItemStage[];\n sessionRoles: string[];\n}\n\nexport interface UpsertWorkItemResult {\n item: WorkItemRow;\n created: boolean;\n previous: WorkItemPriorState;\n}\n\nexport const WORK_ITEMS_SCHEMA: CollectionSchema = {\n name: 'work_items',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n external_source: { type: 'json', nullable: true },\n source_key: { type: 'text', nullable: true },\n parent_work_item_id: { type: 'text', nullable: true },\n title: { type: 'text' },\n stages: { type: 'json' },\n stage_history: { type: 'json' },\n sessions: { type: 'json' },\n metadata: { type: 'json', nullable: true },\n revision: { type: 'integer', default: 1 },\n created_by: { type: 'text' },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n {\n name: 'work_items_project_source_key_unique',\n columns: ['factory_project_id', 'source_key'],\n },\n ],\n indexes: [\n {\n name: 'work_items_org_project_updated_at_idx',\n columns: ['org_id', 'factory_project_id', 'updated_at'],\n },\n {\n name: 'work_items_project_parent_idx',\n columns: ['org_id', 'factory_project_id', 'parent_work_item_id'],\n },\n ],\n};\n\ninterface WorkItemDbRow extends Record<string, unknown> {\n id: string;\n org_id: string;\n factory_project_id: string;\n external_source: ExternalWorkItemSource | null;\n source_key: string | null;\n parent_work_item_id: string | null;\n title: string;\n stages: WorkItemStage[];\n stage_history: WorkItemStageEntry[];\n sessions: WorkItemSessions;\n metadata: Record<string, unknown> | null;\n revision: number;\n created_by: string;\n created_at: Date;\n updated_at: Date;\n}\n\nfunction sourceKey(source: ExternalWorkItemSource | null | undefined): string | null {\n return source ? `${source.integrationId}:${source.type}:${source.externalId}` : null;\n}\n\nfunction toWorkItem(row: WorkItemDbRow): WorkItemRow {\n return {\n id: row.id,\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n externalSource: row.external_source,\n parentWorkItemId: row.parent_work_item_id,\n title: row.title,\n stages: row.stages,\n stageHistory: row.stage_history,\n sessions: row.sessions,\n metadata: row.metadata,\n revision: row.revision,\n createdBy: row.created_by,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nconst toRow = toWorkItem;\n\nfunction patchColumns(changes: Partial<WorkItemRow>): Partial<WorkItemDbRow> {\n return {\n ...(changes.parentWorkItemId !== undefined ? { parent_work_item_id: changes.parentWorkItemId } : {}),\n ...(changes.title !== undefined ? { title: changes.title } : {}),\n ...(changes.stages !== undefined ? { stages: changes.stages } : {}),\n ...(changes.stageHistory !== undefined ? { stage_history: changes.stageHistory } : {}),\n ...(changes.sessions !== undefined ? { sessions: changes.sessions } : {}),\n ...(changes.metadata !== undefined ? { metadata: changes.metadata } : {}),\n ...(changes.revision !== undefined ? { revision: changes.revision } : {}),\n ...(changes.updatedAt !== undefined ? { updated_at: changes.updatedAt } : {}),\n };\n}\n\nfunction emptyPrior(): WorkItemPriorState {\n return { stages: [], sessionRoles: [] };\n}\n\nfunction priorState(row: WorkItemDbRow): WorkItemPriorState {\n return { stages: row.stages, sessionRoles: Object.keys(row.sessions) };\n}\n\nexport class WorkItemRelationError extends Error {\n readonly code = 'invalid_work_item_relation';\n}\n\nexport function validateParentRelation(\n projectItems: WorkItemRow[],\n itemId: string | undefined,\n parentWorkItemId: string | null,\n): void {\n if (parentWorkItemId === null) return;\n const byId = new Map(projectItems.map(item => [item.id, item]));\n const parent = byId.get(parentWorkItemId);\n if (!parent) throw new WorkItemRelationError('Related work item not found in this project.');\n if (itemId === parentWorkItemId) throw new WorkItemRelationError('A work item cannot relate to itself.');\n\n const visited = new Set<string>();\n let cursor: WorkItemRow | undefined = parent;\n while (cursor?.parentWorkItemId) {\n if (cursor.parentWorkItemId === itemId) {\n throw new WorkItemRelationError('This relationship would create a cycle.');\n }\n if (visited.has(cursor.id)) throw new WorkItemRelationError('The related work item chain contains a cycle.');\n visited.add(cursor.id);\n cursor = byId.get(cursor.parentWorkItemId);\n }\n}\n\n/**\n * Diff `oldStages` → `newStages` and return the updated history: exited stages\n * get `exitedAt` + `exitedBy` stamped on their open entry, entered stages get\n * a new entry.\n */\nexport function applyStageTransition(\n history: WorkItemStageEntry[],\n oldStages: WorkItemStage[],\n newStages: WorkItemStage[],\n by: string,\n now: Date,\n): WorkItemStageEntry[] {\n const timestamp = now.toISOString();\n const next = history.map(entry => ({ ...entry }));\n for (const stage of oldStages) {\n if (newStages.includes(stage)) continue;\n for (let i = next.length - 1; i >= 0; i--) {\n const entry = next[i]!;\n if (entry.stage === stage && entry.exitedAt === undefined) {\n entry.exitedAt = timestamp;\n entry.exitedBy = by;\n break;\n }\n }\n }\n for (const stage of newStages) {\n if (!oldStages.includes(stage)) next.push({ stage, enteredAt: timestamp, by });\n }\n return next;\n}\n\nexport function stampSessions(sessions: Record<string, WorkItemSessionInput>, by: string): WorkItemSessions {\n return Object.fromEntries(Object.entries(sessions).map(([role, session]) => [role, { ...session, startedBy: by }]));\n}\n\nfunction applyUpdate({\n current,\n userId,\n input,\n}: {\n current: WorkItemDbRow;\n userId: string;\n input: UpdateWorkItemInput;\n}): Partial<WorkItemDbRow> {\n const now = new Date();\n return {\n ...(input.parentWorkItemId !== undefined ? { parent_work_item_id: input.parentWorkItemId } : {}),\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.stages !== undefined\n ? {\n stages: input.stages,\n stage_history: applyStageTransition(current.stage_history, current.stages, input.stages, userId, now),\n }\n : {}),\n ...(input.sessions !== undefined\n ? { sessions: { ...current.sessions, ...stampSessions(input.sessions, userId) } }\n : {}),\n ...(input.metadata !== undefined\n ? { metadata: input.metadata === null ? null : { ...(current.metadata ?? {}), ...input.metadata } }\n : {}),\n revision: current.revision + 1,\n updated_at: now,\n };\n}\n\nconst projectRelationLocks = new Map<string, Promise<unknown>>();\n\nfunction withInProcessProjectLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const previous = projectRelationLocks.get(key) ?? Promise.resolve();\n const result = previous.then(fn, fn);\n const tail = result.then(\n () => undefined,\n () => undefined,\n );\n projectRelationLocks.set(key, tail);\n void tail.then(() => {\n if (projectRelationLocks.get(key) === tail) projectRelationLocks.delete(key);\n });\n return result;\n}\n\nconst FACTORY_GOVERNANCE_SCHEMAS: CollectionSchema[] = [\n {\n name: 'factory_rule_ingress',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n identity: { type: 'text' },\n trigger_type: { type: 'text' },\n transition_id: { type: 'text' },\n result: { type: 'json' },\n created_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n { name: 'factory_rule_ingress_tenant_identity_unique', columns: ['org_id', 'factory_project_id', 'identity'] },\n ],\n },\n {\n name: 'factory_rule_evaluations',\n columns: {\n id: { type: 'uuid-pk' },\n ingress_id: { type: 'text' },\n work_item_id: { type: 'text', nullable: true },\n rule_set_version: { type: 'text' },\n expected_revision: { type: 'integer', nullable: true },\n outcome: { type: 'text' },\n code: { type: 'text', nullable: true },\n reason: { type: 'text', nullable: true },\n causal_chain: { type: 'json' },\n created_at: { type: 'timestamp' },\n },\n },\n {\n name: 'factory_deferred_decisions',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n evaluation_id: { type: 'text' },\n work_item_id: { type: 'text', nullable: true },\n idempotency_key: { type: 'text' },\n effect_ordinal: { type: 'integer' },\n effect_hash: { type: 'text' },\n causal_chain: { type: 'json' },\n actor: { type: 'json', nullable: true },\n decision: { type: 'json' },\n status: { type: 'text' },\n attempts: { type: 'integer' },\n available_at: { type: 'timestamp' },\n lease_owner: { type: 'text', nullable: true },\n lease_expires_at: { type: 'timestamp', nullable: true },\n last_error: { type: 'text', nullable: true },\n completed_at: { type: 'timestamp', nullable: true },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n {\n name: 'factory_deferred_decisions_tenant_key_unique',\n columns: ['org_id', 'factory_project_id', 'idempotency_key'],\n },\n ],\n },\n {\n name: 'factory_run_bindings',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n work_item_id: { type: 'text' },\n role: { type: 'text' },\n thread_id: { type: 'text' },\n resource_id: { type: 'text' },\n session_id: { type: 'text' },\n branch: { type: 'text' },\n status: { type: 'text' },\n created_at: { type: 'timestamp' },\n revoked_at: { type: 'timestamp', nullable: true },\n },\n },\n {\n name: 'factory_tool_result_cursors',\n columns: {\n binding_id: { type: 'text', primaryKey: true },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n last_message_id: { type: 'text' },\n last_message_created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n },\n {\n name: 'factory_pending_starts',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n binding_id: { type: 'text' },\n kickoff_key: { type: 'text' },\n message: { type: 'text', nullable: true },\n status: { type: 'text' },\n attempts: { type: 'integer' },\n available_at: { type: 'timestamp' },\n lease_owner: { type: 'text', nullable: true },\n lease_expires_at: { type: 'timestamp', nullable: true },\n last_error: { type: 'text', nullable: true },\n completed_at: { type: 'timestamp', nullable: true },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n {\n name: 'factory_pending_starts_tenant_kickoff_unique',\n columns: ['org_id', 'factory_project_id', 'kickoff_key'],\n },\n ],\n },\n];\n\ninterface GovernanceDbRow extends Record<string, unknown> {\n id: string;\n org_id: string;\n factory_project_id: string;\n created_at: Date;\n [key: string]: unknown;\n}\n\nfunction toBinding(row: GovernanceDbRow): FactoryRunBindingRecord {\n return {\n id: row.id,\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n workItemId: String(row.work_item_id),\n role: String(row.role),\n threadId: String(row.thread_id),\n resourceId: String(row.resource_id),\n sessionId: String(row.session_id),\n branch: String(row.branch),\n status: row.status as FactoryRunBindingRecord['status'],\n createdAt: row.created_at,\n revokedAt: (row.revoked_at as Date | null) ?? null,\n };\n}\nfunction toDeferredDecision(row: GovernanceDbRow): FactoryDeferredDecisionRecord {\n return {\n id: row.id,\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n evaluationId: String(row.evaluation_id),\n workItemId: row.work_item_id === null || row.work_item_id === undefined ? null : String(row.work_item_id),\n idempotencyKey: String(row.idempotency_key),\n effectOrdinal: Number(row.effect_ordinal),\n effectHash: String(row.effect_hash),\n causalChain: (row.causal_chain as FactoryDeferredDecisionRecord['causalChain']) ?? [],\n actor: (row.actor as Record<string, unknown> | null) ?? null,\n decision: row.decision as Record<string, unknown>,\n status: row.status as FactoryDispatchStatus,\n attempts: Number(row.attempts),\n availableAt: row.available_at as Date,\n leaseOwner: (row.lease_owner as string | null) ?? null,\n leaseExpiresAt: (row.lease_expires_at as Date | null) ?? null,\n lastError: (row.last_error as string | null) ?? null,\n completedAt: (row.completed_at as Date | null) ?? null,\n createdAt: row.created_at,\n updatedAt: row.updated_at as Date,\n };\n}\nfunction toPendingStart(row: GovernanceDbRow): FactoryPendingStartRecord {\n return {\n id: row.id,\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n bindingId: String(row.binding_id),\n kickoffKey: String(row.kickoff_key),\n message: (row.message as string | null) ?? null,\n status: row.status as FactoryPendingStartRecord['status'],\n attempts: Number(row.attempts),\n availableAt: row.available_at as Date,\n leaseOwner: (row.lease_owner as string | null) ?? null,\n leaseExpiresAt: (row.lease_expires_at as Date | null) ?? null,\n lastError: (row.last_error as string | null) ?? null,\n completedAt: (row.completed_at as Date | null) ?? null,\n createdAt: row.created_at,\n updatedAt: row.updated_at as Date,\n };\n}\n\nexport class WorkItemsStorage extends FactoryStorageDomain {\n constructor() {\n super('work-items');\n }\n\n async init(): Promise<void> {\n await this.ensureCollections([WORK_ITEMS_SCHEMA, ...FACTORY_GOVERNANCE_SCHEMAS]);\n }\n\n async dangerouslyClearAll(): Promise<void> {\n await this.ops.deleteMany('work_items', {});\n }\n\n #leaseQueue: Promise<void> = Promise.resolve();\n\n get #db(): FactoryStorageOps {\n return this.ops;\n }\n\n async #withLocalLeaseLock<T>(fn: () => Promise<T>): Promise<T> {\n const prior = this.#leaseQueue;\n let release!: () => void;\n this.#leaseQueue = new Promise<void>(resolve => {\n release = resolve;\n });\n await prior;\n try {\n return await fn();\n } finally {\n release();\n }\n }\n\n async #withProjectRelationLock<T>(orgId: string, factoryProjectId: string, fn: () => Promise<T>): Promise<T> {\n const key = `work-items:${orgId}:${factoryProjectId}`;\n return withInProcessProjectLock(key, () =>\n this.storage.withDistributedLock ? this.storage.withDistributedLock(key, fn) : fn(),\n );\n }\n\n async #claimLeases<T>(\n table: 'factory_deferred_decisions' | 'factory_pending_starts',\n input: FactoryLeaseClaimInput,\n map: (row: GovernanceDbRow) => T,\n ): Promise<T[]> {\n const claim = () =>\n this.storage.withTransaction(async ops => {\n const candidates = await ops.findMany<GovernanceDbRow>(table, {}, { orderBy: [['created_at', 'asc']] });\n const claimed: T[] = [];\n for (const candidate of candidates) {\n if (claimed.length >= input.limit) break;\n const availableAt = new Date(candidate.available_at as Date | string).getTime();\n const leaseExpiresAt = candidate.lease_expires_at\n ? new Date(candidate.lease_expires_at as Date | string).getTime()\n : 0;\n const claimable =\n (candidate.status === 'pending' || candidate.status === 'retry') && availableAt <= input.now.getTime();\n const expired = candidate.status === 'leased' && leaseExpiresAt <= input.now.getTime();\n if (!claimable && !expired) continue;\n let didClaim = false;\n const row = await ops.updateAtomic<GovernanceDbRow>(table, { id: candidate.id }, current => {\n const currentAvailable = new Date(current.available_at as Date | string).getTime();\n const currentExpiry = current.lease_expires_at\n ? new Date(current.lease_expires_at as Date | string).getTime()\n : 0;\n const currentClaimable =\n (current.status === 'pending' || current.status === 'retry') && currentAvailable <= input.now.getTime();\n const currentExpired = current.status === 'leased' && currentExpiry <= input.now.getTime();\n if (!currentClaimable && !currentExpired) return null;\n didClaim = true;\n return {\n status: 'leased',\n attempts: Number(current.attempts) + 1,\n lease_owner: input.ownerId,\n lease_expires_at: input.leaseExpiresAt,\n updated_at: input.now,\n };\n });\n if (didClaim && row) claimed.push(map(row));\n }\n return claimed;\n });\n return this.storage.withDistributedLock\n ? this.storage.withDistributedLock(`factory-lease:${table}`, claim)\n : this.#withLocalLeaseLock(claim);\n }\n\n async #renewLease(\n table: 'factory_deferred_decisions' | 'factory_pending_starts',\n identity: FactoryLeaseIdentity,\n leaseExpiresAt: Date,\n ): Promise<boolean> {\n let renewed = false;\n await this.#db.updateAtomic<GovernanceDbRow>(\n table,\n { id: identity.id, org_id: identity.orgId, factory_project_id: identity.factoryProjectId },\n current => {\n if (current.status !== 'leased' || current.lease_owner !== identity.ownerId) return null;\n renewed = true;\n return { lease_expires_at: leaseExpiresAt, updated_at: new Date() };\n },\n );\n return renewed;\n }\n\n async #completeLease(\n table: 'factory_deferred_decisions' | 'factory_pending_starts',\n identity: FactoryLeaseIdentity,\n now: Date,\n ): Promise<GovernanceDbRow | null> {\n let completed = false;\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n table,\n { id: identity.id, org_id: identity.orgId, factory_project_id: identity.factoryProjectId },\n current => {\n if (current.status !== 'leased' || current.lease_owner !== identity.ownerId) return null;\n completed = true;\n return {\n status: table === 'factory_pending_starts' ? 'sent' : 'succeeded',\n lease_owner: null,\n lease_expires_at: null,\n completed_at: now,\n updated_at: now,\n };\n },\n );\n return completed ? row : null;\n }\n\n async #failLease(\n table: 'factory_deferred_decisions' | 'factory_pending_starts',\n input: FactoryDispatchFailureInput,\n ): Promise<GovernanceDbRow | null> {\n let failed = false;\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n table,\n { id: input.id, org_id: input.orgId, factory_project_id: input.factoryProjectId },\n current => {\n if (current.status !== 'leased' || current.lease_owner !== input.ownerId) return null;\n failed = true;\n return {\n status: input.terminal ? 'failed' : 'retry',\n available_at: input.availableAt,\n lease_owner: null,\n lease_expires_at: null,\n last_error: input.lastError,\n completed_at: input.terminal ? input.now : null,\n updated_at: input.now,\n };\n },\n );\n return failed ? row : null;\n }\n\n /** List the org's work items for a project, newest first. */\n async list({ orgId, factoryProjectId }: { orgId: string; factoryProjectId: string }): Promise<WorkItemRow[]> {\n const rows = await this.#db.findMany<WorkItemDbRow>(\n 'work_items',\n { org_id: orgId, factory_project_id: factoryProjectId },\n { orderBy: [['updated_at', 'desc']] },\n );\n return rows.map(toWorkItem);\n }\n\n async get({ orgId, id }: { orgId: string; id: string }): Promise<WorkItemRow | null> {\n const row = await this.#db.findOne<WorkItemDbRow>('work_items', { org_id: orgId, id });\n return row ? toWorkItem(row) : null;\n }\n\n async getForProject(orgId: string, factoryProjectId: string, id: string): Promise<WorkItemRow | null> {\n const row = await this.#db.findOne<WorkItemDbRow>('work_items', {\n id,\n org_id: orgId,\n factory_project_id: factoryProjectId,\n });\n return row ? toRow(row) : null;\n }\n\n async getTransitionResultByIngress(\n orgId: string,\n factoryProjectId: string,\n identity: string,\n ): Promise<Record<string, unknown> | null> {\n const row = await this.#db.findOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n identity,\n });\n return (row?.result as Record<string, unknown> | undefined) ?? null;\n }\n\n async commitTransition(input: CommitFactoryTransitionInput): Promise<CommitFactoryTransitionResult> {\n const commit = (): Promise<CommitFactoryTransitionResult> =>\n this.storage.withTransaction<CommitFactoryTransitionResult>(async ops => {\n const prior = await ops.findOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n identity: input.ingress.identity,\n });\n if (prior)\n return {\n status: 'replayed',\n item: await this.getForProject(input.orgId, input.factoryProjectId, input.workItemId),\n result: prior.result as Record<string, unknown>,\n };\n\n const now = new Date();\n let item: WorkItemRow | null = null;\n let code: string | null = null;\n let reason: string | null = null;\n let result: Record<string, unknown>;\n const updated = await ops.updateAtomic<WorkItemDbRow>(\n 'work_items',\n {\n id: input.workItemId,\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n },\n row => {\n const existing = toRow(row);\n item = existing;\n if (existing.revision !== input.expectedRevision) {\n code = 'stale';\n reason = 'The work item changed before this transition committed.';\n return null;\n }\n if (input.evaluation.outcome === 'rejected') {\n code = input.evaluation.code;\n reason = input.evaluation.reason;\n return null;\n }\n if (existing.stages.length === 1 && existing.stages[0] === input.destinationStage) return null;\n return patchColumns({\n stages: [input.destinationStage],\n stageHistory: applyStageTransition(\n existing.stageHistory,\n existing.stages,\n [input.destinationStage],\n input.actorId,\n now,\n ),\n revision: existing.revision + 1,\n updatedAt: now,\n });\n },\n );\n if (updated) item = toRow(updated);\n if (!item) {\n code = input.evaluation.outcome === 'rejected' ? input.evaluation.code : 'invalid_transition';\n reason = input.evaluation.outcome === 'rejected' ? input.evaluation.reason : 'Work item not found.';\n }\n const outcome: 'accepted' | 'rejected' =\n item && code === null && input.evaluation.outcome === 'accepted' ? 'accepted' : 'rejected';\n result =\n outcome === 'accepted'\n ? {\n status: 'accepted',\n transitionId: input.ingress.transitionId,\n itemId: item!.id,\n revision: item!.revision,\n stage: input.destinationStage,\n decisions: input.evaluation.outcome === 'accepted' ? input.evaluation.decisions : [],\n }\n : { status: 'rejected', transitionId: input.ingress.transitionId, itemId: input.workItemId, code, reason };\n const ingress = await ops.insertOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n identity: input.ingress.identity,\n trigger_type: input.ingress.triggerType,\n transition_id: input.ingress.transitionId,\n result,\n created_at: now,\n });\n if (item) {\n const evaluation = await ops.insertOne<GovernanceDbRow>('factory_rule_evaluations', {\n ingress_id: ingress.id,\n work_item_id: item.id,\n rule_set_version: input.ruleSetVersion,\n expected_revision: input.expectedRevision,\n outcome,\n code,\n reason,\n causal_chain: input.causalChain,\n created_at: now,\n });\n if (outcome === 'accepted' && input.evaluation.outcome === 'accepted') {\n for (const [index, decision] of input.evaluation.decisions.entries()) {\n await ops.insertOne<GovernanceDbRow>('factory_deferred_decisions', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n evaluation_id: evaluation.id,\n work_item_id: item.id,\n idempotency_key: String(decision.idempotencyKey),\n effect_ordinal: index,\n effect_hash: factoryDecisionHash(decision),\n causal_chain: input.causalChain,\n actor: null,\n decision,\n status: 'pending',\n attempts: 0,\n available_at: now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n created_at: new Date(now.getTime() + index),\n updated_at: now,\n });\n }\n }\n }\n return { status: 'committed', item, result };\n });\n return this.storage.withDistributedLock\n ? this.storage.withDistributedLock(\n `factory-ingress:${input.orgId}:${input.factoryProjectId}:${input.ingress.identity}`,\n commit,\n )\n : commit();\n }\n\n async commitRuleEvaluation(input: CommitFactoryRuleEvaluationInput): Promise<CommitFactoryRuleEvaluationResult> {\n const commit = () =>\n this.storage.withTransaction<CommitFactoryRuleEvaluationResult>(async ops => {\n const prior = await ops.findOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n identity: input.ingress.identity,\n });\n if (prior) {\n const result = prior.result as Record<string, unknown>;\n const decisions = Array.isArray(result.decisions) ? result.decisions : [];\n const evaluation = await ops.findOne<GovernanceDbRow>('factory_rule_evaluations', { ingress_id: prior.id });\n for (const decision of decisions) {\n if (\n !evaluation ||\n !decision ||\n typeof decision !== 'object' ||\n (decision as Record<string, unknown>).type !== 'upsertLinkedWorkItem' ||\n typeof (decision as Record<string, unknown>).sourceKey !== 'string' ||\n typeof (decision as Record<string, unknown>).idempotencyKey !== 'string'\n ) {\n continue;\n }\n const materialization = decision as Record<string, unknown> & { sourceKey: string; idempotencyKey: string };\n const item = await ops.findOne<WorkItemDbRow>('work_items', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n source_key: materialization.sourceKey,\n });\n if (item) continue;\n await ops.updateAtomic<GovernanceDbRow>(\n 'factory_deferred_decisions',\n {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n evaluation_id: evaluation.id,\n idempotency_key: materialization.idempotencyKey,\n },\n current =>\n current.status === 'succeeded'\n ? {\n status: 'retry',\n attempts: 0,\n available_at: input.now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n updated_at: input.now,\n }\n : null,\n );\n }\n return { status: 'replayed' as const, result };\n }\n const itemRow = input.workItemId\n ? await ops.findOne<WorkItemDbRow>('work_items', {\n id: input.workItemId,\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n })\n : null;\n if (input.workItemId !== null && !itemRow) return { status: 'missing' as const };\n const item = itemRow ? toRow(itemRow) : null;\n const stale = item !== null && item.revision !== input.expectedRevision;\n const outcome = stale ? 'rejected' : input.outcome.status;\n const code = stale ? 'stale' : (input.outcome.code ?? null);\n const reason = stale\n ? 'The work item changed before this rule evaluation committed.'\n : (input.outcome.reason ?? null);\n const decisions = outcome === 'accepted' ? input.decisions : [];\n const result = {\n status: outcome,\n itemId: item?.id ?? null,\n revision: item?.revision ?? null,\n code,\n reason,\n decisions,\n };\n const ingress = await ops.insertOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n identity: input.ingress.identity,\n trigger_type: input.ingress.triggerType,\n transition_id: input.ingress.identity,\n result,\n created_at: input.now,\n });\n const evaluation = await ops.insertOne<GovernanceDbRow>('factory_rule_evaluations', {\n ingress_id: ingress.id,\n work_item_id: item?.id ?? null,\n rule_set_version: input.ruleSetVersion,\n expected_revision: input.expectedRevision,\n outcome,\n code,\n reason,\n causal_chain: input.causalChain,\n created_at: input.now,\n });\n for (const [effectOrdinal, decision] of decisions.entries()) {\n await ops.insertOne<GovernanceDbRow>('factory_deferred_decisions', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n evaluation_id: evaluation.id,\n work_item_id: item?.id ?? null,\n idempotency_key: String(decision.idempotencyKey),\n effect_ordinal: effectOrdinal,\n effect_hash: factoryDecisionHash(decision),\n causal_chain: input.causalChain,\n actor: input.actor,\n decision,\n status: 'pending',\n attempts: 0,\n available_at: input.now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n created_at: new Date(input.now.getTime() + effectOrdinal),\n updated_at: input.now,\n });\n }\n return { status: 'committed' as const, result };\n });\n return this.storage.withDistributedLock\n ? this.storage.withDistributedLock(\n `factory-ingress:${input.orgId}:${input.factoryProjectId}:${input.ingress.identity}`,\n commit,\n )\n : commit();\n }\n\n async getToolResultCursor(\n orgId: string,\n factoryProjectId: string,\n bindingId: string,\n ): Promise<FactoryToolResultCursorRecord | null> {\n const row = await this.#db.findOne<GovernanceDbRow>('factory_tool_result_cursors', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n binding_id: bindingId,\n });\n return row\n ? {\n bindingId: String(row.binding_id),\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n lastMessageId: String(row.last_message_id),\n lastMessageCreatedAt: row.last_message_created_at as Date,\n updatedAt: row.updated_at as Date,\n }\n : null;\n }\n\n async advanceToolResultCursor(cursor: FactoryToolResultCursorRecord): Promise<void> {\n const current = await this.getToolResultCursor(cursor.orgId, cursor.factoryProjectId, cursor.bindingId);\n if (current && current.lastMessageCreatedAt > cursor.lastMessageCreatedAt) return;\n await this.#db.upsertOne<GovernanceDbRow>('factory_tool_result_cursors', ['binding_id'], {\n binding_id: cursor.bindingId,\n org_id: cursor.orgId,\n factory_project_id: cursor.factoryProjectId,\n last_message_id: cursor.lastMessageId,\n last_message_created_at: cursor.lastMessageCreatedAt,\n updated_at: cursor.updatedAt,\n });\n }\n\n async listDeferredDecisions(orgId: string, factoryProjectId: string): Promise<FactoryDeferredDecisionRecord[]> {\n return (\n await this.#db.findMany<GovernanceDbRow>(\n 'factory_deferred_decisions',\n { org_id: orgId, factory_project_id: factoryProjectId },\n { orderBy: [['created_at', 'asc']] },\n )\n ).map(toDeferredDecision);\n }\n\n /** Read a bounded newest-first status page without exposing another tenant. */\n async listDeferredDecisionPage(input: FactoryDeferredDecisionPageInput): Promise<FactoryDeferredDecisionPage> {\n const rows = await this.#db.findMany<GovernanceDbRow>(\n 'factory_deferred_decisions',\n {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n ...(input.statuses ? { status: { in: input.statuses } } : {}),\n },\n {\n orderBy: [\n ['created_at', 'desc'],\n ['id', 'desc'],\n ],\n limit: input.limit + 1,\n ...(input.before ? { cursor: { values: [input.before.createdAt, input.before.id] } } : {}),\n },\n );\n return { decisions: rows.slice(0, input.limit).map(toDeferredDecision), hasMore: rows.length > input.limit };\n }\n\n async claimDeferredDecisions(input: FactoryLeaseClaimInput): Promise<FactoryDeferredDecisionRecord[]> {\n return this.#claimLeases('factory_deferred_decisions', input, toDeferredDecision);\n }\n\n async renewDeferredDecisionLease(identity: FactoryLeaseIdentity, leaseExpiresAt: Date): Promise<boolean> {\n return this.#renewLease('factory_deferred_decisions', identity, leaseExpiresAt);\n }\n\n async completeDeferredDecision(\n identity: FactoryLeaseIdentity,\n now: Date,\n ): Promise<FactoryDeferredDecisionRecord | null> {\n const row = await this.#completeLease('factory_deferred_decisions', identity, now);\n return row ? toDeferredDecision(row) : null;\n }\n\n async failDeferredDecision(input: FactoryDispatchFailureInput): Promise<FactoryDeferredDecisionRecord | null> {\n const row = await this.#failLease('factory_deferred_decisions', input);\n return row ? toDeferredDecision(row) : null;\n }\n\n /** Requeue the same idempotent terminal effect; non-failed decisions are never rerun. */\n async retryDeferredDecision(\n orgId: string,\n factoryProjectId: string,\n decisionId: string,\n now: Date,\n ): Promise<FactoryDeferredDecisionRecord | null> {\n let retried = false;\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n 'factory_deferred_decisions',\n { id: decisionId, org_id: orgId, factory_project_id: factoryProjectId },\n current => {\n if (current.status !== 'failed') return null;\n retried = true;\n return {\n status: 'retry',\n attempts: 0,\n available_at: now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n updated_at: now,\n };\n },\n );\n return retried && row ? toDeferredDecision(row) : null;\n }\n\n /** Resolve exact active agent authority; partial session matches never authorize. */\n async findActiveRunBinding(address: FactoryRunBindingAddress): Promise<FactoryRunBindingRecord | null> {\n const row = await this.#db.findOne<GovernanceDbRow>('factory_run_bindings', {\n org_id: address.orgId,\n factory_project_id: address.factoryProjectId,\n thread_id: address.threadId,\n resource_id: address.resourceId,\n session_id: address.sessionId,\n status: 'active',\n });\n return row ? toBinding(row) : null;\n }\n\n /** Resolve exact bound-session state for processor awareness; ambiguous cross-tenant matches return null. */\n async findRunBindingBySession(address: FactoryRunBindingSessionAddress): Promise<FactoryRunBindingRecord | null> {\n const rows = await this.#db.findMany<GovernanceDbRow>('factory_run_bindings', {\n factory_project_id: address.factoryProjectId,\n thread_id: address.threadId,\n resource_id: address.resourceId,\n session_id: address.sessionId,\n });\n if (new Set(rows.map(row => row.org_id)).size !== 1) return null;\n const row = rows.sort((left, right) => {\n if (left.status === 'active' && right.status !== 'active') return -1;\n if (right.status === 'active' && left.status !== 'active') return 1;\n return right.created_at.getTime() - left.created_at.getTime();\n })[0];\n return row ? toBinding(row) : null;\n }\n\n /** Revoke one exact tenant-scoped binding. */\n async revokeRunBinding(input: RevokeFactoryRunBindingInput): Promise<FactoryRunBindingRecord | null> {\n let revoked = false;\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n 'factory_run_bindings',\n { id: input.bindingId, org_id: input.orgId, factory_project_id: input.factoryProjectId },\n current => {\n if (current.status !== 'active') return null;\n revoked = true;\n return { status: 'revoked', revoked_at: input.revokedAt };\n },\n );\n return revoked && row ? toBinding(row) : null;\n }\n\n /** Enumerate active bindings for the server-owned restart reconciler. */\n async listActiveRunBindings(): Promise<FactoryRunBindingRecord[]> {\n return (await this.#db.findMany<GovernanceDbRow>('factory_run_bindings', { status: 'active' })).map(toBinding);\n }\n\n /** List binding history, optionally narrowed to one work item. */\n async listRunBindings(\n orgId: string,\n factoryProjectId: string,\n workItemId?: string,\n ): Promise<FactoryRunBindingRecord[]> {\n return (\n await this.#db.findMany<GovernanceDbRow>(\n 'factory_run_bindings',\n {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n ...(workItemId ? { work_item_id: workItemId } : {}),\n },\n { orderBy: [['created_at', 'asc']] },\n )\n ).map(toBinding);\n }\n\n async listPendingStarts(orgId: string, factoryProjectId: string): Promise<FactoryPendingStartRecord[]> {\n return (\n await this.#db.findMany<GovernanceDbRow>(\n 'factory_pending_starts',\n { org_id: orgId, factory_project_id: factoryProjectId },\n { orderBy: [['created_at', 'asc']] },\n )\n ).map(toPendingStart);\n }\n\n async claimPendingStarts(input: FactoryLeaseClaimInput): Promise<FactoryPendingStartRecord[]> {\n return this.#claimLeases('factory_pending_starts', input, toPendingStart);\n }\n\n async renewPendingStartLease(identity: FactoryLeaseIdentity, leaseExpiresAt: Date): Promise<boolean> {\n return this.#renewLease('factory_pending_starts', identity, leaseExpiresAt);\n }\n\n async completePendingStart(identity: FactoryLeaseIdentity, now: Date): Promise<FactoryPendingStartRecord | null> {\n const row = await this.#completeLease('factory_pending_starts', identity, now);\n return row ? toPendingStart(row) : null;\n }\n\n async failPendingStart(input: FactoryDispatchFailureInput): Promise<FactoryPendingStartRecord | null> {\n const row = await this.#failLease('factory_pending_starts', input);\n return row ? toPendingStart(row) : null;\n }\n\n async prepareRunStart(input: PrepareFactoryRunStartInput): Promise<PrepareFactoryRunStartResult> {\n const prepare = () =>\n this.storage.withTransaction(async ops => {\n const prior = await ops.findOne<GovernanceDbRow>('factory_pending_starts', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n kickoff_key: input.kickoffKey,\n });\n if (prior) {\n const bindingRow = await ops.findOne<GovernanceDbRow>('factory_run_bindings', {\n id: String(prior.binding_id),\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n });\n const itemRow =\n bindingRow &&\n (await ops.findOne<WorkItemDbRow>('work_items', {\n id: String(bindingRow.work_item_id),\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n }));\n if (!bindingRow || !itemRow) throw new Error('Factory start replay references missing state.');\n return {\n item: toRow(itemRow),\n binding: toBinding(bindingRow),\n pendingStart: toPendingStart(prior),\n replayed: true,\n };\n }\n const now = new Date();\n const create = input.workItem.input;\n let row = input.workItem.id\n ? await ops.findOne<WorkItemDbRow>('work_items', {\n id: input.workItem.id,\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n })\n : sourceKey(create.externalSource)\n ? await ops.findOne<WorkItemDbRow>('work_items', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n source_key: sourceKey(create.externalSource),\n })\n : null;\n let item: WorkItemRow;\n if (row) {\n row = await ops.updateAtomic<WorkItemDbRow>('work_items', { id: row.id }, current => {\n const roles = new Set([...Object.keys(current.sessions), input.role]);\n const sessions = Object.fromEntries([...roles].map(role => [role, input.session]));\n return applyUpdate({ current, userId: input.userId, input: { sessions } });\n });\n item = toRow(row!);\n } else {\n if (create.parentWorkItemId)\n validateParentRelation(\n (\n await ops.findMany<WorkItemDbRow>('work_items', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n })\n ).map(toRow),\n undefined,\n create.parentWorkItemId,\n );\n row = await ops.insertOne<WorkItemDbRow>('work_items', {\n org_id: input.orgId,\n created_by: input.userId,\n factory_project_id: input.factoryProjectId,\n external_source: create.externalSource ?? null,\n source_key: sourceKey(create.externalSource),\n parent_work_item_id: create.parentWorkItemId ?? null,\n title: create.title,\n stages: create.stages ?? [],\n stage_history: applyStageTransition([], [], create.stages ?? [], input.userId, now),\n sessions: stampSessions({ [input.role]: input.session }, input.userId),\n metadata: create.metadata ?? null,\n revision: 1,\n created_at: now,\n updated_at: now,\n });\n item = toRow(row);\n }\n await ops.updateMany(\n 'factory_run_bindings',\n {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n work_item_id: item.id,\n role: input.role,\n status: 'active',\n },\n { status: 'revoked', revoked_at: now },\n );\n const bindingRow = await ops.insertOne<GovernanceDbRow>('factory_run_bindings', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n work_item_id: item.id,\n role: input.role,\n thread_id: input.session.threadId,\n resource_id: input.resourceId,\n session_id: input.session.sessionId,\n branch: input.session.branch,\n status: 'active',\n created_at: now,\n revoked_at: null,\n });\n const pendingRow = await ops.insertOne<GovernanceDbRow>('factory_pending_starts', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n binding_id: bindingRow.id,\n kickoff_key: input.kickoffKey,\n message: input.kickoffMessage,\n status: 'pending',\n attempts: 0,\n available_at: now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n created_at: now,\n updated_at: now,\n });\n return { item, binding: toBinding(bindingRow), pendingStart: toPendingStart(pendingRow), replayed: false };\n });\n return this.storage.withDistributedLock\n ? this.storage.withDistributedLock(\n `factory-start:${input.orgId}:${input.factoryProjectId}:${input.kickoffKey}`,\n prepare,\n )\n : prepare();\n }\n\n async markPendingStart(\n bindingId: string,\n status: 'sent' | 'failed',\n lastError?: string,\n ): Promise<FactoryPendingStartRecord | null> {\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n 'factory_pending_starts',\n { binding_id: bindingId },\n () => ({ status, last_error: lastError ?? null, updated_at: new Date() }),\n );\n return row ? toPendingStart(row) : null;\n }\n\n /**\n * Create a work item, reusing the existing record when `sourceKey` already\n * has one for the project (acting twice on the same issue must not duplicate\n * the card). On reuse the provided stages replace the current ones (with the\n * transition recorded in history) and sessions/metadata are merged in. The\n * result discriminates insert from reuse so callers can audit the actual\n * outcome.\n */\n async upsert(params: {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n input: CreateWorkItemInput;\n reuseMode?: 'update' | 'preserve' | 'non-stage';\n }): Promise<UpsertWorkItemResult> {\n const run = () => this.#upsert(params);\n return params.input.parentWorkItemId\n ? this.#withProjectRelationLock(params.orgId, params.factoryProjectId, run)\n : run();\n }\n\n async #upsert({\n orgId,\n userId,\n factoryProjectId,\n input,\n reuseMode = 'update',\n }: {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n input: CreateWorkItemInput;\n reuseMode?: 'update' | 'preserve' | 'non-stage';\n }): Promise<UpsertWorkItemResult> {\n const key = sourceKey(input.externalSource);\n const reuse = async (): Promise<UpsertWorkItemResult | null> => {\n if (!key) return null;\n const existing = await this.#db.findOne<WorkItemDbRow>('work_items', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n source_key: key,\n });\n if (!existing) return null;\n if (reuseMode === 'preserve') {\n const item = toWorkItem(existing);\n return { created: false, item, previous: priorState(existing) };\n }\n\n let previous = emptyPrior();\n const updated = await this.#db.updateAtomic<WorkItemDbRow>(\n 'work_items',\n { org_id: orgId, factory_project_id: factoryProjectId, source_key: key },\n async current => {\n previous = priorState(current);\n const fullPatch = input.parentWorkItemId === null ? { ...input, parentWorkItemId: undefined } : input;\n const patch: UpdateWorkItemInput =\n reuseMode === 'non-stage'\n ? {\n title: input.title,\n parentWorkItemId: input.parentWorkItemId ?? undefined,\n metadata: input.metadata,\n }\n : fullPatch;\n if (patch.parentWorkItemId !== undefined) {\n validateParentRelation(await this.list({ orgId, factoryProjectId }), current.id, patch.parentWorkItemId);\n }\n return {\n external_source: input.externalSource ?? null,\n ...applyUpdate({ current, userId, input: patch }),\n };\n },\n );\n return updated ? { item: toWorkItem(updated), created: false, previous } : null;\n };\n\n const reused = await reuse();\n if (reused) return reused;\n\n const now = new Date();\n const stages = input.stages ?? ['intake'];\n try {\n validateParentRelation(await this.list({ orgId, factoryProjectId }), undefined, input.parentWorkItemId ?? null);\n const row = await this.#db.insertOne<WorkItemDbRow>('work_items', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n external_source: input.externalSource ?? null,\n source_key: key,\n parent_work_item_id: input.parentWorkItemId ?? null,\n title: input.title,\n stages,\n stage_history: stages.map(stage => ({ stage, enteredAt: now.toISOString(), by: userId })),\n sessions: stampSessions(input.sessions ?? {}, userId),\n metadata: input.metadata ?? null,\n revision: 1,\n created_by: userId,\n created_at: now,\n updated_at: now,\n });\n return { item: toWorkItem(row), created: true, previous: emptyPrior() };\n } catch (error) {\n if (!(error instanceof UniqueViolationError)) throw error;\n const winner = await reuse();\n if (winner) return winner;\n throw error;\n }\n }\n\n async update({\n orgId,\n id,\n userId,\n patch,\n }: {\n orgId: string;\n id: string;\n userId: string;\n patch: UpdateWorkItemInput;\n }): Promise<{ item: WorkItemRow; previous: WorkItemPriorState } | null> {\n const run = async () => {\n let previous = emptyPrior();\n const row = await this.#db.updateAtomic<WorkItemDbRow>('work_items', { org_id: orgId, id }, async current => {\n previous = priorState(current);\n if (patch.parentWorkItemId !== undefined) {\n validateParentRelation(\n await this.list({ orgId, factoryProjectId: current.factory_project_id }),\n current.id,\n patch.parentWorkItemId,\n );\n }\n return applyUpdate({ current, userId, input: patch });\n });\n return row ? { item: toWorkItem(row), previous } : null;\n };\n\n if (patch.parentWorkItemId === undefined) return run();\n const candidate = await this.#db.findOne<WorkItemDbRow>('work_items', { org_id: orgId, id });\n if (!candidate) return null;\n return this.#withProjectRelationLock(orgId, candidate.factory_project_id, run);\n }\n\n async delete({ orgId, id }: { orgId: string; id: string }): Promise<WorkItemRow | null> {\n const candidate = await this.#db.findOne<WorkItemDbRow>('work_items', { org_id: orgId, id });\n if (!candidate) return null;\n\n return this.#withProjectRelationLock(orgId, candidate.factory_project_id, async () => {\n const existing = await this.#db.findOne<WorkItemDbRow>('work_items', { org_id: orgId, id });\n if (!existing) return null;\n const deleted = await this.#db.deleteMany('work_items', { org_id: orgId, id });\n if (deleted === 0) return null;\n await this.#db.updateMany(\n 'work_items',\n { org_id: orgId, parent_work_item_id: id },\n { parent_work_item_id: null, updated_at: new Date() },\n );\n return toWorkItem(existing);\n });\n }\n}\n","/**\n * Aggregation math for the Factory Metrics page.\n *\n * Pure functions over `work_items` rows — flow metrics (throughput, cycle\n * time, stage durations, WIP, aging WIP) plus demand mix, all derived from the\n * server-appended `stageHistory` log. Keeping this DB-free makes the math unit\n * testable and lets the route stay a thin shell.\n */\n\nimport { isAutomationActor } from './base.js';\nimport type { WorkItemRow, WorkItemStageEntry } from './base.js';\n\n/** Default window span (days) when the request omits or malforms the range. */\nexport const DEFAULT_METRICS_WINDOW = 30;\n/** Hard cap on the range span (days) — bounds the gap-filled throughput array. */\nexport const MAX_METRICS_WINDOW = 366;\n\nconst DAY_MS = 86_400_000;\n\n/** Terminal stage — items here count as completed, not in-flight. */\nconst DONE_STAGE = 'done';\n\n/** Terminal stage for tracked non-completions — never a completion. */\nconst CANCELED_STAGE = 'canceled';\n\n/**\n * Terminal stages — items holding only these are not in-flight. `done` is a\n * completion (feeds throughput/cycle time); `canceled` is a tracked\n * non-completion outcome and feeds neither.\n */\nconst TERMINAL_STAGES = new Set([DONE_STAGE, CANCELED_STAGE]);\n\nconst AGING_WIP_LIMIT = 10;\n\nexport interface FactoryMetrics {\n windowDays: number;\n /** Earliest work-item creation time (ISO, window-independent) — the natural\n * lower bound for a date-range control. `null` when the board is empty. */\n earliestItemAt: string | null;\n /** Items reaching `done` per UTC day, gap-filled across the window. */\n throughput: { date: string; count: number }[];\n /** Card creation → `done` duration for items completed in the window. */\n cycleTime: { medianMs: number | null; p90Ms: number | null; samples: number };\n /** Median time spent per stage, over visits that ended inside the window. */\n stageDurations: { stage: string; medianMs: number; samples: number }[];\n /** Current cards per stage (window-independent). */\n wip: { stage: string; count: number }[];\n /** Distinct in-flight cards (at least one non-terminal stage). */\n wipTotal: number;\n /** Oldest in-flight cards by time in their current stage. */\n agingWip: { id: string; title: string; stage: string; enteredAt: string; url: string | null }[];\n /** Cards created in the window, by source. */\n sourceMix: { source: string; count: number }[];\n /** Stage moves in the window: human-performed vs total. */\n transitions: { human: number; total: number };\n /** Per-stage automation over completed visits that exited in the window. */\n stageAutomation: {\n stage: string;\n /** Completed visits (entered+exited) to this stage that exited in the window. */\n exits: number;\n /**\n * Of those: clean automated passes — the item's first visit to the stage,\n * entered *and* exited by an automation actor. Missing `exitedBy` (entries\n * written before exit stamping) counts as human.\n */\n automated: number;\n /**\n * Outcomes of the automated passes' items, mutually exclusive, first match\n * wins: `reworked` (a later visit to the same stage exists — deliberately\n * outranks `done`: an automated pass that needed a redo is an automation\n * failure even if the item eventually merged), then `done`, then\n * `canceled`, then `inFlight`.\n */\n outcomes: { done: number; canceled: number; reworked: number; inFlight: number };\n }[];\n}\n\nconst DATE_ONLY_RE = /^\\d{4}-\\d{2}-\\d{2}$/;\n/** Datetime carrying an explicit `Z` or `±HH:MM` offset. */\nconst ZONED_DATETIME_RE = /(?:[Zz]|[+-]\\d{2}:?\\d{2})$/;\n\nfunction parseRangeParam(value: unknown, boundary: 'from' | 'to'): number | undefined {\n if (typeof value !== 'string' || value.length === 0) return undefined;\n const dateOnly = DATE_ONLY_RE.test(value);\n // Timezone-less datetimes are parsed as server-local by Date.parse, so the\n // window would shift by deployment region — reject them as invalid.\n if (!dateOnly && !ZONED_DATETIME_RE.test(value)) return undefined;\n const time = Date.parse(value);\n if (Number.isNaN(time)) return undefined;\n return boundary === 'to' && dateOnly ? time + DAY_MS : time;\n}\n\nfunction utcDayStart(time: number): number {\n return Date.parse(`${utcDay(time)}T00:00:00Z`);\n}\n\n/**\n * Resolve untrusted `from`/`to` into a bounded half-open UTC window. A date-only\n * `to` covers the whole day; an open/future end resolves to the end of the\n * current UTC day (not `now`) so an event at this instant stays inside the\n * window instead of on its excluded edge.\n */\nexport function parseMetricsRange(\n fromParam: unknown,\n toParam: unknown,\n now: Date,\n): { windowStart: number; windowEnd: number } {\n const nowMs = now.getTime();\n const endOfToday = utcDayStart(nowMs) + DAY_MS;\n const requestedEnd = parseRangeParam(toParam, 'to') ?? endOfToday;\n const windowEnd = Math.min(requestedEnd, endOfToday);\n const lastIncludedDay = utcDayStart(windowEnd - 1);\n const defaultStart = lastIncludedDay - (DEFAULT_METRICS_WINDOW - 1) * DAY_MS;\n const parsedFrom = parseRangeParam(fromParam, 'from');\n let windowStart = parsedFrom !== undefined && parsedFrom < windowEnd ? parsedFrom : defaultStart;\n const earliestStart = lastIncludedDay - (MAX_METRICS_WINDOW - 1) * DAY_MS;\n if (windowStart < earliestStart) windowStart = earliestStart;\n return { windowStart, windowEnd };\n}\n\nfunction parseTime(iso: string): number {\n const time = Date.parse(iso);\n return Number.isNaN(time) ? 0 : time;\n}\n\n/** Nearest-rank percentile over an unsorted sample list. */\nfunction percentile(samples: number[], fraction: number): number | null {\n if (samples.length === 0) return null;\n const sorted = [...samples].sort((a, b) => a - b);\n const rank = Math.max(1, Math.ceil(fraction * sorted.length));\n return sorted[rank - 1]!;\n}\n\n/** UTC `YYYY-MM-DD` for a timestamp. */\nfunction utcDay(time: number): string {\n return new Date(time).toISOString().slice(0, 10);\n}\n\n/**\n * The item's completion time: the `enteredAt` of its still-open `done` entry.\n * `undefined` when the item isn't currently done (including when it was pulled\n * back out of done — that visit has `exitedAt` and doesn't count).\n */\nfunction completedAt(item: WorkItemRow): number | undefined {\n if (!item.stages.includes(DONE_STAGE)) return undefined;\n for (let i = item.stageHistory.length - 1; i >= 0; i--) {\n const entry = item.stageHistory[i]!;\n if (entry.stage === DONE_STAGE && entry.exitedAt === undefined) return parseTime(entry.enteredAt);\n }\n return undefined;\n}\n\n/** Open (no `exitedAt`) history entry for a currently-held non-terminal stage. */\nfunction openEntries(item: WorkItemRow): WorkItemStageEntry[] {\n return item.stageHistory.filter(\n entry => entry.exitedAt === undefined && !TERMINAL_STAGES.has(entry.stage) && item.stages.includes(entry.stage),\n );\n}\n\nexport function computeFactoryMetrics(\n items: WorkItemRow[],\n opts: { windowStart: number; windowEnd: number },\n): FactoryMetrics {\n const { windowStart, windowEnd } = opts;\n\n // Earliest creation across all items (window-independent) — the range lower bound.\n let earliest = Infinity;\n for (const item of items) earliest = Math.min(earliest, item.createdAt.getTime());\n const earliestItemAt = Number.isFinite(earliest) ? new Date(earliest).toISOString() : null;\n\n // ── Throughput + cycle time (completed in window) ─────────────────────────\n // Gap-fill every UTC calendar date intersecting the half-open window.\n const throughputByDay = new Map<string, number>();\n const firstDay = utcDayStart(windowStart);\n for (let day = firstDay; day < windowEnd; day += DAY_MS) {\n throughputByDay.set(utcDay(day), 0);\n }\n const cycleSamples: number[] = [];\n for (const item of items) {\n const doneAt = completedAt(item);\n if (doneAt === undefined || doneAt < windowStart || doneAt >= windowEnd) continue;\n const day = utcDay(doneAt);\n throughputByDay.set(day, (throughputByDay.get(day) ?? 0) + 1);\n cycleSamples.push(Math.max(0, doneAt - item.createdAt.getTime()));\n }\n\n // ── Stage durations (visits that ended in window) ─────────────────────────\n const durationsByStage = new Map<string, number[]>();\n for (const item of items) {\n for (const entry of item.stageHistory) {\n if (entry.exitedAt === undefined || TERMINAL_STAGES.has(entry.stage)) continue;\n const exited = parseTime(entry.exitedAt);\n if (exited < windowStart || exited >= windowEnd) continue;\n const duration = Math.max(0, exited - parseTime(entry.enteredAt));\n const samples = durationsByStage.get(entry.stage) ?? [];\n samples.push(duration);\n durationsByStage.set(entry.stage, samples);\n }\n }\n\n // ── Current WIP + aging (window-independent) ──────────────────────────────\n const wipByStage = new Map<string, number>();\n let wipTotal = 0;\n const aging: FactoryMetrics['agingWip'] = [];\n for (const item of items) {\n for (const stage of item.stages) {\n wipByStage.set(stage, (wipByStage.get(stage) ?? 0) + 1);\n }\n const inFlightStages = item.stages.filter(stage => !TERMINAL_STAGES.has(stage));\n if (inFlightStages.length === 0) continue;\n wipTotal += 1;\n // Age the card by its longest-held current stage; fall back to creation\n // time if history is missing an open entry (shouldn't happen — history is\n // server-appended).\n const open = openEntries(item);\n const oldest = open.reduce<WorkItemStageEntry | undefined>(\n (best, entry) => (!best || parseTime(entry.enteredAt) < parseTime(best.enteredAt) ? entry : best),\n undefined,\n );\n aging.push({\n id: item.id,\n title: item.title,\n stage: oldest?.stage ?? inFlightStages[0]!,\n enteredAt: oldest?.enteredAt ?? item.createdAt.toISOString(),\n url: item.externalSource?.url ?? null,\n });\n }\n aging.sort((a, b) => parseTime(a.enteredAt) - parseTime(b.enteredAt));\n\n // ── Demand mix + transitions (window) ─────────────────────────────────────\n const sourceCounts = new Map<string, number>();\n let transitionsTotal = 0;\n let transitionsHuman = 0;\n for (const item of items) {\n if (item.createdAt.getTime() >= windowStart && item.createdAt.getTime() < windowEnd) {\n const source = item.externalSource\n ? `${item.externalSource.integrationId}:${item.externalSource.type}`\n : 'manual';\n sourceCounts.set(source, (sourceCounts.get(source) ?? 0) + 1);\n }\n for (const entry of item.stageHistory) {\n const entered = parseTime(entry.enteredAt);\n if (entered < windowStart || entered >= windowEnd) continue;\n transitionsTotal += 1;\n if (!isAutomationActor(entry.by)) transitionsHuman += 1;\n }\n }\n\n // ── Per-stage automation (completed visits that exited in window) ─────────\n // Rows appear in insertion order of each stage's first counted exit;\n // terminal stages never get rows (they have no meaningful \"pass through\").\n const automationByStage = new Map<string, FactoryMetrics['stageAutomation'][number]>();\n for (const item of items) {\n const itemDone = completedAt(item) !== undefined;\n const itemCanceled = item.stages.includes(CANCELED_STAGE);\n for (let i = 0; i < item.stageHistory.length; i++) {\n const entry = item.stageHistory[i]!;\n if (entry.exitedAt === undefined || TERMINAL_STAGES.has(entry.stage)) continue;\n const exited = parseTime(entry.exitedAt);\n if (exited < windowStart || exited >= windowEnd) continue;\n let row = automationByStage.get(entry.stage);\n if (!row) {\n row = {\n stage: entry.stage,\n exits: 0,\n automated: 0,\n outcomes: { done: 0, canceled: 0, reworked: 0, inFlight: 0 },\n };\n automationByStage.set(entry.stage, row);\n }\n row.exits += 1;\n // A clean automated pass: automation entered AND exited it, and this is\n // the item's first visit to the stage (a re-run is rework, not clean\n // automation). Missing `exitedBy` → human-exited → not automated.\n const firstVisitIndex = item.stageHistory.findIndex(e => e.stage === entry.stage);\n if (firstVisitIndex !== i || !isAutomationActor(entry.by) || !isAutomationActor(entry.exitedBy)) continue;\n row.automated += 1;\n const reworked = item.stageHistory.some((e, j) => j > i && e.stage === entry.stage);\n if (reworked) row.outcomes.reworked += 1;\n else if (itemDone) row.outcomes.done += 1;\n else if (itemCanceled) row.outcomes.canceled += 1;\n else row.outcomes.inFlight += 1;\n }\n }\n\n return {\n windowDays: throughputByDay.size,\n earliestItemAt,\n throughput: [...throughputByDay.entries()]\n .map(([date, count]) => ({ date, count }))\n .sort((a, b) => a.date.localeCompare(b.date)),\n cycleTime: {\n medianMs: percentile(cycleSamples, 0.5),\n p90Ms: percentile(cycleSamples, 0.9),\n samples: cycleSamples.length,\n },\n stageDurations: [...durationsByStage.entries()].map(([stage, samples]) => ({\n stage,\n medianMs: percentile(samples, 0.5)!,\n samples: samples.length,\n })),\n wip: [...wipByStage.entries()].map(([stage, count]) => ({ stage, count })),\n wipTotal,\n agingWip: aging.slice(0, AGING_WIP_LIMIT),\n sourceMix: [...sourceCounts.entries()]\n .map(([source, count]) => ({ source, count }))\n .sort((a, b) => b.count - a.count),\n transitions: { human: transitionsHuman, total: transitionsTotal },\n stageAutomation: [...automationByStage.values()],\n };\n}\n","/**\n * Base class for factory route modules.\n *\n * Route modules build Mastra `apiRoutes` from injected dependencies instead of\n * reaching into host globals. The host server (e.g. `mastracode/web`) supplies\n * the auth seam and storage domain handles at construction time, so the routes\n * stay portable and testable with fakes.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\n/**\n * The auth surface factory routes need, implemented by the host server.\n *\n * Local (no-auth) deployments implement this with a stub where `enabled()`\n * returns `false` and `tenant()` returns `undefined` — routes then take their\n * single-user local paths.\n */\nexport interface RouteAuth {\n /** Whether an auth provider is active (tenant mode). */\n enabled(): boolean;\n /**\n * Resolve (and cache) the signed-in user for the request, if any. Must be\n * called before `tenant()` so the request context is populated.\n */\n ensureUser(c: Context): Promise<unknown>;\n /** Tenant identity for the request, when signed in. */\n tenant(c: Context): { orgId?: string; userId: string } | undefined;\n /** Fail-closed check that the caller administers the given organization. */\n isOrganizationAdmin(c: Context, organizationId: string): Promise<boolean>;\n}\n\n/** Dependencies shared by every factory route module. */\nexport interface RouteDependencies {\n auth: RouteAuth;\n}\n\n/**\n * A route module: constructed once at boot with its dependencies, then asked\n * for the `ApiRoute[]` it serves.\n */\nexport abstract class Route<TDeps extends RouteDependencies = RouteDependencies> {\n protected readonly deps: TDeps;\n\n constructor(deps: TDeps) {\n this.deps = deps;\n }\n\n /** Build the Mastra `apiRoutes` served by this module. */\n abstract routes(): ApiRoute[];\n}\n"],"mappings":"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","names":["FactoryStorageDomain","UniqueViolationError"]}
|
|
1
|
+
{"version":3,"sources":["../../src/routes/work-items.ts","../../src/rules/start-coordinator.ts","../../src/rules/types.ts","../../src/storage/domains/queue-health/base.ts","../../src/storage/domains/work-items/base.ts","../../src/storage/domains/work-items/metrics.ts","../../src/routes/route.ts"],"sourcesContent":["/**\n * Mastra `apiRoutes` for Factory work items (the kanban board).\n *\n * Registered alongside the other `/web/*` routes behind the host auth gate.\n * The board is org-wide: every route re-resolves the caller's `(orgId, userId)`\n * tenant and scopes reads/writes by `orgId`, so any org member sees and moves\n * the same cards while `created_by` / stage history record who acted.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport { registerApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\nimport type {\n FactoryStartCoordinator,\n FactoryStartPreparedResult,\n FactoryStartRequest,\n} from '../rules/start-coordinator.js';\nimport { FactoryStartTransitionError } from '../rules/start-coordinator.js';\nimport type { FactoryTransitionRequest, FactoryTransitionService } from '../rules/transition-service.js';\nimport type { FactoryRuleBoard, FactoryRuleStage } from '../rules/types.js';\nimport { FACTORY_RULE_BOARDS, FACTORY_RULE_STAGES } from '../rules/types.js';\nimport type { AuditEmitter } from '../storage/domains/audit/domain.js';\nimport type { FactoryProjectsStorage } from '../storage/domains/projects/base.js';\nimport type { QueueHealthStorage } from '../storage/domains/queue-health/base.js';\nimport { thresholdsOrDefault } from '../storage/domains/queue-health/base.js';\nimport type {\n CreateWorkItemInput,\n ExternalWorkItemSource,\n FactoryDeferredDecisionRecord,\n FactoryDispatchStatus,\n UpdateWorkItemInput,\n WorkItemPriorState,\n WorkItemRow,\n WorkItemSessionInput,\n WorkItemStage,\n WorkItemsStorage,\n} from '../storage/domains/work-items/base.js';\nimport { WorkItemRelationError } from '../storage/domains/work-items/base.js';\nimport { computeFactoryMetrics, parseMetricsRange } from '../storage/domains/work-items/metrics.js';\nimport type { RouteDependencies } from './route.js';\nimport { Route } from './route.js';\n\nexport interface WorkItemRoutesDeps extends RouteDependencies {\n audit: AuditEmitter;\n /** Factory projects domain — validates the `:id` project belongs to the caller's org. */\n projects: FactoryProjectsStorage;\n /** Work-items domain backing the kanban board. */\n workItems: WorkItemsStorage;\n /** Per-project queue-health threshold config. */\n queueHealth: QueueHealthStorage;\n /** Governed stage-transition service. Stage moves 503 when absent. */\n transitionService?: Pick<FactoryTransitionService, 'transition' | 'ruleSetVersion'>;\n /** Coordinator that binds a Factory run before dispatching its kickoff. */\n startCoordinator?: Pick<FactoryStartCoordinator, 'prepare'>;\n}\n\nfunction loose(c: unknown): Context {\n return c as Context;\n}\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\nconst MAX_STAGES = 16;\nconst MAX_STAGE_LENGTH = 64;\nconst MAX_METADATA_BYTES = 16 * 1024;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction validStages(value: unknown): value is WorkItemStage[] {\n return (\n Array.isArray(value) &&\n value.length > 0 &&\n value.length <= MAX_STAGES &&\n value.every(\n stage => typeof stage === 'string' && stage.length <= MAX_STAGE_LENGTH && /^[a-z0-9][a-z0-9_-]*$/i.test(stage),\n ) &&\n new Set(value).size === value.length\n );\n}\n\nfunction validMetadata(value: unknown): value is Record<string, unknown> | null {\n if (value === null) return true;\n if (!isRecord(value)) return false;\n try {\n return JSON.stringify(value).length <= MAX_METADATA_BYTES;\n } catch {\n return false;\n }\n}\n\nfunction parseExternalSource(value: unknown): ExternalWorkItemSource | null | undefined {\n if (value === undefined || value === null) return value;\n if (!isRecord(value)) return undefined;\n const { integrationId, type, externalId, url } = value;\n if (typeof integrationId !== 'string' || integrationId.length === 0 || integrationId.length > 128) return undefined;\n if (typeof type !== 'string' || type.length === 0 || type.length > 128) return undefined;\n if (typeof externalId !== 'string' || externalId.length === 0 || externalId.length > 512) return undefined;\n if (url !== undefined && (typeof url !== 'string' || url.length > 2048)) return undefined;\n return { integrationId, type, externalId, ...(url !== undefined ? { url } : {}) };\n}\n\nfunction parseParentWorkItemId(value: unknown): string | null | undefined {\n if (value === null) return null;\n if (typeof value !== 'string' || !UUID_RE.test(value)) return undefined;\n return value;\n}\n\nfunction parseSessions(value: unknown): Record<string, WorkItemSessionInput> | undefined {\n if (!isRecord(value)) return undefined;\n const out: Record<string, WorkItemSessionInput> = {};\n for (const [role, session] of Object.entries(value)) {\n if (!role || role.length > 64 || !isRecord(session)) return undefined;\n const { sessionId, branch, threadId } = session;\n if (typeof sessionId !== 'string' || sessionId.length === 0 || sessionId.length > 512) return undefined;\n if (typeof branch !== 'string' || branch.length === 0 || branch.length > 512) return undefined;\n if (typeof threadId !== 'string' || threadId.length === 0 || threadId.length > 512) return undefined;\n out[role] = { sessionId, branch, threadId };\n }\n return out;\n}\n\n/** Validate an untrusted create body. Unknown keys are dropped. */\nexport function parseCreateWorkItem(body: unknown): CreateWorkItemInput | null {\n if (!isRecord(body)) return null;\n const { externalSource, title, stages, sessions, metadata } = body;\n if (typeof title !== 'string' || title.trim().length === 0 || title.length > 500) return null;\n\n const hasParentWorkItemId = 'parentWorkItemId' in body;\n const parentWorkItemId = hasParentWorkItemId ? parseParentWorkItemId(body.parentWorkItemId) : undefined;\n if (hasParentWorkItemId && parentWorkItemId === undefined) return null;\n const parsedSource = parseExternalSource(externalSource);\n if (externalSource !== undefined && parsedSource === undefined) return null;\n if (stages !== undefined && !validStages(stages)) return null;\n const parsedSessions = sessions === undefined ? undefined : parseSessions(sessions);\n if (sessions !== undefined && parsedSessions === undefined) return null;\n if (metadata !== undefined && !validMetadata(metadata)) return null;\n\n return {\n title: title.trim(),\n ...(parsedSource !== undefined ? { externalSource: parsedSource } : {}),\n ...(hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {}),\n ...(stages !== undefined ? { stages } : {}),\n ...(parsedSessions !== undefined ? { sessions: parsedSessions } : {}),\n ...(metadata !== undefined ? { metadata } : {}),\n };\n}\n\n/** Validate an untrusted patch body. Unknown keys are dropped. */\nexport function parseUpdateWorkItem(body: unknown): UpdateWorkItemInput | null {\n if (!isRecord(body)) return null;\n const { title, stages, sessions, metadata } = body;\n const hasParentWorkItemId = 'parentWorkItemId' in body;\n if (\n title === undefined &&\n stages === undefined &&\n sessions === undefined &&\n metadata === undefined &&\n !hasParentWorkItemId\n )\n return null;\n const parentWorkItemId = hasParentWorkItemId ? parseParentWorkItemId(body.parentWorkItemId) : undefined;\n if (hasParentWorkItemId && parentWorkItemId === undefined) return null;\n if (title !== undefined && (typeof title !== 'string' || title.trim().length === 0 || title.length > 500))\n return null;\n if (stages !== undefined && !validStages(stages)) return null;\n const parsedSessions = sessions === undefined ? undefined : parseSessions(sessions);\n if (sessions !== undefined && parsedSessions === undefined) return null;\n if (metadata !== undefined && !validMetadata(metadata)) return null;\n\n return {\n ...(hasParentWorkItemId ? { parentWorkItemId: parentWorkItemId ?? null } : {}),\n ...(title !== undefined ? { title: title.trim() } : {}),\n ...(stages !== undefined ? { stages } : {}),\n ...(parsedSessions !== undefined ? { sessions: parsedSessions } : {}),\n ...(metadata !== undefined ? { metadata } : {}),\n };\n}\n\nasync function readJson(c: Context): Promise<unknown | undefined> {\n try {\n return await c.req.json();\n } catch {\n return undefined;\n }\n}\n\n/** Fields a PATCH touched, for the bounded `updated` event summary. */\nfunction patchedFields(patch: Record<string, unknown>): string[] {\n return Object.keys(patch).filter(key => patch[key] !== undefined);\n}\n\nfunction boundedText(value: unknown, max: number): string | undefined {\n if (typeof value !== 'string') return undefined;\n const normalized = value.trim();\n return normalized.length > 0 && normalized.length <= max ? normalized : undefined;\n}\n\nfunction parseTransitionBody(\n body: unknown,\n): Omit<FactoryTransitionRequest, 'orgId' | 'factoryProjectId' | 'workItemId' | 'actor'> | null {\n if (!isRecord(body)) return null;\n const board = FACTORY_RULE_BOARDS.includes(body.board as FactoryRuleBoard)\n ? (body.board as FactoryRuleBoard)\n : undefined;\n const stage = FACTORY_RULE_STAGES.includes(body.stage as FactoryRuleStage)\n ? (body.stage as FactoryRuleStage)\n : undefined;\n const requestId = boundedText(body.requestId, 256);\n const cause = boundedText(body.cause, 256);\n if (\n !board ||\n !stage ||\n !requestId ||\n !UUID_RE.test(requestId) ||\n !cause ||\n !Number.isInteger(body.expectedRevision) ||\n Number(body.expectedRevision) < 1\n ) {\n return null;\n }\n return {\n board,\n stage,\n expectedRevision: Number(body.expectedRevision),\n ingress: { type: 'human', identity: requestId },\n cause,\n };\n}\n\nfunction parseInvocation(value: unknown): FactoryStartRequest['invocation'] | undefined | null {\n if (value === undefined) return undefined;\n if (!isRecord(value)) return null;\n if (value.type === 'prompt') {\n const prompt = boundedText(value.prompt, 16_384);\n return prompt ? { type: 'prompt', prompt } : null;\n }\n if (value.type === 'skill') {\n const skillName = boundedText(value.skillName, 64);\n const args = typeof value.arguments === 'string' && value.arguments.length <= 16_384 ? value.arguments : undefined;\n return skillName && args !== undefined ? { type: 'skill', skillName, arguments: args } : null;\n }\n return null;\n}\n\nfunction parseStartBody(\n body: unknown,\n tenant: { orgId: string; userId: string },\n factoryProjectId: string,\n): FactoryStartRequest | null {\n if (!isRecord(body) || !isRecord(body.workItem)) return null;\n const input = parseCreateWorkItem(body.workItem.input);\n const sessionId = boundedText(body.sessionId, 256);\n const threadTitle = boundedText(body.threadTitle, 512);\n const kickoffKey = boundedText(body.kickoffKey, 256);\n const invocation = parseInvocation(body.invocation);\n const destinationStage = FACTORY_RULE_STAGES.includes(body.destinationStage as FactoryRuleStage)\n ? (body.destinationStage as FactoryRuleStage)\n : undefined;\n const role = boundedText(body.workItem.role, 32);\n const id = body.workItem.id === undefined ? undefined : boundedText(body.workItem.id, 64);\n if (body.workItem.id !== undefined && (!id || !UUID_RE.test(id))) return null;\n if (\n !input ||\n !sessionId ||\n !UUID_RE.test(sessionId) ||\n !threadTitle ||\n !kickoffKey ||\n !UUID_RE.test(kickoffKey) ||\n invocation === null ||\n !destinationStage ||\n !role\n ) {\n return null;\n }\n const threadTags = isRecord(body.threadTags)\n ? Object.fromEntries(\n Object.entries(body.threadTags)\n .filter(\n (entry): entry is [string, string] =>\n boundedText(entry[0], 64) !== undefined && boundedText(entry[1], 256) !== undefined,\n )\n .map(([key, value]) => [key, value.trim()]),\n )\n : undefined;\n return {\n ...tenant,\n factoryProjectId,\n sessionId,\n threadTitle,\n threadTags,\n kickoffKey,\n invocation,\n destinationStage,\n workItem: { id, role, input },\n };\n}\n\nconst DECISION_STATUSES = new Set<FactoryDispatchStatus>(['pending', 'leased', 'retry', 'succeeded', 'failed']);\nconst DEFAULT_DECISION_PAGE_SIZE = 25;\nconst MAX_DECISION_PAGE_SIZE = 50;\n\nfunction parseDecisionStatuses(raw: string | undefined): FactoryDispatchStatus[] | undefined {\n if (!raw) return undefined;\n const statuses = [...new Set(raw.split(',').map(status => status.trim()))].filter(\n (status): status is FactoryDispatchStatus => DECISION_STATUSES.has(status as FactoryDispatchStatus),\n );\n return statuses.length > 0 ? statuses : undefined;\n}\n\nfunction parseDecisionLimit(raw: string | undefined): number {\n const parsed = raw ? Number.parseInt(raw, 10) : DEFAULT_DECISION_PAGE_SIZE;\n if (!Number.isFinite(parsed)) return DEFAULT_DECISION_PAGE_SIZE;\n return Math.max(1, Math.min(MAX_DECISION_PAGE_SIZE, parsed));\n}\n\nfunction encodeDecisionCursor(decision: FactoryDeferredDecisionRecord): string {\n return Buffer.from(JSON.stringify([decision.createdAt.toISOString(), decision.id]), 'utf8').toString('base64url');\n}\n\nfunction parseDecisionCursor(raw: string | undefined): { createdAt: Date; id: string } | undefined {\n if (!raw) return undefined;\n try {\n const decoded = JSON.parse(Buffer.from(raw, 'base64url').toString('utf8')) as unknown;\n if (\n !Array.isArray(decoded) ||\n decoded.length !== 2 ||\n typeof decoded[0] !== 'string' ||\n typeof decoded[1] !== 'string'\n ) {\n return undefined;\n }\n const createdAt = new Date(decoded[0]);\n if (Number.isNaN(createdAt.getTime()) || !UUID_RE.test(decoded[1])) return undefined;\n return { createdAt, id: decoded[1] };\n } catch {\n return undefined;\n }\n}\n\nfunction decisionSummary(decision: FactoryDeferredDecisionRecord) {\n const type = typeof decision.decision.type === 'string' ? decision.decision.type.slice(0, 64) : 'unknown';\n return {\n id: decision.id,\n evaluationId: decision.evaluationId,\n workItemId: decision.workItemId,\n type,\n status: decision.status,\n attempts: decision.attempts,\n lastError: decision.lastError?.slice(0, 512) ?? null,\n createdAt: decision.createdAt.toISOString(),\n updatedAt: decision.updatedAt.toISOString(),\n completedAt: decision.completedAt?.toISOString() ?? null,\n };\n}\n\nexport class WorkItemRoutes extends Route<WorkItemRoutesDeps> {\n /** Resolve the `(orgId, userId)` tenant or a ready-to-return error response. */\n async #resolveTenant(c: Context): Promise<{ orgId: string; userId: string } | { response: Response }> {\n await this.deps.auth.ensureUser(c);\n const tenant = this.deps.auth.tenant(c);\n if (!tenant) return { response: c.json({ error: 'unauthorized' }, 401) };\n if (!tenant.orgId) {\n return {\n response: c.json(\n { error: 'organization_required', message: 'The Factory board requires an organization.' },\n 403,\n ),\n };\n }\n return { orgId: tenant.orgId, userId: tenant.userId };\n }\n\n /**\n * Resolve the tenant AND the org-owned project from the `:id` param. Work\n * items hang off a project, so listing/creating requires the project to\n * exist in the caller's org.\n */\n async #resolveProject(\n c: Context,\n ): Promise<{ orgId: string; userId: string; factoryProjectId: string } | { response: Response }> {\n const tenant = await this.#resolveTenant(c);\n if ('response' in tenant) return tenant;\n\n const projectId = c.req.param('id');\n if (!projectId || !UUID_RE.test(projectId)) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n const { projects } = this.deps;\n await projects.ensureReady();\n const project = await projects.get({ orgId: tenant.orgId, id: projectId });\n if (!project) {\n return { response: c.json({ error: 'Project not found' }, 404) };\n }\n return { ...tenant, factoryProjectId: projectId };\n }\n\n /**\n * Emit the audit events a successful work-item PATCH implies: always\n * `updated`, plus `stage_moved` when the stages actually changed and one\n * `run.started` per session role the patch introduced.\n */\n async #auditWorkItemPatch({\n context,\n item,\n previous,\n patch,\n }: {\n context: Context;\n item: WorkItemRow;\n previous: WorkItemPriorState;\n patch: Record<string, unknown>;\n }): Promise<void> {\n const { audit } = this.deps;\n const target = { type: 'work_item', id: item.id, name: item.title };\n await audit.emit({\n context,\n input: {\n action: 'factory.work_item.updated',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: { fields: patchedFields(patch) },\n },\n });\n\n const stagesChanged =\n patch.stages !== undefined &&\n (previous.stages.length !== item.stages.length || previous.stages.some((s, i) => s !== item.stages[i]));\n if (stagesChanged) {\n await audit.emit({\n context,\n input: {\n action: 'factory.work_item.stage_moved',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: { from: previous.stages, to: item.stages },\n },\n });\n }\n\n const newRoles = Object.keys(item.sessions).filter(role => !previous.sessionRoles.includes(role));\n for (const role of newRoles) {\n const session = item.sessions[role];\n await audit.emit({\n context,\n input: {\n action: 'factory.run.started',\n factoryProjectId: item.factoryProjectId,\n targets: [target],\n metadata: {\n role,\n branch: session?.branch,\n threadId: session?.threadId,\n sessionId: session?.sessionId,\n },\n },\n });\n }\n }\n\n /** Build the Factory work-item routes as Mastra `apiRoutes`. */\n routes(): ApiRoute[] {\n const { audit, workItems, queueHealth, transitionService, startCoordinator } = this.deps;\n return [\n // ── List the org's work items for a project ─────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({ workItems: items });\n },\n }),\n\n // ── Flow metrics aggregated over the project's work items ───────────────\n registerApiRoute('/web/factory/projects/:id/metrics', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const { windowStart, windowEnd } = parseMetricsRange(\n loose(c).req.query('from'),\n loose(c).req.query('to'),\n new Date(),\n );\n await workItems.ensureReady();\n const items = await workItems.list({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n });\n return c.json({ metrics: computeFactoryMetrics(items, { windowStart, windowEnd }) });\n },\n }),\n\n // ── Per-project queue-health age-threshold config (seconds) ─────────────\n registerApiRoute('/web/factory/projects/:id/health/thresholds', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n await queueHealth.ensureReady();\n const stored = await queueHealth.getConfig(resolved.orgId, resolved.factoryProjectId);\n // Validate at the read choke point: `getConfig` round-trips a stored\n // JSONB row, and only `saveConfig` validates on write — a corrupted or\n // hand-edited row (empty / non-ascending) would otherwise flow to the\n // chart and invert bucket colors. Fall back to the default on invalid.\n return c.json({ thresholds: thresholdsOrDefault(stored) });\n },\n }),\n\n // ── Bounded durable rule-decision status ────────────────────────────────\n registerApiRoute('/web/factory/projects/:id/decisions', {\n method: 'GET',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n\n const cursorRaw = context.req.query('before');\n const before = parseDecisionCursor(cursorRaw);\n if (cursorRaw && !before) return c.json({ error: 'invalid_cursor' }, 400);\n await workItems.ensureReady();\n const page = await workItems.listDeferredDecisionPage({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n statuses: parseDecisionStatuses(context.req.query('statuses')),\n before,\n limit: parseDecisionLimit(context.req.query('limit')),\n });\n const last = page.decisions.at(-1);\n return c.json({\n decisions: page.decisions.map(decisionSummary),\n ...(page.hasMore && last ? { nextCursor: encodeDecisionCursor(last) } : {}),\n });\n },\n }),\n\n registerApiRoute('/web/factory/projects/:id/decisions/:decisionId/retry', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const context = loose(c);\n const resolved = await this.#resolveProject(context);\n if ('response' in resolved) return resolved.response;\n const decisionId = context.req.param('decisionId');\n if (!decisionId || !UUID_RE.test(decisionId)) return c.json({ error: 'invalid_decision_id' }, 422);\n await workItems.ensureReady();\n const decision = await workItems.retryDeferredDecision(\n resolved.orgId,\n resolved.factoryProjectId,\n decisionId,\n new Date(),\n );\n if (!decision) return c.json({ error: 'decision_not_retryable' }, 409);\n return c.json({ decision: decisionSummary(decision) });\n },\n }),\n\n // ── Create (upsert on sourceKey) a work item ─────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const input = parseCreateWorkItem(body);\n if (!input) return c.json({ error: 'invalid_work_item' }, 400);\n if ((input.stages ?? ['intake']).length !== 1 || (input.stages ?? ['intake'])[0] !== 'intake') {\n return c.json(\n { error: 'governed_transition_required', message: 'New work items must enter through Factory intake.' },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const result = await workItems.upsert({\n orgId: resolved.orgId,\n userId: resolved.userId,\n factoryProjectId: resolved.factoryProjectId,\n input,\n reuseMode: 'non-stage',\n });\n let item = result.item;\n if (result.created) {\n if (!transitionService) {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ error: 'factory_transitions_unavailable' }, 503);\n }\n const entered = await transitionService.transition({\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId: item.id,\n board: item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: 'intake',\n expectedRevision: item.revision,\n actor: { type: 'human', id: resolved.userId },\n ingress: { type: 'human', identity: `work-item:${item.id}:initial-entry` },\n cause: 'work_item_created',\n initialEntry: true,\n });\n if (entered.status === 'rejected') {\n await workItems.delete({ orgId: resolved.orgId, id: item.id });\n return c.json({ status: 'rejected', code: entered.code, reason: entered.reason }, 422);\n }\n item = (await workItems.getForProject(resolved.orgId, resolved.factoryProjectId, item.id)) ?? item;\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.created',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: item.id, name: item.title }],\n metadata: { externalSource: item.externalSource, stages: item.stages },\n },\n });\n } else {\n // Source-key reuse: the POST updated an existing card, so audit it\n // as an update (plus stage/run events) instead of a false creation.\n const { stages: _stages, sessions: _sessions, ...boundedPatch } = input;\n await this.#auditWorkItemPatch({\n context: loose(c),\n item,\n previous: result.previous,\n patch: boundedPatch as unknown as Record<string, unknown>,\n });\n }\n return c.json({ workItem: item });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Authoritative stage transition ──────────────────────────────────────\n registerApiRoute('/web/factory/projects/:id/work-items/:workItemId/transition', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n const workItemId = loose(c).req.param('workItemId');\n if (!workItemId || !UUID_RE.test(workItemId)) return c.json({ error: 'Work item not found' }, 404);\n const parsed = parseTransitionBody(await readJson(loose(c)));\n if (!parsed) return c.json({ error: 'invalid_transition_request' }, 400);\n if (!transitionService) {\n return c.json({ error: 'factory_transition_unavailable' }, 503);\n }\n await workItems.ensureReady();\n const result = await transitionService.transition({\n ...parsed,\n orgId: resolved.orgId,\n factoryProjectId: resolved.factoryProjectId,\n workItemId,\n actor: { type: 'human', id: resolved.userId },\n ingress: {\n ...parsed.ingress,\n identity: `human:${resolved.userId}:${parsed.ingress.identity}`,\n },\n });\n await audit.emit({\n context: loose(c),\n input: {\n action:\n result.status === 'accepted'\n ? 'factory.work_item.stage_moved'\n : 'factory.work_item.transition_rejected',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: workItemId }],\n metadata: {\n transitionId: result.transitionId,\n ingressType: parsed.ingress.type,\n ruleSetVersion: transitionService.ruleSetVersion,\n ...(result.status === 'accepted'\n ? { to: result.stage, revision: result.revision }\n : { code: result.code, reason: result.reason }),\n },\n },\n });\n if (result.status === 'accepted') return c.json({ result });\n return c.json({ result }, result.code === 'stale' ? 409 : 422);\n },\n }),\n\n // ── Bind a Factory run before dispatching its kickoff ────────────────────\n registerApiRoute('/web/factory/projects/:id/runs/start', {\n method: 'POST',\n requiresAuth: false,\n handler: async c => {\n const resolved = await this.#resolveProject(loose(c));\n if ('response' in resolved) return resolved.response;\n if (!startCoordinator) {\n return c.json({ error: 'factory_start_unavailable' }, 503);\n }\n const input = parseStartBody(await readJson(loose(c)), resolved, resolved.factoryProjectId);\n if (!input) return c.json({ error: 'invalid_factory_start' }, 400);\n input.requestContext = loose(c).get('requestContext');\n if (\n !input.workItem.id &&\n ((input.workItem.input.stages ?? ['intake']).length !== 1 ||\n (input.workItem.input.stages ?? ['intake'])[0] !== 'intake')\n ) {\n return c.json(\n { error: 'governed_transition_required', message: 'Create the work item in Intake before starting it.' },\n 409,\n );\n }\n await workItems.ensureReady();\n let prepared: FactoryStartPreparedResult;\n try {\n prepared = await startCoordinator.prepare(input);\n } catch (error) {\n if (error instanceof FactoryStartTransitionError) {\n return c.json({ result: error.result }, error.result.code === 'stale' ? 409 : 422);\n }\n throw error;\n }\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.run.started',\n factoryProjectId: resolved.factoryProjectId,\n targets: [{ type: 'work_item', id: prepared.workItemId }],\n metadata: {\n role: input.workItem.role,\n branch: prepared.branch,\n threadId: prepared.threadId,\n sessionId: prepared.sessionId,\n bindingId: prepared.bindingId,\n },\n },\n });\n return c.json({ prepared }, 202);\n },\n }),\n\n // ── Patch non-stage metadata / sessions / title ──────────────────────────\n registerApiRoute('/web/factory/work-items/:id', {\n method: 'PATCH',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const id = loose(c).req.param('id');\n if (!id || !UUID_RE.test(id)) return c.json({ error: 'Work item not found' }, 404);\n\n const body = await readJson(loose(c));\n if (body === undefined) return c.json({ error: 'Invalid JSON body' }, 400);\n const patch = parseUpdateWorkItem(body);\n if (!patch) return c.json({ error: 'invalid_work_item_patch' }, 400);\n if (patch.stages !== undefined) {\n return c.json(\n { error: 'governed_transition_required', message: 'Use the Factory transition endpoint to move stages.' },\n 409,\n );\n }\n\n await workItems.ensureReady();\n try {\n const updated = await workItems.update({ orgId: tenant.orgId, id, userId: tenant.userId, patch });\n if (!updated) return c.json({ error: 'Work item not found' }, 404);\n await this.#auditWorkItemPatch({\n context: loose(c),\n item: updated.item,\n previous: updated.previous,\n patch: patch as Record<string, unknown>,\n });\n return c.json({ workItem: updated.item });\n } catch (error) {\n if (error instanceof WorkItemRelationError) {\n return c.json({ error: error.code, message: error.message }, 400);\n }\n throw error;\n }\n },\n }),\n\n // ── Remove a work item ───────────────────────────────────────────────────\n registerApiRoute('/web/factory/work-items/:id', {\n method: 'DELETE',\n requiresAuth: false,\n handler: async c => {\n const tenant = await this.#resolveTenant(loose(c));\n if ('response' in tenant) return tenant.response;\n\n const id = loose(c).req.param('id');\n if (!id || !UUID_RE.test(id)) return c.json({ error: 'Work item not found' }, 404);\n\n await workItems.ensureReady();\n const deleted = await workItems.delete({ orgId: tenant.orgId, id });\n if (!deleted) return c.json({ error: 'Work item not found' }, 404);\n await audit.emit({\n context: loose(c),\n input: {\n action: 'factory.work_item.deleted',\n factoryProjectId: deleted.factoryProjectId,\n targets: [{ type: 'work_item', id: deleted.id, name: deleted.title }],\n },\n });\n return c.json({ ok: true });\n },\n }),\n ];\n }\n}\n","import type { MastraCodeState } from '@mastra/code-sdk/schema';\nimport type { AgentController } from '@mastra/core/agent-controller';\nimport { RequestContext } from '@mastra/core/request-context';\nimport { formatSkillActivation } from '@mastra/core/workspace';\n\nimport type { SourceControlSession, SourceControlStorageHandle } from '../storage/domains/source-control/base.js';\nimport type { CreateWorkItemInput, WorkItemsStorage } from '../storage/domains/work-items/base.js';\nimport type { FactoryTransitionService } from './transition-service.js';\nimport type { FactoryRuleStage, FactoryTransitionResult } from './types.js';\n\nexport interface FactoryStartRequest {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n sessionId: string;\n threadTitle: string;\n threadTags?: Record<string, string>;\n kickoffKey: string;\n invocation?: { type: 'prompt'; prompt: string } | { type: 'skill'; skillName: string; arguments: string };\n destinationStage: FactoryRuleStage;\n workItem: {\n id?: string;\n role: string;\n input: CreateWorkItemInput;\n };\n requestContext?: RequestContext;\n}\n\nexport class FactoryStartTransitionError extends Error {\n readonly result: Extract<FactoryTransitionResult, { status: 'rejected' }>;\n\n constructor(result: Extract<FactoryTransitionResult, { status: 'rejected' }>) {\n super(result.reason);\n this.name = 'FactoryStartTransitionError';\n this.result = result;\n }\n}\n\nexport interface FactoryStartPreparedResult {\n workItemId: string;\n bindingId: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n branch: string;\n revision: number;\n kickoffStatus: 'pending' | 'leased' | 'retry' | 'sent' | 'failed';\n replayed: boolean;\n}\n\ntype FactoryController = AgentController<MastraCodeState>;\ntype FactorySession = Awaited<ReturnType<FactoryController['createSession']>>;\n\nfunction escapeSkillBoundary(value: string): string {\n return value.replaceAll('</skill>', '</skill>');\n}\n\nasync function resolveKickoffMessage(\n session: FactorySession,\n invocation: FactoryStartRequest['invocation'],\n): Promise<string | null> {\n if (!invocation) return null;\n if (invocation.type === 'prompt') return invocation.prompt;\n\n const skills = session.getWorkspace().skills;\n await skills?.maybeRefresh();\n const skill = await skills?.get(invocation.skillName);\n if (!skill || skill['user-invocable'] === false) {\n throw new Error(`Skill not found: ${invocation.skillName}.`);\n }\n const args = invocation.arguments.trim();\n const content = `${formatSkillActivation(skill)}${args ? `\\n\\nARGUMENTS: ${args}` : ''}`.trim();\n return `<skill name=\"${skill.name}\">\\n${escapeSkillBoundary(content)}\\n</skill>`;\n}\n\nasync function resolveSourceSession(\n storage: SourceControlStorageHandle,\n request: FactoryStartRequest,\n): Promise<SourceControlSession> {\n const session = await storage.sessions.getBySessionId(request.sessionId);\n if (!session || session.orgId !== request.orgId || session.userId !== request.userId) {\n throw new Error('Factory session not found');\n }\n const projectRepository = await storage.projectRepositories.get({\n orgId: request.orgId,\n id: session.projectRepositoryId,\n });\n if (!projectRepository) throw new Error('Factory session repository not found');\n const connection = await storage.connections.get({ orgId: request.orgId, id: projectRepository.connectionId });\n if (!connection || connection.factoryProjectId !== request.factoryProjectId) {\n throw new Error('Factory session does not belong to this project');\n }\n return session;\n}\n\nasync function configureThread(session: FactorySession, request: FactoryStartRequest): Promise<string> {\n const threadId = session.thread.requireId();\n await session.thread.rename({ title: request.threadTitle });\n const settings = { ...(request.threadTags ?? {}), factorySessionId: request.sessionId };\n await Promise.all(Object.entries(settings).map(([key, value]) => session.thread.setSetting({ key, value })));\n return threadId;\n}\n\nexport class FactoryStartCoordinator {\n readonly #controller: FactoryController;\n readonly #storage: WorkItemsStorage;\n readonly #transitionService?: Pick<FactoryTransitionService, 'transition'>;\n readonly #sourceControl?: SourceControlStorageHandle;\n\n constructor(\n controller: FactoryController,\n storage: WorkItemsStorage,\n transitionService?: Pick<FactoryTransitionService, 'transition'>,\n sourceControl?: SourceControlStorageHandle,\n ) {\n this.#controller = controller;\n this.#storage = storage;\n this.#transitionService = transitionService;\n this.#sourceControl = sourceControl;\n }\n\n async prepare(request: FactoryStartRequest): Promise<FactoryStartPreparedResult> {\n const storage = this.#storage;\n if (!this.#sourceControl) throw new Error('Factory source control storage is unavailable');\n const sourceSession = await resolveSourceSession(this.#sourceControl, request);\n const requestContext = request.requestContext ?? new RequestContext();\n if (!request.requestContext) {\n requestContext.set('user', { workosId: request.userId, organizationId: request.orgId });\n }\n const sessionState = {\n factoryProjectId: request.factoryProjectId,\n projectRepositoryId: sourceSession.projectRepositoryId,\n };\n const session = await this.#controller.createSession({\n id: sourceSession.sessionId,\n ownerId: request.userId,\n resourceId: sourceSession.sessionId,\n threadId: sourceSession.sessionId,\n requestContext,\n tags: sessionState,\n });\n // Bound-agent authority gates (the transition tool, the factory-phase\n // processor, workspace token selection) resolve the session address from\n // controller state. Seed it server-side — `tags` covers fresh creation,\n // the explicit setState covers get-or-create returning a session another\n // caller created without them — so autonomous runs never depend on a\n // browser connecting to populate the state.\n await session.state.set(sessionState);\n const threadId = await configureThread(session, request);\n const kickoffMessage = await resolveKickoffMessage(session, request.invocation);\n const prepared = await storage.prepareRunStart({\n orgId: request.orgId,\n userId: request.userId,\n factoryProjectId: request.factoryProjectId,\n workItem: { id: request.workItem.id, input: request.workItem.input },\n role: request.workItem.role,\n session: { sessionId: sourceSession.sessionId, branch: sourceSession.branch, threadId },\n resourceId: sourceSession.sessionId,\n kickoffKey: request.kickoffKey,\n kickoffMessage,\n });\n await session.thread.setSetting({ key: 'factoryWorkItemId', value: prepared.item.id });\n\n let revision = prepared.item.revision;\n if (prepared.item.stages.length !== 1 || prepared.item.stages[0] !== request.destinationStage) {\n if (!this.#transitionService) throw new Error('Factory transition service is unavailable.');\n const transition = await this.#transitionService.transition({\n orgId: request.orgId,\n factoryProjectId: request.factoryProjectId,\n workItemId: prepared.item.id,\n board: prepared.item.externalSource?.type === 'pull-request' ? 'review' : 'work',\n stage: request.destinationStage,\n expectedRevision: prepared.item.revision,\n actor: { type: 'human', id: request.userId },\n ingress: { type: 'human', identity: `start:${request.kickoffKey}:transition` },\n cause: 'run_start',\n });\n if (transition.status === 'rejected') {\n await storage.markPendingStart(prepared.binding.id, 'failed', transition.reason);\n throw new FactoryStartTransitionError(transition);\n }\n revision = transition.revision;\n }\n\n if (kickoffMessage === null) {\n await storage.markPendingStart(prepared.binding.id, 'sent');\n prepared.pendingStart.status = 'sent';\n }\n\n return {\n workItemId: prepared.item.id,\n bindingId: prepared.binding.id,\n threadId,\n resourceId: sourceSession.sessionId,\n sessionId: sourceSession.sessionId,\n branch: sourceSession.branch,\n revision,\n kickoffStatus: prepared.pendingStart.status,\n replayed: prepared.replayed,\n };\n }\n}\n","export type WorkItemSource = 'github-issue' | 'github-pr' | 'linear-issue' | 'manual';\n\nexport const FACTORY_RULE_STAGES = ['intake', 'triage', 'planning', 'execute', 'review', 'done', 'canceled'] as const;\nexport type FactoryRuleStage = (typeof FACTORY_RULE_STAGES)[number];\n\nexport const FACTORY_RULE_BOARDS = ['work', 'review'] as const;\nexport type FactoryRuleBoard = (typeof FACTORY_RULE_BOARDS)[number];\n\nexport const FACTORY_RULE_SOURCES = ['issue', 'pullRequest', 'linearIssue', 'manual'] as const;\nexport type FactoryRuleSource = (typeof FACTORY_RULE_SOURCES)[number];\n\nexport const FACTORY_GITHUB_EVENTS = [\n 'issueOpened',\n 'pullRequestOpened',\n 'pullRequestUpdated',\n 'pullRequestReviewRequested',\n 'pullRequestMerged',\n] as const;\nexport type FactoryGithubEventName = (typeof FACTORY_GITHUB_EVENTS)[number];\n\nexport const FACTORY_LINEAR_EVENTS = ['issueObserved'] as const;\nexport type FactoryLinearEventName = (typeof FACTORY_LINEAR_EVENTS)[number];\n\nexport type FactoryRuleJsonValue =\n null | boolean | number | string | FactoryRuleJsonValue[] | { [key: string]: FactoryRuleJsonValue };\n\nexport interface FactoryRuleItemContext {\n id: string;\n source: WorkItemSource;\n sourceKey: string | null;\n parentWorkItemId: string | null;\n title: string;\n url: string | null;\n stages: readonly string[];\n}\n\nexport type FactoryRuleActor =\n | { type: 'human'; id: string }\n | { type: 'agent'; bindingId: string; role: string }\n | { type: 'github'; login: string; trusted: boolean; factoryAuthored: boolean }\n | { type: 'system'; id: string };\n\nexport interface FactoryRuleIngressIdentity {\n type: 'human' | 'agent' | 'toolResult' | 'github' | 'linear' | 'rule';\n id: string;\n}\n\nexport interface FactoryRuleCausalEntry {\n ingressId: string;\n decisionType: FactoryCommitDecision['type'];\n}\n\nexport interface FactoryRuleContextBase {\n tenant: { orgId: string; projectId: string };\n actor: FactoryRuleActor;\n ingress: FactoryRuleIngressIdentity;\n cause: string;\n causalChain: readonly FactoryRuleCausalEntry[];\n ruleSetVersion: string;\n}\n\nexport interface FactoryBoundRuleContext extends FactoryRuleContextBase {\n item: FactoryRuleItemContext;\n board: FactoryRuleBoard;\n itemRevision: number;\n}\n\nexport interface FactoryStageRuleContext extends FactoryBoundRuleContext {\n source: FactoryRuleSource;\n stage: FactoryRuleStage;\n fromStage: FactoryRuleStage;\n toStage: FactoryRuleStage;\n}\n\nexport interface FactoryToolResultRuleContext extends FactoryBoundRuleContext {\n toolName: string;\n threadId: string;\n assistantMessageId: string;\n toolCallId: string;\n result: {\n status: 'success' | 'error';\n value: FactoryRuleJsonValue;\n };\n}\n\nexport interface FactoryGithubRuleContext extends FactoryRuleContextBase {\n item?: FactoryRuleItemContext;\n board?: FactoryRuleBoard;\n itemRevision?: number;\n event: FactoryGithubEventName;\n deliveryId: string;\n factory: { createdAt: string };\n repository: { id: number; fullName: string };\n issue?: { number: number; title: string; url: string; createdAt?: string };\n pullRequest?: {\n number: number;\n title: string;\n url: string;\n createdAt?: string;\n state: 'open' | 'closed';\n merged: boolean;\n headBranch: string;\n baseBranch: string;\n };\n}\n\nexport interface FactoryLinearRuleContext extends FactoryRuleContextBase {\n item?: FactoryRuleItemContext;\n board?: FactoryRuleBoard;\n itemRevision?: number;\n event: FactoryLinearEventName;\n issue: {\n id: string;\n identifier: string;\n title: string;\n url: string;\n state: string;\n stateType: string;\n priorityLabel: string;\n assignee: string | null;\n team: string | null;\n labels: readonly string[];\n createdAt: string;\n updatedAt: string;\n };\n}\n\nexport type FactoryRuleHandler<TContext> = (\n context: Readonly<TContext>,\n) => FactoryRuleDecision | void | Promise<FactoryRuleDecision | void>;\n\nexport interface FactoryBoardRuleLeaf {\n onEnter?: FactoryRuleHandler<FactoryStageRuleContext>;\n onExit?: FactoryRuleHandler<FactoryStageRuleContext>;\n}\n\nexport interface FactoryToolRuleLeaf {\n onResult?: FactoryRuleHandler<FactoryToolResultRuleContext>;\n}\n\nexport interface FactoryGithubRuleLeaf {\n onEvent?: FactoryRuleHandler<FactoryGithubRuleContext>;\n}\n\nexport interface FactoryLinearRuleLeaf {\n onEvent?: FactoryRuleHandler<FactoryLinearRuleContext>;\n}\n\nexport type FactoryBoardRules = Partial<\n Record<FactoryRuleStage, Partial<Record<FactoryRuleSource, FactoryBoardRuleLeaf>>>\n>;\n\nexport interface FactoryRules {\n version: string;\n work: FactoryBoardRules;\n review: FactoryBoardRules;\n tools: Record<string, FactoryToolRuleLeaf>;\n github: Partial<Record<FactoryGithubEventName, FactoryGithubRuleLeaf>>;\n linear: Partial<Record<FactoryLinearEventName, FactoryLinearRuleLeaf>>;\n}\n\nexport interface FactoryRulesOverrides {\n work?: FactoryBoardRules;\n review?: FactoryBoardRules;\n tools?: Record<string, FactoryToolRuleLeaf>;\n github?: Partial<Record<FactoryGithubEventName, FactoryGithubRuleLeaf>>;\n linear?: Partial<Record<FactoryLinearEventName, FactoryLinearRuleLeaf>>;\n}\n\nexport type FactoryRuleRejectionCode =\n | 'forbidden'\n | 'invalid_transition'\n | 'missing_binding'\n | 'stale'\n | 'timeout'\n | 'rule_error'\n | 'causal_depth_exceeded'\n | 'repeated_transition';\n\nexport interface FactoryRuleRejectDecision {\n type: 'reject';\n code: FactoryRuleRejectionCode;\n reason: string;\n}\n\ninterface FactoryCommitDecisionBase {\n idempotencyKey: string;\n}\n\nexport interface FactoryTransitionDecision extends FactoryCommitDecisionBase {\n type: 'transition';\n board: FactoryRuleBoard;\n stage: FactoryRuleStage;\n}\n\nexport interface FactoryUpsertLinkedWorkItemDecision extends FactoryCommitDecisionBase {\n type: 'upsertLinkedWorkItem';\n board: FactoryRuleBoard;\n source: WorkItemSource;\n sourceKey: string;\n title: string;\n url: string | null;\n stage: FactoryRuleStage;\n metadata?: Record<string, FactoryRuleJsonValue>;\n}\n\nexport interface FactoryInvokeSkillDecision extends FactoryCommitDecisionBase {\n type: 'invokeSkill';\n role: string;\n skillName: string;\n arguments?: string;\n precedingMessage?: string;\n}\n\nexport interface FactorySendMessageDecision extends FactoryCommitDecisionBase {\n type: 'sendMessage';\n role: string;\n message: string;\n priority?: 'medium' | 'high' | 'urgent';\n idleBehavior?: 'persist' | 'wake';\n prepareBinding?: boolean;\n}\n\nexport interface FactoryNotifyDecision extends FactoryCommitDecisionBase {\n type: 'notify';\n title: string;\n body?: string;\n level?: 'info' | 'warning' | 'error';\n}\n\nexport type FactoryCommitDecision =\n | FactoryTransitionDecision\n | FactoryUpsertLinkedWorkItemDecision\n | FactoryInvokeSkillDecision\n | FactorySendMessageDecision\n | FactoryNotifyDecision;\n\nexport type FactoryRuleDecision = FactoryRuleRejectDecision | FactoryCommitDecision;\n\nexport interface FactoryTransitionResultAccepted {\n status: 'accepted';\n transitionId: string;\n itemId: string;\n revision: number;\n stage: FactoryRuleStage;\n decisions: FactoryCommitDecision[];\n}\n\nexport interface FactoryTransitionResultRejected {\n status: 'rejected';\n transitionId: string;\n itemId: string;\n code: FactoryRuleRejectionCode;\n reason: string;\n}\n\nexport type FactoryTransitionResult = FactoryTransitionResultAccepted | FactoryTransitionResultRejected;\n\nexport function factoryRuleSourceForWorkItem(source: WorkItemSource): FactoryRuleSource {\n switch (source) {\n case 'github-issue':\n return 'issue';\n case 'github-pr':\n return 'pullRequest';\n case 'linear-issue':\n return 'linearIssue';\n case 'manual':\n return 'manual';\n }\n}\n","/**\n * Queue-health threshold configuration domain: per-project age buckets for the\n * Factory Overview queue-health chart.\n *\n * Stored per `(org, github_project)` — each connected GitHub project gets its\n * own age thresholds so a fast-moving automated pipeline and a slow human one\n * can bucket \"how old is the work\" differently. `thresholdsSeconds` is an\n * ordered-ascending list of age boundaries in seconds: an item younger than\n * the first boundary is green, younger than the second amber, younger than the\n * third orange, and red otherwise. Seconds (not hours) so sub-minute buckets\n * are representable for fast automated flows.\n */\n\nimport { FactoryStorageDomain, UniqueViolationError } from '@mastra/core/storage';\nimport type { CollectionSchema, FactoryStorageOps } from '@mastra/core/storage';\n\nexport interface QueueHealthConfig {\n /** Ordered-ascending age boundaries in seconds, e.g. `[14400, 86400, 259200]`. */\n thresholdsSeconds: number[];\n}\n\n/** Default: green <4h, amber <24h, orange <72h, red 72h+. */\nexport const DEFAULT_QUEUE_HEALTH_CONFIG: QueueHealthConfig = {\n thresholdsSeconds: [14400, 86400, 259200],\n};\n\n/**\n * Throw unless `thresholdsSeconds` is a non-empty ascending number list. A\n * descending config would silently invert bucket semantics, so validate at the\n * write boundary rather than trusting callers.\n */\nexport function assertValidThresholds(config: QueueHealthConfig): void {\n const t = config.thresholdsSeconds;\n if (!Array.isArray(t) || t.length === 0 || t.some(v => typeof v !== 'number' || !Number.isFinite(v))) {\n throw new Error('[QueueHealthStorage] thresholdsSeconds must be a non-empty array of finite numbers.');\n }\n for (let i = 1; i < t.length; i++) {\n if (t[i]! <= t[i - 1]!) {\n throw new Error('[QueueHealthStorage] thresholdsSeconds must be strictly ascending.');\n }\n }\n}\n\n/** Validate untrusted JSON into a `QueueHealthConfig`, or `null` when invalid. */\nexport function parseQueueHealthConfig(body: unknown): QueueHealthConfig | null {\n if (typeof body !== 'object' || body === null) return null;\n const config = body as { thresholdsSeconds?: unknown };\n if (!Array.isArray(config.thresholdsSeconds)) return null;\n try {\n assertValidThresholds(config as QueueHealthConfig);\n } catch {\n return null;\n }\n return { thresholdsSeconds: [...(config as QueueHealthConfig).thresholdsSeconds] };\n}\n\n/**\n * Return `config.thresholdsSeconds` when valid, else the default. Validation\n * lives at the `saveConfig` write boundary, but `getConfig` round-trips a\n * stored JSON row — a corrupted or hand-edited row (empty / non-ascending)\n * would otherwise reach the chart and invert bucket colors, so the read route\n * re-validates and falls back.\n */\nexport function thresholdsOrDefault(config: QueueHealthConfig): number[] {\n return parseQueueHealthConfig(config)?.thresholdsSeconds ?? DEFAULT_QUEUE_HEALTH_CONFIG.thresholdsSeconds;\n}\n\nexport const QUEUE_HEALTH_SETTINGS_SCHEMA: CollectionSchema = {\n name: 'queue_health_settings',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n config: { type: 'json' },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [{ name: 'queue_health_settings_org_project_unique', columns: ['org_id', 'factory_project_id'] }],\n};\n\n/**\n * Queue-health settings storage, written once against the generic\n * `FactoryStorageOps` surface — works on any `FactoryStorage` backend.\n */\nexport class QueueHealthStorage extends FactoryStorageDomain {\n constructor() {\n super('queue-health');\n }\n\n async init(): Promise<void> {\n await this.ensureCollections([QUEUE_HEALTH_SETTINGS_SCHEMA]);\n }\n\n async dangerouslyClearAll(): Promise<void> {\n await this.ops.deleteMany('queue_health_settings', {});\n }\n\n get #db(): FactoryStorageOps {\n return this.ops;\n }\n\n /** Read the project's queue-health config, falling back to {@link DEFAULT_QUEUE_HEALTH_CONFIG}. */\n async getConfig(orgId: string, factoryProjectId: string): Promise<QueueHealthConfig> {\n const row = await this.#db.findOne<{ config: unknown }>('queue_health_settings', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n });\n return structuredClone(parseQueueHealthConfig(row?.config) ?? DEFAULT_QUEUE_HEALTH_CONFIG);\n }\n\n /** Upsert the project's queue-health config (`created_at` is preserved on update). */\n async saveConfig(orgId: string, factoryProjectId: string, config: QueueHealthConfig): Promise<void> {\n assertValidThresholds(config);\n const where = { org_id: orgId, factory_project_id: factoryProjectId };\n const updateExisting = () =>\n this.#db.updateAtomic('queue_health_settings', where, () => ({ config, updated_at: new Date() }));\n if (await updateExisting()) return;\n\n const now = new Date();\n try {\n await this.#db.insertOne('queue_health_settings', { ...where, config, created_at: now, updated_at: now });\n } catch (error) {\n if (!(error instanceof UniqueViolationError)) throw error;\n // Lost the insert race — update the winning row under the backend's serialized write primitive.\n if (!(await updateExisting())) throw error;\n }\n }\n}\n","/**\n * Factory work-items storage domain.\n *\n * Work items belong to a first-class Factory project. External intake items use\n * a provider-neutral source reference; manual work items have no source.\n * Stage history is server-owned, while session and metadata patches merge\n * atomically so concurrent actors do not overwrite each other. The authoritative\n * Factory transition path keeps one exclusive current stage per item.\n */\n\nimport { createHash } from 'node:crypto';\n\nimport { FactoryStorageDomain, UniqueViolationError } from '@mastra/core/storage';\nimport type { CollectionSchema, FactoryStorageOps } from '@mastra/core/storage';\n\nexport type WorkItemStage = string;\n\nfunction stableJson(value: unknown): string {\n if (Array.isArray(value)) return `[${value.map(stableJson).join(',')}]`;\n if (value && typeof value === 'object') {\n return `{${Object.entries(value as Record<string, unknown>)\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`)\n .join(',')}}`;\n }\n return JSON.stringify(value) ?? 'null';\n}\n\nexport function factoryDecisionHash(decision: Record<string, unknown>): string {\n return createHash('sha256').update(stableJson(decision)).digest('hex');\n}\n\nexport interface ExternalWorkItemSource {\n integrationId: string;\n type: string;\n externalId: string;\n url?: string;\n}\n\nexport interface WorkItemStageEntry {\n stage: WorkItemStage;\n enteredAt: string;\n exitedAt?: string;\n by: string;\n /**\n * Actor that closed this entry; absent on entries written before exit\n * stamping existed — treat as human.\n */\n exitedBy?: string;\n}\n\n/**\n * Sentinel actor ids that mark a stage transition as automation-driven (vs a\n * human's WorkOS user id): generic sentinels plus the system ids the Factory\n * rules engine stamps (see `actorId` in factory/rules/transition-service.ts).\n * Metrics treat any other actor — including a missing `exitedBy` on\n * pre-existing entries — as human.\n */\nexport const AUTOMATION_ACTORS = new Set([\n 'factory',\n 'system',\n 'automation',\n 'factory-rule-dispatcher',\n 'factory-tool-result-rule',\n]);\n\n/**\n * Whether an actor id marks a transition no human performed on the Factory\n * board: a sentinel automation id, an agent binding (`agent:*`), or an\n * external-webhook actor (`github:*` — a human may have acted on GitHub, but\n * the board move itself was automated).\n */\nexport function isAutomationActor(by: string | undefined): boolean {\n if (by === undefined) return false;\n return AUTOMATION_ACTORS.has(by) || by.startsWith('agent:') || by.startsWith('github:');\n}\n\nexport interface WorkItemSessionRef {\n sessionId: string;\n branch: string;\n threadId: string;\n startedBy: string;\n}\n\nexport interface FactoryRuleIngressRecord {\n id: string;\n orgId: string;\n factoryProjectId: string;\n identity: string;\n triggerType: string;\n transitionId: string;\n result: Record<string, unknown>;\n createdAt: Date;\n}\n\nexport interface CommitFactoryRuleEvaluationInput {\n orgId: string;\n factoryProjectId: string;\n workItemId: string | null;\n ingress: { identity: string; triggerType: string };\n ruleSetVersion: string;\n expectedRevision: number | null;\n actor: Record<string, unknown> | null;\n outcome: { status: 'accepted' | 'rejected'; code?: string; reason?: string };\n decisions: Record<string, unknown>[];\n causalChain: Array<{ ingressId: string; decisionType: string }>;\n now: Date;\n}\n\nexport type CommitFactoryRuleEvaluationResult =\n | { status: 'committed'; result: Record<string, unknown> }\n | { status: 'replayed'; result: Record<string, unknown> }\n | { status: 'missing' };\n\nexport interface FactoryToolResultCursorRecord {\n bindingId: string;\n orgId: string;\n factoryProjectId: string;\n lastMessageId: string;\n lastMessageCreatedAt: Date;\n updatedAt: Date;\n}\n\nexport interface FactoryRuleEvaluationRecord {\n id: string;\n ingressId: string;\n workItemId: string | null;\n ruleSetVersion: string;\n expectedRevision: number | null;\n outcome: 'accepted' | 'rejected';\n code: string | null;\n reason: string | null;\n causalChain: Array<{ ingressId: string; decisionType: string }>;\n createdAt: Date;\n}\n\nexport type FactoryDispatchStatus = 'pending' | 'leased' | 'retry' | 'succeeded' | 'failed';\n\nexport interface FactoryDeferredDecisionPageInput {\n orgId: string;\n factoryProjectId: string;\n statuses?: FactoryDispatchStatus[];\n before?: { createdAt: Date; id: string };\n limit: number;\n}\n\nexport interface FactoryDeferredDecisionPage {\n decisions: FactoryDeferredDecisionRecord[];\n hasMore: boolean;\n}\n\nexport interface FactoryDeferredDecisionRecord {\n id: string;\n orgId: string;\n factoryProjectId: string;\n evaluationId: string;\n workItemId: string | null;\n idempotencyKey: string;\n effectOrdinal: number;\n effectHash: string;\n causalChain: Array<{ ingressId: string; decisionType: string }>;\n actor: Record<string, unknown> | null;\n decision: Record<string, unknown>;\n status: FactoryDispatchStatus;\n attempts: number;\n availableAt: Date;\n leaseOwner: string | null;\n leaseExpiresAt: Date | null;\n lastError: string | null;\n completedAt: Date | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface FactoryRunBindingSessionAddress {\n factoryProjectId: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n}\n\nexport interface FactoryRunBindingAddress extends FactoryRunBindingSessionAddress {\n orgId: string;\n}\n\nexport interface RevokeFactoryRunBindingInput {\n orgId: string;\n factoryProjectId: string;\n bindingId: string;\n revokedAt: Date;\n}\n\nexport interface FactoryRunBindingRecord {\n id: string;\n orgId: string;\n factoryProjectId: string;\n workItemId: string;\n role: string;\n threadId: string;\n resourceId: string;\n sessionId: string;\n branch: string;\n status: 'active' | 'revoked';\n createdAt: Date;\n revokedAt: Date | null;\n}\n\nexport interface FactoryPendingStartRecord {\n id: string;\n orgId: string;\n factoryProjectId: string;\n bindingId: string;\n kickoffKey: string;\n message: string | null;\n status: 'pending' | 'leased' | 'retry' | 'sent' | 'failed';\n attempts: number;\n availableAt: Date;\n leaseOwner: string | null;\n leaseExpiresAt: Date | null;\n lastError: string | null;\n completedAt: Date | null;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface FactoryLeaseClaimInput {\n ownerId: string;\n now: Date;\n leaseExpiresAt: Date;\n limit: number;\n}\n\nexport interface FactoryLeaseIdentity {\n id: string;\n orgId: string;\n factoryProjectId: string;\n ownerId: string;\n}\n\nexport interface FactoryDispatchFailureInput extends FactoryLeaseIdentity {\n now: Date;\n availableAt: Date;\n lastError: string;\n terminal: boolean;\n}\n\nexport interface CommitFactoryTransitionInput {\n orgId: string;\n factoryProjectId: string;\n workItemId: string;\n expectedRevision: number;\n destinationStage: string;\n actorId: string;\n ingress: { identity: string; triggerType: string; transitionId: string };\n ruleSetVersion: string;\n causalChain: Array<{ ingressId: string; decisionType: string }>;\n evaluation:\n | { outcome: 'accepted'; decisions: Record<string, unknown>[] }\n | { outcome: 'rejected'; code: string; reason: string };\n}\n\nexport type CommitFactoryTransitionResult =\n | { status: 'committed'; item: WorkItemRow | null; result: Record<string, unknown> }\n | { status: 'replayed'; item: WorkItemRow | null; result: Record<string, unknown> }\n | { status: 'missing' };\n\nexport interface PrepareFactoryRunStartInput {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n workItem: { id?: string; input: CreateWorkItemInput };\n role: string;\n session: WorkItemSessionInput;\n resourceId: string;\n kickoffKey: string;\n kickoffMessage: string | null;\n}\n\nexport interface PrepareFactoryRunStartResult {\n item: WorkItemRow;\n binding: FactoryRunBindingRecord;\n pendingStart: FactoryPendingStartRecord;\n replayed: boolean;\n}\n\n/** Session ref as accepted from clients — `startedBy` is stamped server-side. */\nexport interface WorkItemSessionInput {\n sessionId: string;\n branch: string;\n threadId: string;\n}\n\nexport type WorkItemSessions = Record<string, WorkItemSessionRef>;\n\nexport interface WorkItemRow {\n id: string;\n orgId: string;\n factoryProjectId: string;\n externalSource: ExternalWorkItemSource | null;\n parentWorkItemId: string | null;\n title: string;\n stages: WorkItemStage[];\n stageHistory: WorkItemStageEntry[];\n sessions: WorkItemSessions;\n metadata: Record<string, unknown> | null;\n revision: number;\n createdBy: string;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface CreateWorkItemInput {\n externalSource?: ExternalWorkItemSource | null;\n parentWorkItemId?: string | null;\n title: string;\n stages?: WorkItemStage[];\n sessions?: Record<string, WorkItemSessionInput>;\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface UpdateWorkItemInput {\n parentWorkItemId?: string | null;\n title?: string;\n stages?: WorkItemStage[];\n sessions?: Record<string, WorkItemSessionInput>;\n metadata?: Record<string, unknown> | null;\n}\n\nexport interface WorkItemPriorState {\n stages: WorkItemStage[];\n sessionRoles: string[];\n}\n\nexport interface UpsertWorkItemResult {\n item: WorkItemRow;\n created: boolean;\n previous: WorkItemPriorState;\n}\n\nexport const WORK_ITEMS_SCHEMA: CollectionSchema = {\n name: 'work_items',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n external_source: { type: 'json', nullable: true },\n source_key: { type: 'text', nullable: true },\n parent_work_item_id: { type: 'text', nullable: true },\n title: { type: 'text' },\n stages: { type: 'json' },\n stage_history: { type: 'json' },\n sessions: { type: 'json' },\n metadata: { type: 'json', nullable: true },\n revision: { type: 'integer', default: 1 },\n created_by: { type: 'text' },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n {\n name: 'work_items_project_source_key_unique',\n columns: ['factory_project_id', 'source_key'],\n },\n ],\n indexes: [\n {\n name: 'work_items_org_project_updated_at_idx',\n columns: ['org_id', 'factory_project_id', 'updated_at'],\n },\n {\n name: 'work_items_project_parent_idx',\n columns: ['org_id', 'factory_project_id', 'parent_work_item_id'],\n },\n ],\n};\n\ninterface WorkItemDbRow extends Record<string, unknown> {\n id: string;\n org_id: string;\n factory_project_id: string;\n external_source: ExternalWorkItemSource | null;\n source_key: string | null;\n parent_work_item_id: string | null;\n title: string;\n stages: WorkItemStage[];\n stage_history: WorkItemStageEntry[];\n sessions: WorkItemSessions;\n metadata: Record<string, unknown> | null;\n revision: number;\n created_by: string;\n created_at: Date;\n updated_at: Date;\n}\n\nfunction sourceKey(source: ExternalWorkItemSource | null | undefined): string | null {\n return source ? `${source.integrationId}:${source.type}:${source.externalId}` : null;\n}\n\nfunction toWorkItem(row: WorkItemDbRow): WorkItemRow {\n return {\n id: row.id,\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n externalSource: row.external_source,\n parentWorkItemId: row.parent_work_item_id,\n title: row.title,\n stages: row.stages,\n stageHistory: row.stage_history,\n sessions: row.sessions,\n metadata: row.metadata,\n revision: row.revision,\n createdBy: row.created_by,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n}\n\nconst toRow = toWorkItem;\n\nfunction patchColumns(changes: Partial<WorkItemRow>): Partial<WorkItemDbRow> {\n return {\n ...(changes.parentWorkItemId !== undefined ? { parent_work_item_id: changes.parentWorkItemId } : {}),\n ...(changes.title !== undefined ? { title: changes.title } : {}),\n ...(changes.stages !== undefined ? { stages: changes.stages } : {}),\n ...(changes.stageHistory !== undefined ? { stage_history: changes.stageHistory } : {}),\n ...(changes.sessions !== undefined ? { sessions: changes.sessions } : {}),\n ...(changes.metadata !== undefined ? { metadata: changes.metadata } : {}),\n ...(changes.revision !== undefined ? { revision: changes.revision } : {}),\n ...(changes.updatedAt !== undefined ? { updated_at: changes.updatedAt } : {}),\n };\n}\n\nfunction emptyPrior(): WorkItemPriorState {\n return { stages: [], sessionRoles: [] };\n}\n\nfunction priorState(row: WorkItemDbRow): WorkItemPriorState {\n return { stages: row.stages, sessionRoles: Object.keys(row.sessions) };\n}\n\nexport class WorkItemRelationError extends Error {\n readonly code = 'invalid_work_item_relation';\n}\n\nexport function validateParentRelation(\n projectItems: WorkItemRow[],\n itemId: string | undefined,\n parentWorkItemId: string | null,\n): void {\n if (parentWorkItemId === null) return;\n const byId = new Map(projectItems.map(item => [item.id, item]));\n const parent = byId.get(parentWorkItemId);\n if (!parent) throw new WorkItemRelationError('Related work item not found in this project.');\n if (itemId === parentWorkItemId) throw new WorkItemRelationError('A work item cannot relate to itself.');\n\n const visited = new Set<string>();\n let cursor: WorkItemRow | undefined = parent;\n while (cursor?.parentWorkItemId) {\n if (cursor.parentWorkItemId === itemId) {\n throw new WorkItemRelationError('This relationship would create a cycle.');\n }\n if (visited.has(cursor.id)) throw new WorkItemRelationError('The related work item chain contains a cycle.');\n visited.add(cursor.id);\n cursor = byId.get(cursor.parentWorkItemId);\n }\n}\n\n/**\n * Diff `oldStages` → `newStages` and return the updated history: exited stages\n * get `exitedAt` + `exitedBy` stamped on their open entry, entered stages get\n * a new entry.\n */\nexport function applyStageTransition(\n history: WorkItemStageEntry[],\n oldStages: WorkItemStage[],\n newStages: WorkItemStage[],\n by: string,\n now: Date,\n): WorkItemStageEntry[] {\n const timestamp = now.toISOString();\n const next = history.map(entry => ({ ...entry }));\n for (const stage of oldStages) {\n if (newStages.includes(stage)) continue;\n for (let i = next.length - 1; i >= 0; i--) {\n const entry = next[i]!;\n if (entry.stage === stage && entry.exitedAt === undefined) {\n entry.exitedAt = timestamp;\n entry.exitedBy = by;\n break;\n }\n }\n }\n for (const stage of newStages) {\n if (!oldStages.includes(stage)) next.push({ stage, enteredAt: timestamp, by });\n }\n return next;\n}\n\nexport function stampSessions(sessions: Record<string, WorkItemSessionInput>, by: string): WorkItemSessions {\n return Object.fromEntries(Object.entries(sessions).map(([role, session]) => [role, { ...session, startedBy: by }]));\n}\n\nfunction applyUpdate({\n current,\n userId,\n input,\n}: {\n current: WorkItemDbRow;\n userId: string;\n input: UpdateWorkItemInput;\n}): Partial<WorkItemDbRow> {\n const now = new Date();\n return {\n ...(input.parentWorkItemId !== undefined ? { parent_work_item_id: input.parentWorkItemId } : {}),\n ...(input.title !== undefined ? { title: input.title } : {}),\n ...(input.stages !== undefined\n ? {\n stages: input.stages,\n stage_history: applyStageTransition(current.stage_history, current.stages, input.stages, userId, now),\n }\n : {}),\n ...(input.sessions !== undefined\n ? { sessions: { ...current.sessions, ...stampSessions(input.sessions, userId) } }\n : {}),\n ...(input.metadata !== undefined\n ? { metadata: input.metadata === null ? null : { ...(current.metadata ?? {}), ...input.metadata } }\n : {}),\n revision: current.revision + 1,\n updated_at: now,\n };\n}\n\nconst projectRelationLocks = new Map<string, Promise<unknown>>();\n\nfunction withInProcessProjectLock<T>(key: string, fn: () => Promise<T>): Promise<T> {\n const previous = projectRelationLocks.get(key) ?? Promise.resolve();\n const result = previous.then(fn, fn);\n const tail = result.then(\n () => undefined,\n () => undefined,\n );\n projectRelationLocks.set(key, tail);\n void tail.then(() => {\n if (projectRelationLocks.get(key) === tail) projectRelationLocks.delete(key);\n });\n return result;\n}\n\nconst FACTORY_GOVERNANCE_SCHEMAS: CollectionSchema[] = [\n {\n name: 'factory_rule_ingress',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n identity: { type: 'text' },\n trigger_type: { type: 'text' },\n transition_id: { type: 'text' },\n result: { type: 'json' },\n created_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n { name: 'factory_rule_ingress_tenant_identity_unique', columns: ['org_id', 'factory_project_id', 'identity'] },\n ],\n },\n {\n name: 'factory_rule_evaluations',\n columns: {\n id: { type: 'uuid-pk' },\n ingress_id: { type: 'text' },\n work_item_id: { type: 'text', nullable: true },\n rule_set_version: { type: 'text' },\n expected_revision: { type: 'integer', nullable: true },\n outcome: { type: 'text' },\n code: { type: 'text', nullable: true },\n reason: { type: 'text', nullable: true },\n causal_chain: { type: 'json' },\n created_at: { type: 'timestamp' },\n },\n },\n {\n name: 'factory_deferred_decisions',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n evaluation_id: { type: 'text' },\n work_item_id: { type: 'text', nullable: true },\n idempotency_key: { type: 'text' },\n effect_ordinal: { type: 'integer' },\n effect_hash: { type: 'text' },\n causal_chain: { type: 'json' },\n actor: { type: 'json', nullable: true },\n decision: { type: 'json' },\n status: { type: 'text' },\n attempts: { type: 'integer' },\n available_at: { type: 'timestamp' },\n lease_owner: { type: 'text', nullable: true },\n lease_expires_at: { type: 'timestamp', nullable: true },\n last_error: { type: 'text', nullable: true },\n completed_at: { type: 'timestamp', nullable: true },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n {\n name: 'factory_deferred_decisions_tenant_key_unique',\n columns: ['org_id', 'factory_project_id', 'idempotency_key'],\n },\n ],\n },\n {\n name: 'factory_run_bindings',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n work_item_id: { type: 'text' },\n role: { type: 'text' },\n thread_id: { type: 'text' },\n resource_id: { type: 'text' },\n session_id: { type: 'text' },\n branch: { type: 'text' },\n status: { type: 'text' },\n created_at: { type: 'timestamp' },\n revoked_at: { type: 'timestamp', nullable: true },\n },\n },\n {\n name: 'factory_tool_result_cursors',\n columns: {\n binding_id: { type: 'text', primaryKey: true },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n last_message_id: { type: 'text' },\n last_message_created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n },\n {\n name: 'factory_pending_starts',\n columns: {\n id: { type: 'uuid-pk' },\n org_id: { type: 'text' },\n factory_project_id: { type: 'text' },\n binding_id: { type: 'text' },\n kickoff_key: { type: 'text' },\n message: { type: 'text', nullable: true },\n status: { type: 'text' },\n attempts: { type: 'integer' },\n available_at: { type: 'timestamp' },\n lease_owner: { type: 'text', nullable: true },\n lease_expires_at: { type: 'timestamp', nullable: true },\n last_error: { type: 'text', nullable: true },\n completed_at: { type: 'timestamp', nullable: true },\n created_at: { type: 'timestamp' },\n updated_at: { type: 'timestamp' },\n },\n uniqueIndexes: [\n {\n name: 'factory_pending_starts_tenant_kickoff_unique',\n columns: ['org_id', 'factory_project_id', 'kickoff_key'],\n },\n ],\n },\n];\n\ninterface GovernanceDbRow extends Record<string, unknown> {\n id: string;\n org_id: string;\n factory_project_id: string;\n created_at: Date;\n [key: string]: unknown;\n}\n\nfunction toBinding(row: GovernanceDbRow): FactoryRunBindingRecord {\n return {\n id: row.id,\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n workItemId: String(row.work_item_id),\n role: String(row.role),\n threadId: String(row.thread_id),\n resourceId: String(row.resource_id),\n sessionId: String(row.session_id),\n branch: String(row.branch),\n status: row.status as FactoryRunBindingRecord['status'],\n createdAt: row.created_at,\n revokedAt: (row.revoked_at as Date | null) ?? null,\n };\n}\nfunction toDeferredDecision(row: GovernanceDbRow): FactoryDeferredDecisionRecord {\n return {\n id: row.id,\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n evaluationId: String(row.evaluation_id),\n workItemId: row.work_item_id === null || row.work_item_id === undefined ? null : String(row.work_item_id),\n idempotencyKey: String(row.idempotency_key),\n effectOrdinal: Number(row.effect_ordinal),\n effectHash: String(row.effect_hash),\n causalChain: (row.causal_chain as FactoryDeferredDecisionRecord['causalChain']) ?? [],\n actor: (row.actor as Record<string, unknown> | null) ?? null,\n decision: row.decision as Record<string, unknown>,\n status: row.status as FactoryDispatchStatus,\n attempts: Number(row.attempts),\n availableAt: row.available_at as Date,\n leaseOwner: (row.lease_owner as string | null) ?? null,\n leaseExpiresAt: (row.lease_expires_at as Date | null) ?? null,\n lastError: (row.last_error as string | null) ?? null,\n completedAt: (row.completed_at as Date | null) ?? null,\n createdAt: row.created_at,\n updatedAt: row.updated_at as Date,\n };\n}\nfunction toPendingStart(row: GovernanceDbRow): FactoryPendingStartRecord {\n return {\n id: row.id,\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n bindingId: String(row.binding_id),\n kickoffKey: String(row.kickoff_key),\n message: (row.message as string | null) ?? null,\n status: row.status as FactoryPendingStartRecord['status'],\n attempts: Number(row.attempts),\n availableAt: row.available_at as Date,\n leaseOwner: (row.lease_owner as string | null) ?? null,\n leaseExpiresAt: (row.lease_expires_at as Date | null) ?? null,\n lastError: (row.last_error as string | null) ?? null,\n completedAt: (row.completed_at as Date | null) ?? null,\n createdAt: row.created_at,\n updatedAt: row.updated_at as Date,\n };\n}\n\nexport class WorkItemsStorage extends FactoryStorageDomain {\n constructor() {\n super('work-items');\n }\n\n async init(): Promise<void> {\n await this.ensureCollections([WORK_ITEMS_SCHEMA, ...FACTORY_GOVERNANCE_SCHEMAS]);\n }\n\n async dangerouslyClearAll(): Promise<void> {\n await this.ops.deleteMany('work_items', {});\n }\n\n #leaseQueue: Promise<void> = Promise.resolve();\n\n get #db(): FactoryStorageOps {\n return this.ops;\n }\n\n async #withLocalLeaseLock<T>(fn: () => Promise<T>): Promise<T> {\n const prior = this.#leaseQueue;\n let release!: () => void;\n this.#leaseQueue = new Promise<void>(resolve => {\n release = resolve;\n });\n await prior;\n try {\n return await fn();\n } finally {\n release();\n }\n }\n\n async #withProjectRelationLock<T>(orgId: string, factoryProjectId: string, fn: () => Promise<T>): Promise<T> {\n const key = `work-items:${orgId}:${factoryProjectId}`;\n return withInProcessProjectLock(key, () =>\n this.storage.withDistributedLock ? this.storage.withDistributedLock(key, fn) : fn(),\n );\n }\n\n async #claimLeases<T>(\n table: 'factory_deferred_decisions' | 'factory_pending_starts',\n input: FactoryLeaseClaimInput,\n map: (row: GovernanceDbRow) => T,\n ): Promise<T[]> {\n const claim = () =>\n this.storage.withTransaction(async ops => {\n const candidates = await ops.findMany<GovernanceDbRow>(table, {}, { orderBy: [['created_at', 'asc']] });\n const claimed: T[] = [];\n for (const candidate of candidates) {\n if (claimed.length >= input.limit) break;\n const availableAt = new Date(candidate.available_at as Date | string).getTime();\n const leaseExpiresAt = candidate.lease_expires_at\n ? new Date(candidate.lease_expires_at as Date | string).getTime()\n : 0;\n const claimable =\n (candidate.status === 'pending' || candidate.status === 'retry') && availableAt <= input.now.getTime();\n const expired = candidate.status === 'leased' && leaseExpiresAt <= input.now.getTime();\n if (!claimable && !expired) continue;\n let didClaim = false;\n const row = await ops.updateAtomic<GovernanceDbRow>(table, { id: candidate.id }, current => {\n const currentAvailable = new Date(current.available_at as Date | string).getTime();\n const currentExpiry = current.lease_expires_at\n ? new Date(current.lease_expires_at as Date | string).getTime()\n : 0;\n const currentClaimable =\n (current.status === 'pending' || current.status === 'retry') && currentAvailable <= input.now.getTime();\n const currentExpired = current.status === 'leased' && currentExpiry <= input.now.getTime();\n if (!currentClaimable && !currentExpired) return null;\n didClaim = true;\n return {\n status: 'leased',\n attempts: Number(current.attempts) + 1,\n lease_owner: input.ownerId,\n lease_expires_at: input.leaseExpiresAt,\n updated_at: input.now,\n };\n });\n if (didClaim && row) claimed.push(map(row));\n }\n return claimed;\n });\n return this.storage.withDistributedLock\n ? this.storage.withDistributedLock(`factory-lease:${table}`, claim)\n : this.#withLocalLeaseLock(claim);\n }\n\n async #renewLease(\n table: 'factory_deferred_decisions' | 'factory_pending_starts',\n identity: FactoryLeaseIdentity,\n leaseExpiresAt: Date,\n ): Promise<boolean> {\n let renewed = false;\n await this.#db.updateAtomic<GovernanceDbRow>(\n table,\n { id: identity.id, org_id: identity.orgId, factory_project_id: identity.factoryProjectId },\n current => {\n if (current.status !== 'leased' || current.lease_owner !== identity.ownerId) return null;\n renewed = true;\n return { lease_expires_at: leaseExpiresAt, updated_at: new Date() };\n },\n );\n return renewed;\n }\n\n async #completeLease(\n table: 'factory_deferred_decisions' | 'factory_pending_starts',\n identity: FactoryLeaseIdentity,\n now: Date,\n ): Promise<GovernanceDbRow | null> {\n let completed = false;\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n table,\n { id: identity.id, org_id: identity.orgId, factory_project_id: identity.factoryProjectId },\n current => {\n if (current.status !== 'leased' || current.lease_owner !== identity.ownerId) return null;\n completed = true;\n return {\n status: table === 'factory_pending_starts' ? 'sent' : 'succeeded',\n lease_owner: null,\n lease_expires_at: null,\n completed_at: now,\n updated_at: now,\n };\n },\n );\n return completed ? row : null;\n }\n\n async #failLease(\n table: 'factory_deferred_decisions' | 'factory_pending_starts',\n input: FactoryDispatchFailureInput,\n ): Promise<GovernanceDbRow | null> {\n let failed = false;\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n table,\n { id: input.id, org_id: input.orgId, factory_project_id: input.factoryProjectId },\n current => {\n if (current.status !== 'leased' || current.lease_owner !== input.ownerId) return null;\n failed = true;\n return {\n status: input.terminal ? 'failed' : 'retry',\n available_at: input.availableAt,\n lease_owner: null,\n lease_expires_at: null,\n last_error: input.lastError,\n completed_at: input.terminal ? input.now : null,\n updated_at: input.now,\n };\n },\n );\n return failed ? row : null;\n }\n\n /** List the org's work items for a project, newest first. */\n async list({ orgId, factoryProjectId }: { orgId: string; factoryProjectId: string }): Promise<WorkItemRow[]> {\n const rows = await this.#db.findMany<WorkItemDbRow>(\n 'work_items',\n { org_id: orgId, factory_project_id: factoryProjectId },\n { orderBy: [['updated_at', 'desc']] },\n );\n return rows.map(toWorkItem);\n }\n\n async get({ orgId, id }: { orgId: string; id: string }): Promise<WorkItemRow | null> {\n const row = await this.#db.findOne<WorkItemDbRow>('work_items', { org_id: orgId, id });\n return row ? toWorkItem(row) : null;\n }\n\n async getForProject(orgId: string, factoryProjectId: string, id: string): Promise<WorkItemRow | null> {\n const row = await this.#db.findOne<WorkItemDbRow>('work_items', {\n id,\n org_id: orgId,\n factory_project_id: factoryProjectId,\n });\n return row ? toRow(row) : null;\n }\n\n async getTransitionResultByIngress(\n orgId: string,\n factoryProjectId: string,\n identity: string,\n ): Promise<Record<string, unknown> | null> {\n const row = await this.#db.findOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n identity,\n });\n return (row?.result as Record<string, unknown> | undefined) ?? null;\n }\n\n async commitTransition(input: CommitFactoryTransitionInput): Promise<CommitFactoryTransitionResult> {\n const commit = (): Promise<CommitFactoryTransitionResult> =>\n this.storage.withTransaction<CommitFactoryTransitionResult>(async ops => {\n const prior = await ops.findOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n identity: input.ingress.identity,\n });\n if (prior)\n return {\n status: 'replayed',\n item: await this.getForProject(input.orgId, input.factoryProjectId, input.workItemId),\n result: prior.result as Record<string, unknown>,\n };\n\n const now = new Date();\n let item: WorkItemRow | null = null;\n let code: string | null = null;\n let reason: string | null = null;\n let result: Record<string, unknown>;\n const updated = await ops.updateAtomic<WorkItemDbRow>(\n 'work_items',\n {\n id: input.workItemId,\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n },\n row => {\n const existing = toRow(row);\n item = existing;\n if (existing.revision !== input.expectedRevision) {\n code = 'stale';\n reason = 'The work item changed before this transition committed.';\n return null;\n }\n if (input.evaluation.outcome === 'rejected') {\n code = input.evaluation.code;\n reason = input.evaluation.reason;\n return null;\n }\n if (existing.stages.length === 1 && existing.stages[0] === input.destinationStage) return null;\n return patchColumns({\n stages: [input.destinationStage],\n stageHistory: applyStageTransition(\n existing.stageHistory,\n existing.stages,\n [input.destinationStage],\n input.actorId,\n now,\n ),\n revision: existing.revision + 1,\n updatedAt: now,\n });\n },\n );\n if (updated) item = toRow(updated);\n if (!item) {\n code = input.evaluation.outcome === 'rejected' ? input.evaluation.code : 'invalid_transition';\n reason = input.evaluation.outcome === 'rejected' ? input.evaluation.reason : 'Work item not found.';\n }\n const outcome: 'accepted' | 'rejected' =\n item && code === null && input.evaluation.outcome === 'accepted' ? 'accepted' : 'rejected';\n result =\n outcome === 'accepted'\n ? {\n status: 'accepted',\n transitionId: input.ingress.transitionId,\n itemId: item!.id,\n revision: item!.revision,\n stage: input.destinationStage,\n decisions: input.evaluation.outcome === 'accepted' ? input.evaluation.decisions : [],\n }\n : { status: 'rejected', transitionId: input.ingress.transitionId, itemId: input.workItemId, code, reason };\n const ingress = await ops.insertOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n identity: input.ingress.identity,\n trigger_type: input.ingress.triggerType,\n transition_id: input.ingress.transitionId,\n result,\n created_at: now,\n });\n if (item) {\n const evaluation = await ops.insertOne<GovernanceDbRow>('factory_rule_evaluations', {\n ingress_id: ingress.id,\n work_item_id: item.id,\n rule_set_version: input.ruleSetVersion,\n expected_revision: input.expectedRevision,\n outcome,\n code,\n reason,\n causal_chain: input.causalChain,\n created_at: now,\n });\n if (outcome === 'accepted' && input.evaluation.outcome === 'accepted') {\n for (const [index, decision] of input.evaluation.decisions.entries()) {\n await ops.insertOne<GovernanceDbRow>('factory_deferred_decisions', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n evaluation_id: evaluation.id,\n work_item_id: item.id,\n idempotency_key: String(decision.idempotencyKey),\n effect_ordinal: index,\n effect_hash: factoryDecisionHash(decision),\n causal_chain: input.causalChain,\n actor: null,\n decision,\n status: 'pending',\n attempts: 0,\n available_at: now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n created_at: new Date(now.getTime() + index),\n updated_at: now,\n });\n }\n }\n }\n return { status: 'committed', item, result };\n });\n return this.storage.withDistributedLock\n ? this.storage.withDistributedLock(\n `factory-ingress:${input.orgId}:${input.factoryProjectId}:${input.ingress.identity}`,\n commit,\n )\n : commit();\n }\n\n async commitRuleEvaluation(input: CommitFactoryRuleEvaluationInput): Promise<CommitFactoryRuleEvaluationResult> {\n const commit = () =>\n this.storage.withTransaction<CommitFactoryRuleEvaluationResult>(async ops => {\n const prior = await ops.findOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n identity: input.ingress.identity,\n });\n if (prior) {\n const result = prior.result as Record<string, unknown>;\n const decisions = Array.isArray(result.decisions) ? result.decisions : [];\n const evaluation = await ops.findOne<GovernanceDbRow>('factory_rule_evaluations', { ingress_id: prior.id });\n for (const decision of decisions) {\n if (\n !evaluation ||\n !decision ||\n typeof decision !== 'object' ||\n (decision as Record<string, unknown>).type !== 'upsertLinkedWorkItem' ||\n typeof (decision as Record<string, unknown>).sourceKey !== 'string' ||\n typeof (decision as Record<string, unknown>).idempotencyKey !== 'string'\n ) {\n continue;\n }\n const materialization = decision as Record<string, unknown> & { sourceKey: string; idempotencyKey: string };\n const item = await ops.findOne<WorkItemDbRow>('work_items', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n source_key: materialization.sourceKey,\n });\n if (item) continue;\n await ops.updateAtomic<GovernanceDbRow>(\n 'factory_deferred_decisions',\n {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n evaluation_id: evaluation.id,\n idempotency_key: materialization.idempotencyKey,\n },\n current =>\n current.status === 'succeeded'\n ? {\n status: 'retry',\n attempts: 0,\n available_at: input.now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n updated_at: input.now,\n }\n : null,\n );\n }\n return { status: 'replayed' as const, result };\n }\n const itemRow = input.workItemId\n ? await ops.findOne<WorkItemDbRow>('work_items', {\n id: input.workItemId,\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n })\n : null;\n if (input.workItemId !== null && !itemRow) return { status: 'missing' as const };\n const item = itemRow ? toRow(itemRow) : null;\n const stale = item !== null && item.revision !== input.expectedRevision;\n const outcome = stale ? 'rejected' : input.outcome.status;\n const code = stale ? 'stale' : (input.outcome.code ?? null);\n const reason = stale\n ? 'The work item changed before this rule evaluation committed.'\n : (input.outcome.reason ?? null);\n const decisions = outcome === 'accepted' ? input.decisions : [];\n const result = {\n status: outcome,\n itemId: item?.id ?? null,\n revision: item?.revision ?? null,\n code,\n reason,\n decisions,\n };\n const ingress = await ops.insertOne<GovernanceDbRow>('factory_rule_ingress', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n identity: input.ingress.identity,\n trigger_type: input.ingress.triggerType,\n transition_id: input.ingress.identity,\n result,\n created_at: input.now,\n });\n const evaluation = await ops.insertOne<GovernanceDbRow>('factory_rule_evaluations', {\n ingress_id: ingress.id,\n work_item_id: item?.id ?? null,\n rule_set_version: input.ruleSetVersion,\n expected_revision: input.expectedRevision,\n outcome,\n code,\n reason,\n causal_chain: input.causalChain,\n created_at: input.now,\n });\n for (const [effectOrdinal, decision] of decisions.entries()) {\n await ops.insertOne<GovernanceDbRow>('factory_deferred_decisions', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n evaluation_id: evaluation.id,\n work_item_id: item?.id ?? null,\n idempotency_key: String(decision.idempotencyKey),\n effect_ordinal: effectOrdinal,\n effect_hash: factoryDecisionHash(decision),\n causal_chain: input.causalChain,\n actor: input.actor,\n decision,\n status: 'pending',\n attempts: 0,\n available_at: input.now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n created_at: new Date(input.now.getTime() + effectOrdinal),\n updated_at: input.now,\n });\n }\n return { status: 'committed' as const, result };\n });\n return this.storage.withDistributedLock\n ? this.storage.withDistributedLock(\n `factory-ingress:${input.orgId}:${input.factoryProjectId}:${input.ingress.identity}`,\n commit,\n )\n : commit();\n }\n\n async getToolResultCursor(\n orgId: string,\n factoryProjectId: string,\n bindingId: string,\n ): Promise<FactoryToolResultCursorRecord | null> {\n const row = await this.#db.findOne<GovernanceDbRow>('factory_tool_result_cursors', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n binding_id: bindingId,\n });\n return row\n ? {\n bindingId: String(row.binding_id),\n orgId: row.org_id,\n factoryProjectId: String(row.factory_project_id),\n lastMessageId: String(row.last_message_id),\n lastMessageCreatedAt: row.last_message_created_at as Date,\n updatedAt: row.updated_at as Date,\n }\n : null;\n }\n\n async advanceToolResultCursor(cursor: FactoryToolResultCursorRecord): Promise<void> {\n const current = await this.getToolResultCursor(cursor.orgId, cursor.factoryProjectId, cursor.bindingId);\n if (current && current.lastMessageCreatedAt > cursor.lastMessageCreatedAt) return;\n await this.#db.upsertOne<GovernanceDbRow>('factory_tool_result_cursors', ['binding_id'], {\n binding_id: cursor.bindingId,\n org_id: cursor.orgId,\n factory_project_id: cursor.factoryProjectId,\n last_message_id: cursor.lastMessageId,\n last_message_created_at: cursor.lastMessageCreatedAt,\n updated_at: cursor.updatedAt,\n });\n }\n\n async listDeferredDecisions(orgId: string, factoryProjectId: string): Promise<FactoryDeferredDecisionRecord[]> {\n return (\n await this.#db.findMany<GovernanceDbRow>(\n 'factory_deferred_decisions',\n { org_id: orgId, factory_project_id: factoryProjectId },\n { orderBy: [['created_at', 'asc']] },\n )\n ).map(toDeferredDecision);\n }\n\n /** Read a bounded newest-first status page without exposing another tenant. */\n async listDeferredDecisionPage(input: FactoryDeferredDecisionPageInput): Promise<FactoryDeferredDecisionPage> {\n const rows = await this.#db.findMany<GovernanceDbRow>(\n 'factory_deferred_decisions',\n {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n ...(input.statuses ? { status: { in: input.statuses } } : {}),\n },\n {\n orderBy: [\n ['created_at', 'desc'],\n ['id', 'desc'],\n ],\n limit: input.limit + 1,\n ...(input.before ? { cursor: { values: [input.before.createdAt, input.before.id] } } : {}),\n },\n );\n return { decisions: rows.slice(0, input.limit).map(toDeferredDecision), hasMore: rows.length > input.limit };\n }\n\n async claimDeferredDecisions(input: FactoryLeaseClaimInput): Promise<FactoryDeferredDecisionRecord[]> {\n return this.#claimLeases('factory_deferred_decisions', input, toDeferredDecision);\n }\n\n async renewDeferredDecisionLease(identity: FactoryLeaseIdentity, leaseExpiresAt: Date): Promise<boolean> {\n return this.#renewLease('factory_deferred_decisions', identity, leaseExpiresAt);\n }\n\n async completeDeferredDecision(\n identity: FactoryLeaseIdentity,\n now: Date,\n ): Promise<FactoryDeferredDecisionRecord | null> {\n const row = await this.#completeLease('factory_deferred_decisions', identity, now);\n return row ? toDeferredDecision(row) : null;\n }\n\n async failDeferredDecision(input: FactoryDispatchFailureInput): Promise<FactoryDeferredDecisionRecord | null> {\n const row = await this.#failLease('factory_deferred_decisions', input);\n return row ? toDeferredDecision(row) : null;\n }\n\n /** Requeue the same idempotent terminal effect; non-failed decisions are never rerun. */\n async retryDeferredDecision(\n orgId: string,\n factoryProjectId: string,\n decisionId: string,\n now: Date,\n ): Promise<FactoryDeferredDecisionRecord | null> {\n let retried = false;\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n 'factory_deferred_decisions',\n { id: decisionId, org_id: orgId, factory_project_id: factoryProjectId },\n current => {\n if (current.status !== 'failed') return null;\n retried = true;\n return {\n status: 'retry',\n attempts: 0,\n available_at: now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n updated_at: now,\n };\n },\n );\n return retried && row ? toDeferredDecision(row) : null;\n }\n\n /** Resolve exact active agent authority; partial session matches never authorize. */\n async findActiveRunBinding(address: FactoryRunBindingAddress): Promise<FactoryRunBindingRecord | null> {\n const row = await this.#db.findOne<GovernanceDbRow>('factory_run_bindings', {\n org_id: address.orgId,\n factory_project_id: address.factoryProjectId,\n thread_id: address.threadId,\n resource_id: address.resourceId,\n session_id: address.sessionId,\n status: 'active',\n });\n return row ? toBinding(row) : null;\n }\n\n /** Resolve exact bound-session state for processor awareness; ambiguous cross-tenant matches return null. */\n async findRunBindingBySession(address: FactoryRunBindingSessionAddress): Promise<FactoryRunBindingRecord | null> {\n const rows = await this.#db.findMany<GovernanceDbRow>('factory_run_bindings', {\n factory_project_id: address.factoryProjectId,\n thread_id: address.threadId,\n resource_id: address.resourceId,\n session_id: address.sessionId,\n });\n if (new Set(rows.map(row => row.org_id)).size !== 1) return null;\n const row = rows.sort((left, right) => {\n if (left.status === 'active' && right.status !== 'active') return -1;\n if (right.status === 'active' && left.status !== 'active') return 1;\n return right.created_at.getTime() - left.created_at.getTime();\n })[0];\n return row ? toBinding(row) : null;\n }\n\n /** Revoke one exact tenant-scoped binding. */\n async revokeRunBinding(input: RevokeFactoryRunBindingInput): Promise<FactoryRunBindingRecord | null> {\n let revoked = false;\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n 'factory_run_bindings',\n { id: input.bindingId, org_id: input.orgId, factory_project_id: input.factoryProjectId },\n current => {\n if (current.status !== 'active') return null;\n revoked = true;\n return { status: 'revoked', revoked_at: input.revokedAt };\n },\n );\n return revoked && row ? toBinding(row) : null;\n }\n\n /** Enumerate active bindings for the server-owned restart reconciler. */\n async listActiveRunBindings(): Promise<FactoryRunBindingRecord[]> {\n return (await this.#db.findMany<GovernanceDbRow>('factory_run_bindings', { status: 'active' })).map(toBinding);\n }\n\n /** List binding history, optionally narrowed to one work item. */\n async listRunBindings(\n orgId: string,\n factoryProjectId: string,\n workItemId?: string,\n ): Promise<FactoryRunBindingRecord[]> {\n return (\n await this.#db.findMany<GovernanceDbRow>(\n 'factory_run_bindings',\n {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n ...(workItemId ? { work_item_id: workItemId } : {}),\n },\n { orderBy: [['created_at', 'asc']] },\n )\n ).map(toBinding);\n }\n\n async listPendingStarts(orgId: string, factoryProjectId: string): Promise<FactoryPendingStartRecord[]> {\n return (\n await this.#db.findMany<GovernanceDbRow>(\n 'factory_pending_starts',\n { org_id: orgId, factory_project_id: factoryProjectId },\n { orderBy: [['created_at', 'asc']] },\n )\n ).map(toPendingStart);\n }\n\n async claimPendingStarts(input: FactoryLeaseClaimInput): Promise<FactoryPendingStartRecord[]> {\n return this.#claimLeases('factory_pending_starts', input, toPendingStart);\n }\n\n async renewPendingStartLease(identity: FactoryLeaseIdentity, leaseExpiresAt: Date): Promise<boolean> {\n return this.#renewLease('factory_pending_starts', identity, leaseExpiresAt);\n }\n\n async completePendingStart(identity: FactoryLeaseIdentity, now: Date): Promise<FactoryPendingStartRecord | null> {\n const row = await this.#completeLease('factory_pending_starts', identity, now);\n return row ? toPendingStart(row) : null;\n }\n\n async failPendingStart(input: FactoryDispatchFailureInput): Promise<FactoryPendingStartRecord | null> {\n const row = await this.#failLease('factory_pending_starts', input);\n return row ? toPendingStart(row) : null;\n }\n\n async prepareRunStart(input: PrepareFactoryRunStartInput): Promise<PrepareFactoryRunStartResult> {\n const prepare = () =>\n this.storage.withTransaction(async ops => {\n const prior = await ops.findOne<GovernanceDbRow>('factory_pending_starts', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n kickoff_key: input.kickoffKey,\n });\n if (prior) {\n const bindingRow = await ops.findOne<GovernanceDbRow>('factory_run_bindings', {\n id: String(prior.binding_id),\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n });\n const itemRow =\n bindingRow &&\n (await ops.findOne<WorkItemDbRow>('work_items', {\n id: String(bindingRow.work_item_id),\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n }));\n if (!bindingRow || !itemRow) throw new Error('Factory start replay references missing state.');\n return {\n item: toRow(itemRow),\n binding: toBinding(bindingRow),\n pendingStart: toPendingStart(prior),\n replayed: true,\n };\n }\n const now = new Date();\n const create = input.workItem.input;\n let row = input.workItem.id\n ? await ops.findOne<WorkItemDbRow>('work_items', {\n id: input.workItem.id,\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n })\n : sourceKey(create.externalSource)\n ? await ops.findOne<WorkItemDbRow>('work_items', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n source_key: sourceKey(create.externalSource),\n })\n : null;\n let item: WorkItemRow;\n if (row) {\n row = await ops.updateAtomic<WorkItemDbRow>('work_items', { id: row.id }, current => {\n const roles = new Set([...Object.keys(current.sessions), input.role]);\n const sessions = Object.fromEntries([...roles].map(role => [role, input.session]));\n return applyUpdate({ current, userId: input.userId, input: { sessions } });\n });\n item = toRow(row!);\n } else {\n if (create.parentWorkItemId)\n validateParentRelation(\n (\n await ops.findMany<WorkItemDbRow>('work_items', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n })\n ).map(toRow),\n undefined,\n create.parentWorkItemId,\n );\n row = await ops.insertOne<WorkItemDbRow>('work_items', {\n org_id: input.orgId,\n created_by: input.userId,\n factory_project_id: input.factoryProjectId,\n external_source: create.externalSource ?? null,\n source_key: sourceKey(create.externalSource),\n parent_work_item_id: create.parentWorkItemId ?? null,\n title: create.title,\n stages: create.stages ?? [],\n stage_history: applyStageTransition([], [], create.stages ?? [], input.userId, now),\n sessions: stampSessions({ [input.role]: input.session }, input.userId),\n metadata: create.metadata ?? null,\n revision: 1,\n created_at: now,\n updated_at: now,\n });\n item = toRow(row);\n }\n await ops.updateMany(\n 'factory_run_bindings',\n {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n work_item_id: item.id,\n role: input.role,\n status: 'active',\n },\n { status: 'revoked', revoked_at: now },\n );\n const bindingRow = await ops.insertOne<GovernanceDbRow>('factory_run_bindings', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n work_item_id: item.id,\n role: input.role,\n thread_id: input.session.threadId,\n resource_id: input.resourceId,\n session_id: input.session.sessionId,\n branch: input.session.branch,\n status: 'active',\n created_at: now,\n revoked_at: null,\n });\n const pendingRow = await ops.insertOne<GovernanceDbRow>('factory_pending_starts', {\n org_id: input.orgId,\n factory_project_id: input.factoryProjectId,\n binding_id: bindingRow.id,\n kickoff_key: input.kickoffKey,\n message: input.kickoffMessage,\n status: 'pending',\n attempts: 0,\n available_at: now,\n lease_owner: null,\n lease_expires_at: null,\n last_error: null,\n completed_at: null,\n created_at: now,\n updated_at: now,\n });\n return { item, binding: toBinding(bindingRow), pendingStart: toPendingStart(pendingRow), replayed: false };\n });\n return this.storage.withDistributedLock\n ? this.storage.withDistributedLock(\n `factory-start:${input.orgId}:${input.factoryProjectId}:${input.kickoffKey}`,\n prepare,\n )\n : prepare();\n }\n\n async markPendingStart(\n bindingId: string,\n status: 'sent' | 'failed',\n lastError?: string,\n ): Promise<FactoryPendingStartRecord | null> {\n const row = await this.#db.updateAtomic<GovernanceDbRow>(\n 'factory_pending_starts',\n { binding_id: bindingId },\n () => ({ status, last_error: lastError ?? null, updated_at: new Date() }),\n );\n return row ? toPendingStart(row) : null;\n }\n\n /**\n * Create a work item, reusing the existing record when `sourceKey` already\n * has one for the project (acting twice on the same issue must not duplicate\n * the card). On reuse the provided stages replace the current ones (with the\n * transition recorded in history) and sessions/metadata are merged in. The\n * result discriminates insert from reuse so callers can audit the actual\n * outcome.\n */\n async upsert(params: {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n input: CreateWorkItemInput;\n reuseMode?: 'update' | 'preserve' | 'non-stage';\n }): Promise<UpsertWorkItemResult> {\n const run = () => this.#upsert(params);\n return params.input.parentWorkItemId\n ? this.#withProjectRelationLock(params.orgId, params.factoryProjectId, run)\n : run();\n }\n\n async #upsert({\n orgId,\n userId,\n factoryProjectId,\n input,\n reuseMode = 'update',\n }: {\n orgId: string;\n userId: string;\n factoryProjectId: string;\n input: CreateWorkItemInput;\n reuseMode?: 'update' | 'preserve' | 'non-stage';\n }): Promise<UpsertWorkItemResult> {\n const key = sourceKey(input.externalSource);\n const reuse = async (): Promise<UpsertWorkItemResult | null> => {\n if (!key) return null;\n const existing = await this.#db.findOne<WorkItemDbRow>('work_items', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n source_key: key,\n });\n if (!existing) return null;\n if (reuseMode === 'preserve') {\n const item = toWorkItem(existing);\n return { created: false, item, previous: priorState(existing) };\n }\n\n let previous = emptyPrior();\n const updated = await this.#db.updateAtomic<WorkItemDbRow>(\n 'work_items',\n { org_id: orgId, factory_project_id: factoryProjectId, source_key: key },\n async current => {\n previous = priorState(current);\n const fullPatch = input.parentWorkItemId === null ? { ...input, parentWorkItemId: undefined } : input;\n const patch: UpdateWorkItemInput =\n reuseMode === 'non-stage'\n ? {\n title: input.title,\n parentWorkItemId: input.parentWorkItemId ?? undefined,\n metadata: input.metadata,\n }\n : fullPatch;\n if (patch.parentWorkItemId !== undefined) {\n validateParentRelation(await this.list({ orgId, factoryProjectId }), current.id, patch.parentWorkItemId);\n }\n return {\n external_source: input.externalSource ?? null,\n ...applyUpdate({ current, userId, input: patch }),\n };\n },\n );\n return updated ? { item: toWorkItem(updated), created: false, previous } : null;\n };\n\n const reused = await reuse();\n if (reused) return reused;\n\n const now = new Date();\n const stages = input.stages ?? ['intake'];\n try {\n validateParentRelation(await this.list({ orgId, factoryProjectId }), undefined, input.parentWorkItemId ?? null);\n const row = await this.#db.insertOne<WorkItemDbRow>('work_items', {\n org_id: orgId,\n factory_project_id: factoryProjectId,\n external_source: input.externalSource ?? null,\n source_key: key,\n parent_work_item_id: input.parentWorkItemId ?? null,\n title: input.title,\n stages,\n stage_history: stages.map(stage => ({ stage, enteredAt: now.toISOString(), by: userId })),\n sessions: stampSessions(input.sessions ?? {}, userId),\n metadata: input.metadata ?? null,\n revision: 1,\n created_by: userId,\n created_at: now,\n updated_at: now,\n });\n return { item: toWorkItem(row), created: true, previous: emptyPrior() };\n } catch (error) {\n if (!(error instanceof UniqueViolationError)) throw error;\n const winner = await reuse();\n if (winner) return winner;\n throw error;\n }\n }\n\n async update({\n orgId,\n id,\n userId,\n patch,\n }: {\n orgId: string;\n id: string;\n userId: string;\n patch: UpdateWorkItemInput;\n }): Promise<{ item: WorkItemRow; previous: WorkItemPriorState } | null> {\n const run = async () => {\n let previous = emptyPrior();\n const row = await this.#db.updateAtomic<WorkItemDbRow>('work_items', { org_id: orgId, id }, async current => {\n previous = priorState(current);\n if (patch.parentWorkItemId !== undefined) {\n validateParentRelation(\n await this.list({ orgId, factoryProjectId: current.factory_project_id }),\n current.id,\n patch.parentWorkItemId,\n );\n }\n return applyUpdate({ current, userId, input: patch });\n });\n return row ? { item: toWorkItem(row), previous } : null;\n };\n\n if (patch.parentWorkItemId === undefined) return run();\n const candidate = await this.#db.findOne<WorkItemDbRow>('work_items', { org_id: orgId, id });\n if (!candidate) return null;\n return this.#withProjectRelationLock(orgId, candidate.factory_project_id, run);\n }\n\n async delete({ orgId, id }: { orgId: string; id: string }): Promise<WorkItemRow | null> {\n const candidate = await this.#db.findOne<WorkItemDbRow>('work_items', { org_id: orgId, id });\n if (!candidate) return null;\n\n return this.#withProjectRelationLock(orgId, candidate.factory_project_id, async () => {\n const existing = await this.#db.findOne<WorkItemDbRow>('work_items', { org_id: orgId, id });\n if (!existing) return null;\n const deleted = await this.#db.deleteMany('work_items', { org_id: orgId, id });\n if (deleted === 0) return null;\n await this.#db.updateMany(\n 'work_items',\n { org_id: orgId, parent_work_item_id: id },\n { parent_work_item_id: null, updated_at: new Date() },\n );\n return toWorkItem(existing);\n });\n }\n}\n","/**\n * Aggregation math for the Factory Metrics page.\n *\n * Pure functions over `work_items` rows — flow metrics (throughput, cycle\n * time, stage durations, WIP, aging WIP) plus demand mix, all derived from the\n * server-appended `stageHistory` log. Keeping this DB-free makes the math unit\n * testable and lets the route stay a thin shell.\n */\n\nimport { isAutomationActor } from './base.js';\nimport type { WorkItemRow, WorkItemStageEntry } from './base.js';\n\n/** Default window span (days) when the request omits or malforms the range. */\nexport const DEFAULT_METRICS_WINDOW = 30;\n/** Hard cap on the range span (days) — bounds the gap-filled throughput array. */\nexport const MAX_METRICS_WINDOW = 366;\n\nconst DAY_MS = 86_400_000;\n\n/** Terminal stage — items here count as completed, not in-flight. */\nconst DONE_STAGE = 'done';\n\n/** Terminal stage for tracked non-completions — never a completion. */\nconst CANCELED_STAGE = 'canceled';\n\n/**\n * Terminal stages — items holding only these are not in-flight. `done` is a\n * completion (feeds throughput/cycle time); `canceled` is a tracked\n * non-completion outcome and feeds neither.\n */\nconst TERMINAL_STAGES = new Set([DONE_STAGE, CANCELED_STAGE]);\n\nconst AGING_WIP_LIMIT = 10;\n\nexport interface FactoryMetrics {\n windowDays: number;\n /** Earliest work-item creation time (ISO, window-independent) — the natural\n * lower bound for a date-range control. `null` when the board is empty. */\n earliestItemAt: string | null;\n /** Items reaching `done` per UTC day, gap-filled across the window. */\n throughput: { date: string; count: number }[];\n /** Card creation → `done` duration for items completed in the window. */\n cycleTime: { medianMs: number | null; p90Ms: number | null; samples: number };\n /** Median time spent per stage, over visits that ended inside the window. */\n stageDurations: { stage: string; medianMs: number; samples: number }[];\n /** Current cards per stage (window-independent). */\n wip: { stage: string; count: number }[];\n /** Distinct in-flight cards (at least one non-terminal stage). */\n wipTotal: number;\n /** Oldest in-flight cards by time in their current stage. */\n agingWip: { id: string; title: string; stage: string; enteredAt: string; url: string | null }[];\n /** Cards created in the window, by source. */\n sourceMix: { source: string; count: number }[];\n /** Stage moves in the window: human-performed vs total. */\n transitions: { human: number; total: number };\n /** Per-stage automation over completed visits that exited in the window. */\n stageAutomation: {\n stage: string;\n /** Completed visits (entered+exited) to this stage that exited in the window. */\n exits: number;\n /**\n * Of those: clean automated passes — the item's first visit to the stage,\n * entered *and* exited by an automation actor. Missing `exitedBy` (entries\n * written before exit stamping) counts as human.\n */\n automated: number;\n /**\n * Outcomes of the automated passes' items, mutually exclusive, first match\n * wins: `reworked` (a later visit to the same stage exists — deliberately\n * outranks `done`: an automated pass that needed a redo is an automation\n * failure even if the item eventually merged), then `done`, then\n * `canceled`, then `inFlight`.\n */\n outcomes: { done: number; canceled: number; reworked: number; inFlight: number };\n }[];\n}\n\nconst DATE_ONLY_RE = /^\\d{4}-\\d{2}-\\d{2}$/;\n/** Datetime carrying an explicit `Z` or `±HH:MM` offset. */\nconst ZONED_DATETIME_RE = /(?:[Zz]|[+-]\\d{2}:?\\d{2})$/;\n\nfunction parseRangeParam(value: unknown, boundary: 'from' | 'to'): number | undefined {\n if (typeof value !== 'string' || value.length === 0) return undefined;\n const dateOnly = DATE_ONLY_RE.test(value);\n // Timezone-less datetimes are parsed as server-local by Date.parse, so the\n // window would shift by deployment region — reject them as invalid.\n if (!dateOnly && !ZONED_DATETIME_RE.test(value)) return undefined;\n const time = Date.parse(value);\n if (Number.isNaN(time)) return undefined;\n return boundary === 'to' && dateOnly ? time + DAY_MS : time;\n}\n\nfunction utcDayStart(time: number): number {\n return Date.parse(`${utcDay(time)}T00:00:00Z`);\n}\n\n/**\n * Resolve untrusted `from`/`to` into a bounded half-open UTC window. A date-only\n * `to` covers the whole day; an open/future end resolves to the end of the\n * current UTC day (not `now`) so an event at this instant stays inside the\n * window instead of on its excluded edge.\n */\nexport function parseMetricsRange(\n fromParam: unknown,\n toParam: unknown,\n now: Date,\n): { windowStart: number; windowEnd: number } {\n const nowMs = now.getTime();\n const endOfToday = utcDayStart(nowMs) + DAY_MS;\n const requestedEnd = parseRangeParam(toParam, 'to') ?? endOfToday;\n const windowEnd = Math.min(requestedEnd, endOfToday);\n const lastIncludedDay = utcDayStart(windowEnd - 1);\n const defaultStart = lastIncludedDay - (DEFAULT_METRICS_WINDOW - 1) * DAY_MS;\n const parsedFrom = parseRangeParam(fromParam, 'from');\n let windowStart = parsedFrom !== undefined && parsedFrom < windowEnd ? parsedFrom : defaultStart;\n const earliestStart = lastIncludedDay - (MAX_METRICS_WINDOW - 1) * DAY_MS;\n if (windowStart < earliestStart) windowStart = earliestStart;\n return { windowStart, windowEnd };\n}\n\nfunction parseTime(iso: string): number {\n const time = Date.parse(iso);\n return Number.isNaN(time) ? 0 : time;\n}\n\n/** Nearest-rank percentile over an unsorted sample list. */\nfunction percentile(samples: number[], fraction: number): number | null {\n if (samples.length === 0) return null;\n const sorted = [...samples].sort((a, b) => a - b);\n const rank = Math.max(1, Math.ceil(fraction * sorted.length));\n return sorted[rank - 1]!;\n}\n\n/** UTC `YYYY-MM-DD` for a timestamp. */\nfunction utcDay(time: number): string {\n return new Date(time).toISOString().slice(0, 10);\n}\n\n/**\n * The item's completion time: the `enteredAt` of its still-open `done` entry.\n * `undefined` when the item isn't currently done (including when it was pulled\n * back out of done — that visit has `exitedAt` and doesn't count).\n */\nfunction completedAt(item: WorkItemRow): number | undefined {\n if (!item.stages.includes(DONE_STAGE)) return undefined;\n for (let i = item.stageHistory.length - 1; i >= 0; i--) {\n const entry = item.stageHistory[i]!;\n if (entry.stage === DONE_STAGE && entry.exitedAt === undefined) return parseTime(entry.enteredAt);\n }\n return undefined;\n}\n\n/** Open (no `exitedAt`) history entry for a currently-held non-terminal stage. */\nfunction openEntries(item: WorkItemRow): WorkItemStageEntry[] {\n return item.stageHistory.filter(\n entry => entry.exitedAt === undefined && !TERMINAL_STAGES.has(entry.stage) && item.stages.includes(entry.stage),\n );\n}\n\nexport function computeFactoryMetrics(\n items: WorkItemRow[],\n opts: { windowStart: number; windowEnd: number },\n): FactoryMetrics {\n const { windowStart, windowEnd } = opts;\n\n // Earliest creation across all items (window-independent) — the range lower bound.\n let earliest = Infinity;\n for (const item of items) earliest = Math.min(earliest, item.createdAt.getTime());\n const earliestItemAt = Number.isFinite(earliest) ? new Date(earliest).toISOString() : null;\n\n // ── Throughput + cycle time (completed in window) ─────────────────────────\n // Gap-fill every UTC calendar date intersecting the half-open window.\n const throughputByDay = new Map<string, number>();\n const firstDay = utcDayStart(windowStart);\n for (let day = firstDay; day < windowEnd; day += DAY_MS) {\n throughputByDay.set(utcDay(day), 0);\n }\n const cycleSamples: number[] = [];\n for (const item of items) {\n const doneAt = completedAt(item);\n if (doneAt === undefined || doneAt < windowStart || doneAt >= windowEnd) continue;\n const day = utcDay(doneAt);\n throughputByDay.set(day, (throughputByDay.get(day) ?? 0) + 1);\n cycleSamples.push(Math.max(0, doneAt - item.createdAt.getTime()));\n }\n\n // ── Stage durations (visits that ended in window) ─────────────────────────\n const durationsByStage = new Map<string, number[]>();\n for (const item of items) {\n for (const entry of item.stageHistory) {\n if (entry.exitedAt === undefined || TERMINAL_STAGES.has(entry.stage)) continue;\n const exited = parseTime(entry.exitedAt);\n if (exited < windowStart || exited >= windowEnd) continue;\n const duration = Math.max(0, exited - parseTime(entry.enteredAt));\n const samples = durationsByStage.get(entry.stage) ?? [];\n samples.push(duration);\n durationsByStage.set(entry.stage, samples);\n }\n }\n\n // ── Current WIP + aging (window-independent) ──────────────────────────────\n const wipByStage = new Map<string, number>();\n let wipTotal = 0;\n const aging: FactoryMetrics['agingWip'] = [];\n for (const item of items) {\n for (const stage of item.stages) {\n wipByStage.set(stage, (wipByStage.get(stage) ?? 0) + 1);\n }\n const inFlightStages = item.stages.filter(stage => !TERMINAL_STAGES.has(stage));\n if (inFlightStages.length === 0) continue;\n wipTotal += 1;\n // Age the card by its longest-held current stage; fall back to creation\n // time if history is missing an open entry (shouldn't happen — history is\n // server-appended).\n const open = openEntries(item);\n const oldest = open.reduce<WorkItemStageEntry | undefined>(\n (best, entry) => (!best || parseTime(entry.enteredAt) < parseTime(best.enteredAt) ? entry : best),\n undefined,\n );\n aging.push({\n id: item.id,\n title: item.title,\n stage: oldest?.stage ?? inFlightStages[0]!,\n enteredAt: oldest?.enteredAt ?? item.createdAt.toISOString(),\n url: item.externalSource?.url ?? null,\n });\n }\n aging.sort((a, b) => parseTime(a.enteredAt) - parseTime(b.enteredAt));\n\n // ── Demand mix + transitions (window) ─────────────────────────────────────\n const sourceCounts = new Map<string, number>();\n let transitionsTotal = 0;\n let transitionsHuman = 0;\n for (const item of items) {\n if (item.createdAt.getTime() >= windowStart && item.createdAt.getTime() < windowEnd) {\n const source = item.externalSource\n ? `${item.externalSource.integrationId}:${item.externalSource.type}`\n : 'manual';\n sourceCounts.set(source, (sourceCounts.get(source) ?? 0) + 1);\n }\n for (const entry of item.stageHistory) {\n const entered = parseTime(entry.enteredAt);\n if (entered < windowStart || entered >= windowEnd) continue;\n transitionsTotal += 1;\n if (!isAutomationActor(entry.by)) transitionsHuman += 1;\n }\n }\n\n // ── Per-stage automation (completed visits that exited in window) ─────────\n // Rows appear in insertion order of each stage's first counted exit;\n // terminal stages never get rows (they have no meaningful \"pass through\").\n const automationByStage = new Map<string, FactoryMetrics['stageAutomation'][number]>();\n for (const item of items) {\n const itemDone = completedAt(item) !== undefined;\n const itemCanceled = item.stages.includes(CANCELED_STAGE);\n for (let i = 0; i < item.stageHistory.length; i++) {\n const entry = item.stageHistory[i]!;\n if (entry.exitedAt === undefined || TERMINAL_STAGES.has(entry.stage)) continue;\n const exited = parseTime(entry.exitedAt);\n if (exited < windowStart || exited >= windowEnd) continue;\n let row = automationByStage.get(entry.stage);\n if (!row) {\n row = {\n stage: entry.stage,\n exits: 0,\n automated: 0,\n outcomes: { done: 0, canceled: 0, reworked: 0, inFlight: 0 },\n };\n automationByStage.set(entry.stage, row);\n }\n row.exits += 1;\n // A clean automated pass: automation entered AND exited it, and this is\n // the item's first visit to the stage (a re-run is rework, not clean\n // automation). Missing `exitedBy` → human-exited → not automated.\n const firstVisitIndex = item.stageHistory.findIndex(e => e.stage === entry.stage);\n if (firstVisitIndex !== i || !isAutomationActor(entry.by) || !isAutomationActor(entry.exitedBy)) continue;\n row.automated += 1;\n const reworked = item.stageHistory.some((e, j) => j > i && e.stage === entry.stage);\n if (reworked) row.outcomes.reworked += 1;\n else if (itemDone) row.outcomes.done += 1;\n else if (itemCanceled) row.outcomes.canceled += 1;\n else row.outcomes.inFlight += 1;\n }\n }\n\n return {\n windowDays: throughputByDay.size,\n earliestItemAt,\n throughput: [...throughputByDay.entries()]\n .map(([date, count]) => ({ date, count }))\n .sort((a, b) => a.date.localeCompare(b.date)),\n cycleTime: {\n medianMs: percentile(cycleSamples, 0.5),\n p90Ms: percentile(cycleSamples, 0.9),\n samples: cycleSamples.length,\n },\n stageDurations: [...durationsByStage.entries()].map(([stage, samples]) => ({\n stage,\n medianMs: percentile(samples, 0.5)!,\n samples: samples.length,\n })),\n wip: [...wipByStage.entries()].map(([stage, count]) => ({ stage, count })),\n wipTotal,\n agingWip: aging.slice(0, AGING_WIP_LIMIT),\n sourceMix: [...sourceCounts.entries()]\n .map(([source, count]) => ({ source, count }))\n .sort((a, b) => b.count - a.count),\n transitions: { human: transitionsHuman, total: transitionsTotal },\n stageAutomation: [...automationByStage.values()],\n };\n}\n","/**\n * Base class for factory route modules.\n *\n * Route modules build Mastra `apiRoutes` from injected dependencies instead of\n * reaching into host globals. The host server (e.g. `mastracode/web`) supplies\n * the auth seam and storage domain handles at construction time, so the routes\n * stay portable and testable with fakes.\n */\n\nimport type { ApiRoute } from '@mastra/core/server';\nimport type { Context } from 'hono';\n\n/**\n * The auth surface factory routes need, implemented by the host server.\n *\n * Local (no-auth) deployments implement this with a stub where `enabled()`\n * returns `false` and `tenant()` returns `undefined` — routes then take their\n * single-user local paths.\n */\nexport interface RouteAuth {\n /** Whether an auth provider is active (tenant mode). */\n enabled(): boolean;\n /**\n * Resolve (and cache) the signed-in user for the request, if any. Must be\n * called before `tenant()` so the request context is populated.\n */\n ensureUser(c: Context): Promise<unknown>;\n /** Tenant identity for the request, when signed in. */\n tenant(c: Context): { orgId?: string; userId: string } | undefined;\n /** Fail-closed check that the caller administers the given organization. */\n isOrganizationAdmin(c: Context, organizationId: string): Promise<boolean>;\n}\n\n/** Dependencies shared by every factory route module. */\nexport interface RouteDependencies {\n auth: RouteAuth;\n}\n\n/**\n * A route module: constructed once at boot with its dependencies, then asked\n * for the `ApiRoute[]` it serves.\n */\nexport abstract class Route<TDeps extends RouteDependencies = RouteDependencies> {\n protected readonly deps: TDeps;\n\n constructor(deps: TDeps) {\n this.deps = deps;\n }\n\n /** Build the Mastra `apiRoutes` served by this module. */\n abstract routes(): ApiRoute[];\n}\n"],"mappings":"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","names":["FactoryStorageDomain","UniqueViolationError"]}
|