Skip to main content

katgpt_types/
inference.rs

1//! Inference result + proposer/gate types.
2
3#[cfg(feature = "sr2am_configurator")]
4use super::PlanningDecision;
5
6// ---------------------------------------------------------------------------
7// InferenceResult
8// ---------------------------------------------------------------------------
9
10/// Output of a single inference pass, with reward signal for feedback loop.
11///
12/// Fields ordered by descending alignment to minimize padding:
13/// u64/i64/usize/String (8-byte) → f32 (4-byte) → Option<#[repr(u8)]> (2-byte) → u8/bool (1-byte).
14#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
15pub struct InferenceResult {
16    // --- 8-byte aligned ---
17    /// Input prompt hash (for dedup, not stored).
18    pub prompt_hash: u64,
19    /// Timestamp (Uuid v7 prefix).
20    pub timestamp: i64,
21    /// Number of nodes explored in DDTree.
22    pub tree_budget_used: usize,
23    /// Actual planning horizon used this turn (after entropy truncation, Plan 112 T13).
24    #[cfg(feature = "sr2am_configurator")]
25    pub plan_horizon_used: usize,
26    /// Domain that handled this inference.
27    pub domain: String,
28    /// Generated output text.
29    pub output: String,
30
31    // --- 4-byte aligned ---
32    /// Best-path reward (max relevance score from WasmPruner).
33    pub reward: f32,
34
35    // --- 2-byte aligned (Option<#[repr(u8)] enum>) ---
36    /// SR²AM configurator planning decision for this turn (Plan 112).
37    #[cfg(feature = "sr2am_configurator")]
38    pub planning_decision: Option<PlanningDecision>,
39
40    // --- 1-byte fields (tail-packed) ---
41    /// Was this result screened out (reward below threshold)?
42    pub screened: bool,
43    /// Inference budget level (0=cheap, 1=moderate, 2=expensive).
44    pub budget_level: u8,
45}
46
47// ---------------------------------------------------------------------------
48// Data Gate — Self-Play Stability (Plan 111, Research 075)
49// ---------------------------------------------------------------------------
50
51/// Discriminator for different self-play task types.
52#[cfg(feature = "data_gate")]
53#[derive(Debug, Clone, Copy, PartialEq, Eq)]
54#[repr(u8)]
55pub enum TaskType {
56    /// Python code output prediction
57    CodeIO,
58    /// DSL expression evaluation
59    DslExpr,
60    /// Game action (Bomber, Go, FFT, Monopoly)
61    GameAction,
62    /// Open-ended generation
63    OpenEnded,
64}
65
66/// A task proposed by the self-play proposer, before solver evaluation.
67#[cfg(feature = "data_gate")]
68#[derive(Debug, Clone)]
69pub struct ProposerTask {
70    /// Task identifier for diagnostics.
71    pub id: usize,
72    /// The problem/query text.
73    pub query: String,
74    /// Optional code or DSL expression to execute.
75    pub program: Option<String>,
76    /// Optional input for the program.
77    pub program_input: Option<String>,
78    /// Task type discriminator.
79    pub task_type: TaskType,
80}
81
82/// Gate admission decision.
83///
84/// Decides whether a proposer-generated task should enter the training pool
85/// BEFORE the solver attempts it.
86#[cfg(feature = "data_gate")]
87#[repr(u8)]
88#[derive(Debug, Clone, PartialEq, Eq)]
89pub enum GateDecision {
90    /// Task passes the gate — admitted to training pool.
91    Admit,
92    /// Task rejected with reason.
93    Reject(String),
94}
95
96/// Task-level admission gate for self-play training pool.
97///
98/// Decides whether a proposer-generated task should enter the training pool
99/// BEFORE the solver attempts it. This is the binding constraint for self-play
100/// stability (Survive or Collapse, Pu et al. 2026).
101///
102/// Key finding: a strict gate is sufficient for stability under every reward
103/// variant; no reward variant is sufficient once the gate is removed.
104#[cfg(feature = "data_gate")]
105pub trait DataGate {
106    /// Admit or reject a proposed task.
107    ///
108    /// Returns `GateDecision::Admit` if the task passes the gate,
109    /// `GateDecision::Reject(reason)` if not.
110    fn admit(&self, task: &ProposerTask) -> GateDecision;
111
112    /// Current leak rate ε (fraction of failed tasks admitted).
113    /// ε=0 means strict gate (optimal). ε=1 means gate off (collapse).
114    fn leak_rate(&self) -> f32;
115}