Skip to main content

origin_types/
onboarding.rs

1// SPDX-License-Identifier: Apache-2.0
2//! Onboarding milestone wire types. Shared with origin-mcp + origin-app.
3
4use serde::{Deserialize, Serialize};
5use std::str::FromStr;
6
7/// Canonical identifier for each onboarding milestone. The string form
8/// (produced by `as_str`, `FromStr`, and serde's kebab-case rename) is
9/// the single source of truth for (a) the DB primary key, (b) the JSON
10/// wire format, (c) `MilestoneRecord.id`. All four forms must stay in sync --
11/// the round-trip test in this module enforces that.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13#[serde(rename_all = "kebab-case")]
14pub enum MilestoneId {
15    IntelligenceReady,
16    FirstMemory,
17    FirstRecall,
18    /// Wire format preserved as "first-concept" until 0c.2/0c.3 DB/API rename pass.
19    #[serde(rename = "first-concept")]
20    FirstPage,
21    GraphAlive,
22    SecondAgent,
23}
24
25impl MilestoneId {
26    pub fn as_str(&self) -> &'static str {
27        match self {
28            MilestoneId::IntelligenceReady => "intelligence-ready",
29            MilestoneId::FirstMemory => "first-memory",
30            MilestoneId::FirstRecall => "first-recall",
31            MilestoneId::FirstPage => "first-concept",
32            MilestoneId::GraphAlive => "graph-alive",
33            MilestoneId::SecondAgent => "second-agent",
34        }
35    }
36}
37
38impl FromStr for MilestoneId {
39    type Err = String;
40    fn from_str(s: &str) -> Result<Self, Self::Err> {
41        match s {
42            "intelligence-ready" => Ok(MilestoneId::IntelligenceReady),
43            "first-memory" => Ok(MilestoneId::FirstMemory),
44            "first-recall" => Ok(MilestoneId::FirstRecall),
45            "first-concept" => Ok(MilestoneId::FirstPage),
46            "graph-alive" => Ok(MilestoneId::GraphAlive),
47            "second-agent" => Ok(MilestoneId::SecondAgent),
48            _ => Err(format!("unknown milestone id: {}", s)),
49        }
50    }
51}
52
53/// A recorded milestone, returned by DB queries and API endpoints.
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct MilestoneRecord {
56    pub id: MilestoneId,
57    pub first_triggered_at: i64,
58    pub acknowledged_at: Option<i64>,
59    /// Optional JSON payload (e.g. concept_id, agent_name).
60    pub payload: Option<serde_json::Value>,
61}