/**
* Output Ingestion & Interpretation — input and output schemas
* (Std 2 + Std 11).
*/
import { z } from 'zod';
import { insightSynthesisOutputSchema } from '../../intelligence/insight-synthesis/schema.js';
export const outputIngestionInputSchema = insightSynthesisOutputSchema;
export type OutputIngestionInput = z.infer<typeof outputIngestionInputSchema>;
export const recommendationSupportSchema = z.object({
/** "insight" | "comparison" | "metric" | "methodology" — what
* upstream object this recommendation rests on. */
kind: z.enum(['insight', 'comparison', 'metric', 'methodology']),
/** The id of the upstream object — insightId / comparisonId /
* metricKey / methodology_id. */
ref: z.string(),
detail: z.string(),
});
export type RecommendationSupport = z.infer<typeof recommendationSupportSchema>;
export const recommendationSchema = z.object({
recommendationId: z.string(),
/** Source insight from Pillar 2 this recommendation interprets. */
sourceInsightId: z.string(),
/** Rule from the library that produced this recommendation. */
ruleApplied: z.string(),
/** The interpretive language the rule's action produced. */
language: z.string(),
/** The action category the rule classifies this finding as — e.g.
* "outperformer", "underperformer", "in-line", "moderate-divergence". */
suggestedActionCategory: z.string(),
/** Severity per the rule's severity_mapping. */
severity: z.enum(['low', 'normal', 'material', 'high_impact']),
/** Optional structured position (e.g. "+2.1 std dev above peer mean"). */
statisticalPosition: z.string().optional(),
/** Optional entity the recommendation is about (some recommendations
* are aggregate / cross-entity). */
entityIdentifier: z.string().optional(),
/** Audience tier carried through from the JobRequest for downstream
* visualization + delivery rule matching. */
audienceTier: z.string(),
/** What this recommendation rests on — at least one citation
* required (Std 4 in the Decision context). */
supportingFindings: z.array(recommendationSupportSchema).min(1),
/** Reasoning lineage back to source URLs (carried from upstream). */
reasoningLineage: z.array(z.string()),
confidence: z.number().min(0).max(1),
flags: z.array(z.string()),
});
export type Recommendation = z.infer<typeof recommendationSchema>;
export const ruleGapEscalationSchema = z.object({
sourceInsightId: z.string(),
reason: z.enum(['no-rule-matched', 'rule-conflict-unresolved', 'sub-threshold-confidence', 'material-finding-needs-authorization']),
detail: z.string(),
triedTriggers: z.array(z.string()),
});
export type RuleGapEscalation = z.infer<typeof ruleGapEscalationSchema>;
export const outputIngestionOutputSchema = z.object({
recommendations: z.array(recommendationSchema),
ruleGapsEscalated: z.array(ruleGapEscalationSchema),
/** Set of rule_ids actually used in this run (for audit + tracking). */
appliedRules: z.array(z.string()),
notes: z.array(z.string()),
});
export type OutputIngestionOutput = z.infer<typeof outputIngestionOutputSchema>;