import { z } from 'zod'; export const COUNCIL_SCHEMA_VERSION = '1.0.0'; export const COUNCIL_PIPELINE_VERSION = '1.0.0'; export const councilGroupSchema = z.enum(['D', 'P']); export type CouncilGroup = z.infer; export const stopReasonSchema = z.enum([ 'max_rounds', 'convergence', 'bridge_validation_failed', 'grounding_failed', 'meta_validation_failed', ]); export const validationFailureReasonSchema = z.enum([ 'schema_invalid', 'unknown_id', 'cap_exceeded', 'repair_failed', 'parse_failed', ]); export const droppedReasonSchema = z.enum([ 'cap_top_ideas', 'cap_field_bullets', 'cap_entry_chars', 'cap_total_chars', 'invalid_reference', 'grounding_failed', ]); export const rejectionReasonCodeSchema = z.enum([ 'low_score', 'high_risk', 'insufficient_grounding', 'duplicate', 'out_of_scope', 'unknown_id', 'other', ]); const schemaVersionField = z.literal(COUNCIL_SCHEMA_VERSION); export const ideaContentSchema = z.object({ title: z.string().min(1), hypothesis: z.string().min(1), mechanism: z.string().min(1), expected_outcome: z.string().min(1), }).strict(); export const ideaGroundingSchema = z.object({ mve: z.string().min(1), constraints: z.array(z.string().min(1)).min(1), falsifiability_checks: z.array(z.string().min(1)).min(1), }).strict(); export const ideaCardSchema = z.object({ schema_version: schemaVersionField, idea_id: z.string().min(1), group: councilGroupSchema, round: z.number().int().min(1), content: ideaContentSchema, grounding: ideaGroundingSchema.optional(), grounding_failed: z.boolean().optional(), }).strict(); export const scoreSetSchema = z.object({ novelty: z.number().int().min(0).max(100), feasibility: z.number().int().min(0).max(100), impact: z.number().int().min(0).max(100), testability: z.number().int().min(0).max(100), }).strict(); export const ideaAssessmentSchema = z.object({ schema_version: schemaVersionField, idea_id: z.string().min(1), scores: scoreSetSchema, decision: z.enum(['shortlist', 'hold', 'reject']), notes: z.string().min(1), }).strict(); export const bridgeIdeaSchema = z.object({ idea_id: z.string().min(1), mechanism: z.string().min(1), rationale: z.string().min(1), }).strict(); export const bridgePacketSchema = z.object({ schema_version: schemaVersionField, from_group: councilGroupSchema, to_group: councilGroupSchema, round: z.number().int().min(1), top_ideas: z.array(bridgeIdeaSchema), assumptions: z.array(z.string().min(1)), risks: z.array(z.string().min(1)), asks: z.array(z.string().min(1)), what_to_steal: z.array(z.string().min(1)), }).strict(); export const councilBriefSchema = z.object({ schema_version: schemaVersionField, group: councilGroupSchema, round: z.number().int().min(1), ideas: z.array(ideaCardSchema), assessments: z.array(ideaAssessmentSchema), shortlist: z.array(z.string().min(1)), assumptions: z.array(z.string().min(1)), risks: z.array(z.string().min(1)), asks: z.array(z.string().min(1)), what_to_steal: z.array(z.string().min(1)), convergence_signal: z.boolean(), novelty_score: z.number().int().min(0).max(100), repetition_rate: z.number().int().min(0).max(100), }).strict(); export const councilDiffSchema = z.object({ schema_version: schemaVersionField, group: councilGroupSchema, from_round: z.number().int().min(1), to_round: z.number().int().min(1), idea_added: z.array(z.string().min(1)), idea_removed: z.array(z.string().min(1)), shortlist_added: z.array(z.string().min(1)), shortlist_removed: z.array(z.string().min(1)), score_changes: z.array(z.object({ idea_id: z.string().min(1), from_total: z.number().int(), to_total: z.number().int(), }).strict()), assumptions_added: z.array(z.string().min(1)), assumptions_removed: z.array(z.string().min(1)), mve_changed: z.array(z.string().min(1)), }).strict(); export const mergeRecordSchema = z.object({ sources: z.array(z.string().min(1)).min(2), result_title: z.string().min(1), rationale: z.string().min(1), }).strict(); export const metaSelectionSchema = z.object({ schema_version: schemaVersionField, selected_primary: z.array(z.string().min(1)), selected_secondary: z.array(z.string().min(1)), merges: z.array(mergeRecordSchema).optional(), rejections: z.array(z.object({ idea_id: z.string().min(1), reason_code: rejectionReasonCodeSchema, }).strict()), open_questions: z.array(z.string().min(1)), next_experiments: z.array(z.string().min(1)), }).strict(); export const councilTraceEventSchema = z.object({ schema_version: schemaVersionField, event_id: z.string().min(1), phase_index: z.number().int().min(1), call_id: z.string().min(1), group: councilGroupSchema.optional(), round: z.number().int().min(1).optional(), prompt_payload_hash: z.string().length(64), artifact_hash: z.string().length(64).optional(), token_usage: z.object({ inputTokens: z.number().int().min(0), outputTokens: z.number().int().min(0), }).strict().optional(), latency_ms: z.number().int().min(0).optional(), dropped_reason: droppedReasonSchema.optional(), validation_failure: validationFailureReasonSchema.optional(), }).strict(); export const councilConversationTurnSchema = z.object({ schema_version: schemaVersionField, phase_index: z.number().int().min(1), call_id: z.string().min(1), agent: z.string().min(1), tier: z.enum(['fast', 'default', 'complex', 'local']), group: councilGroupSchema.optional(), round: z.number().int().min(1).optional(), prompt_payload: z.record(z.string(), z.unknown()), response: z.string(), usage: z.object({ inputTokens: z.number().int().min(0), outputTokens: z.number().int().min(0), }).strict(), }).strict(); export const stopSnapshotSchema = z.object({ stop_reason: stopReasonSchema, round_reached: z.number().int().min(1), final_shortlist_D: z.array(z.string().min(1)), final_shortlist_P: z.array(z.string().min(1)), bridge_validated: z.boolean(), grounding_failures_count: z.number().int().min(0), }).strict(); export const councilRunResultSchema = z.object({ pipeline_version: z.literal(COUNCIL_PIPELINE_VERSION), input_hash: z.string().length(64), brief_D_v1: councilBriefSchema, brief_P_v1: councilBriefSchema, brief_D_v2: councilBriefSchema, brief_P_v2: councilBriefSchema, diff_D: councilDiffSchema, diff_P: councilDiffSchema, bridge_D_to_P: bridgePacketSchema, bridge_P_to_D: bridgePacketSchema, meta: metaSelectionSchema, stop_snapshot: stopSnapshotSchema, trace: z.array(councilTraceEventSchema), conversations: z.array(councilConversationTurnSchema), }).strict(); export const councilRunInputSchema = z.object({ task: z.string().min(1), constraints: z.union([z.string().min(1), z.record(z.string(), z.unknown())]).optional(), success_definition: z.string().min(1).optional(), budget: z.record(z.string(), z.unknown()).optional(), timebox: z.union([z.string().min(1), z.number().positive()]).optional(), output_format: z.string().min(1).optional(), max_rounds: z.number().int().min(1).max(6).optional(), session_id: z.string().min(1).optional(), }).strict(); export const ideationOutputSchema = z.object({ ideas: z.array(ideaContentSchema).min(1), }).strict(); export const assessmentOutputSchema = z.object({ assessments: z.array(z.object({ idea_id: z.string().min(1), scores: scoreSetSchema, decision: z.enum(['shortlist', 'hold', 'reject']), notes: z.string().min(1), }).strict()), assumptions: z.array(z.string().min(1)), risks: z.array(z.string().min(1)), asks: z.array(z.string().min(1)), what_to_steal: z.array(z.string().min(1)), convergence_signal: z.boolean(), novelty_score: z.number().int().min(0).max(100), repetition_rate: z.number().int().min(0).max(100), }).strict(); export const groundingOutputSchema = z.object({ grounded: z.array(z.object({ idea_id: z.string().min(1), mve: z.string().min(1), constraints: z.array(z.string().min(1)).min(1), falsifiability_checks: z.array(z.string().min(1)).min(1), }).strict()), }).strict(); export type StopReason = z.infer; export type ValidationFailureReason = z.infer; export type DroppedReason = z.infer; export type IdeaCard = z.infer; export type IdeaAssessment = z.infer; export type BridgePacket = z.infer; export type CouncilBrief = z.infer; export type CouncilDiff = z.infer; export type CouncilRunInput = z.infer; export type CouncilRunResult = z.infer; export type CouncilTraceEvent = z.infer; export type CouncilConversationTurn = z.infer; export type MetaSelection = z.infer;