BID · Console
Baseline · Intelligence · Decision
src/agents/decision/output-ingestion/schema.ts 3,113 bytes · typescript
/**
 * 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>;