spb/autoscholar
Public
1import { z } from "zod";2import { Discipline, ResearchMode } from "./modes.js";34export const RunStatus = z.enum([5 "draft",6 "validated",7 "queued",8 "provisioning",9 "running",10 "quality_check",11 "quality_failed",12 "revising",13 "ready_to_publish",14 "awaiting_approval",15 "publishing",16 "published",17 "cancelling",18 "cancelled",19 "failed",20 "retrying",21]);22export type RunStatus = z.infer<typeof RunStatus>;2324/** Valid transitions of the run state machine (enforced server-side, appended to the event ledger). */25export const RUN_TRANSITIONS: Record<RunStatus, readonly RunStatus[]> = {26 draft: ["validated", "cancelled"],27 validated: ["queued", "cancelled"],28 queued: ["provisioning", "cancelling", "cancelled", "failed"],29 provisioning: ["running", "quality_check", "retrying", "cancelling", "cancelled", "failed"],30 running: ["quality_check", "retrying", "cancelling", "failed", "revising"],31 quality_check: ["quality_failed", "ready_to_publish", "cancelling", "failed"],32 quality_failed: ["revising", "cancelled", "failed", "ready_to_publish"],33 revising: ["queued", "retrying", "cancelling", "failed"],34 ready_to_publish: ["awaiting_approval", "publishing", "cancelled", "failed"],35 awaiting_approval: ["publishing", "cancelled", "quality_failed"],36 publishing: ["published", "failed", "ready_to_publish"],37 published: [],38 cancelling: ["cancelled", "failed"],39 cancelled: [],40 failed: ["retrying", "queued"],41 retrying: ["queued", "failed", "cancelled"],42};4344export const ACTIVE_RUN_STATUSES: readonly RunStatus[] = [45 "queued",46 "provisioning",47 "running",48 "quality_check",49 "revising",50 "retrying",51 "publishing",52];5354export const TERMINAL_RUN_STATUSES: readonly RunStatus[] = ["published", "cancelled", "failed"];5556export const STAGES = [57 { index: 0, key: "preflight", name: "Preflight" },58 { index: 1, key: "framing", name: "Research framing" },59 { index: 2, key: "literature", name: "Literature and prior art" },60 { index: 3, key: "design", name: "Research design and foundations" },61 { index: 4, key: "execute", name: "Execute research" },62 { index: 5, key: "robustness", name: "Robustness and falsification" },63 { index: 6, key: "manuscript", name: "Manuscript construction" },64 { index: 7, key: "review", name: "Independent critical review" },65 { index: 8, key: "reproduction", name: "Reproduction and build" },66 { index: 9, key: "quality", name: "Quality decision" },67 { index: 10, key: "publication", name: "Publication" },68] as const;69export type StageKey = (typeof STAGES)[number]["key"];70export const StageKey = z.enum(STAGES.map((s) => s.key) as [StageKey, ...StageKey[]]);71export const WORKER_STAGES: readonly StageKey[] = STAGES.slice(0, 9).map((s) => s.key);7273export const StageStatus = z.enum(["pending", "running", "completed", "failed", "skipped", "cancelled"]);74export type StageStatus = z.infer<typeof StageStatus>;7576export const ComputeProfile = z.enum(["standard", "compute-heavy", "memory-heavy"]);77export type ComputeProfile = z.infer<typeof ComputeProfile>;7879/** Immutable job manifest. Server-authored, never contains secrets. */80export const RunManifest = z.object({81 schemaVersion: z.literal(1),82 runId: z.string().uuid(),83 projectId: z.string().uuid(),84 instructionVersionId: z.string().uuid(),85 instructionVersion: z.number().int().positive(),86 instructionSha256: z.string().regex(/^[a-f0-9]{64}$/),87 researchMode: ResearchMode,88 secondaryModes: z.array(ResearchMode).default([]),89 discipline: Discipline,90 computeProfile: ComputeProfile,91 provider: z.literal("anthropic"),92 model: z.string().min(1),93 reviewerModel: z.string().min(1),94 maxBudgetUsd: z.number().positive().max(2000),95 maxRuntimeMinutes: z96 .number()97 .int()98 .positive()99 .max(24 * 60),100 maxAttempts: z.number().int().min(1).max(5),101 autoPublish: z.boolean(),102 qualityPolicyVersion: z.string(),103 createdAt: z.string().datetime(),104 createdBy: z.string().uuid(),105 title: z.string().min(3).max(300),106});107export type RunManifest = z.infer<typeof RunManifest>;108109export const LaunchRunRequest = z.object({110 projectId: z.string().uuid(),111 instructionVersionId: z.string().uuid(),112 idempotencyKey: z.string().min(8).max(128),113 title: z.string().min(3).max(300),114 researchMode: ResearchMode,115 secondaryModes: z.array(ResearchMode).max(3).default([]),116 discipline: Discipline,117 computeProfile: ComputeProfile.default("standard"),118 model: z.string().min(1).optional(),119 maxBudgetUsd: z.number().positive().max(2000).optional(),120 maxRuntimeMinutes: z121 .number()122 .int()123 .positive()124 .max(24 * 60)125 .optional(),126 maxAttempts: z.number().int().min(1).max(5).default(2),127 autoPublish: z.boolean().default(false),128});129export type LaunchRunRequest = z.infer<typeof LaunchRunRequest>;130