import { z } from "zod"; import { StageKey } from "./run.js"; export const ArtifactKind = z.enum([ "instruction", "manifest", "plan", "source", "data", "code", "result", "figure", "table", "manuscript", "pdf", "review", "provenance", "log", "checksum", "other", ]); export type ArtifactKind = z.infer; export const ArtifactVisibility = z.enum(["private", "public"]); export const ArtifactDescriptor = z.object({ path: z .string() .min(1) .max(512) .refine((p) => !p.startsWith("/") && !p.split("/").includes("..") && !p.includes("\\"), "unsafe path"), kind: ArtifactKind, sha256: z.string().regex(/^[a-f0-9]{64}$/), bytes: z.number().int().nonnegative(), contentType: z.string().max(128).default("application/octet-stream"), stage: StageKey, synthetic: z.boolean().default(false), }); export type ArtifactDescriptor = z.infer; /** The required mode-aware artifact structure under runs// (relative paths). */ export const CONTRACT_PATHS = { instruction: "input/CLAUDE.md", manifest: "input/run.json", plan: "plan/research-plan.md", feasibility: "plan/feasibility.json", referencesBib: "sources/references.bib", sources: "sources/sources.json", sourceMap: "sources/source-map.json", dataReadme: "data/README.md", dataManifest: "data/manifest.json", codeReadme: "code/README.md", metrics: "results/metrics.json", robustness: "results/robustness.md", experimentLog: "results/experiment-log.jsonl", mainTex: "manuscript/main.tex", manuscriptBib: "manuscript/references.bib", mainPdf: "manuscript/main.pdf", abstract: "manuscript/abstract.md", metadata: "manuscript/metadata.json", review1: "review/review-1.md", revisions: "review/revisions.md", qaReport: "review/qa-report.json", events: "provenance/events.jsonl", runSummary: "provenance/run-summary.json", checksums: "provenance/checksums.sha256", } as const; export const ManuscriptMetadata = z.object({ title: z.string().min(3).max(300), abstract: z.string().min(50).max(5000), keywords: z.array(z.string().min(1).max(60)).min(2).max(12), discipline: z.string(), researchMode: z.string(), secondaryModes: z.array(z.string()).default([]), contributions: z.array(z.string()).min(1).max(8), methods: z.string().max(3000), mainResults: z.string().max(3000), limitations: z.string().max(3000), dataAvailability: z.string().max(2000).default(""), codeAvailability: z.string().max(2000).default(""), ethics: z.string().max(2000).default(""), synthetic: z.boolean().default(false), language: z.string().default("en"), }); export type ManuscriptMetadata = z.infer; export const SourceRecord = z.object({ key: z.string().min(1), kind: z.enum(["doi", "arxiv", "pmid", "openalex", "url", "isbn", "other"]), identifier: z.string().min(1), title: z.string().min(1), authors: z.array(z.string()).default([]), year: z.number().int().optional(), venue: z.string().optional(), url: z.string().url().optional(), verified: z.boolean(), verifiedAt: z.string().datetime().optional(), verificationMethod: z.string().optional(), accessLevel: z.enum(["metadata", "abstract", "full-text"]).default("metadata"), notes: z.string().optional(), }); export type SourceRecord = z.infer; export const SourcesFile = z.object({ sources: z.array(SourceRecord) }); export const SourceMapEntry = z.object({ claim: z.string().min(1), location: z.string().optional(), sourceKeys: z.array(z.string()).default([]), artifactPaths: z.array(z.string()).default([]), kind: z.enum(["literature", "result", "data", "derivation", "definition"]).default("literature"), }); export const SourceMapFile = z.object({ claims: z.array(SourceMapEntry) }); export const FeasibilityFile = z.object({ feasible: z.boolean(), researchMode: z.string(), secondaryModes: z.array(z.string()).default([]), summary: z.string(), restrictedActivities: z.array(z.string()).default([]), requiredApprovals: z.array(z.string()).default([]), missingInputs: z.array(z.string()).default([]), risks: z.array(z.string()).default([]), estimatedBudgetUsd: z.number().optional(), rejectReason: z.string().optional(), }); export type FeasibilityFile = z.infer; export const DataManifestEntry = z.object({ name: z.string(), source: z.string(), url: z.string().optional(), license: z.string(), acquiredAt: z.string(), sha256: z .string() .regex(/^[a-f0-9]{64}$/) .optional(), bytes: z.number().int().optional(), synthetic: z.boolean(), transformations: z.array(z.string()).default([]), notes: z.string().optional(), }); export const DataManifestFile = z.object({ datasets: z.array(DataManifestEntry) }); export const MetricsFile = z.object({ metrics: z.record(z.string(), z.unknown()), reportedValues: z .array( z.object({ label: z.string(), value: z.union([z.number(), z.string()]), unit: z.string().optional(), location: z.string().optional(), }), ) .default([]), synthetic: z.boolean().default(false), }); export const ExperimentLogEntry = z.object({ name: z.string(), command: z.string(), startedAt: z.string(), endedAt: z.string(), exitCode: z.number().int(), seed: z.union([z.number(), z.string()]).optional(), environment: z.record(z.string(), z.string()).optional(), outputs: z.array(z.string()).default([]), synthetic: z.boolean().default(false), }); export const RunSummary = z.object({ runId: z.string().uuid(), attemptNo: z.number().int(), researchMode: z.string(), stagesCompleted: z.array(z.string()), costUsd: z.number(), turns: z.number().int(), model: z.string(), reviewerModel: z.string(), workerName: z.string(), startedAt: z.string(), endedAt: z.string(), sdkVersion: z.string(), toolchain: z.record(z.string(), z.string()).default({}), synthetic: z.boolean().default(false), }); export type RunSummary = z.infer;