origin_types/pages.rs
1// SPDX-License-Identifier: Apache-2.0
2//! Wire types for compiled knowledge pages.
3
4use serde::{Deserialize, Serialize};
5
6/// A compiled knowledge page — structured, cross-referenced, backed by source memories.
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct Page {
9 pub id: String,
10 pub title: String,
11 pub summary: Option<String>,
12 pub content: String,
13 pub entity_id: Option<String>,
14 #[serde(default, alias = "domain")]
15 pub space: Option<String>,
16 /// Kept for dual-write transition; prefer concept_sources join table for new reads.
17 pub source_memory_ids: Vec<String>,
18 pub version: i64,
19 pub status: String,
20 pub created_at: String,
21 pub last_compiled: String,
22 pub last_modified: String,
23 /// How many source memories were updated since last distillation.
24 pub sources_updated_count: i64,
25 /// Why this page is stale: "source_updated" | "source_conflict" | None.
26 pub stale_reason: Option<String>,
27 /// True if a human has edited this page's content directly.
28 pub user_edited: bool,
29 /// Relevance score from search (0.0-1.0). Only populated by `search_pages`;
30 /// zero for persisted/non-search contexts.
31 #[serde(default, skip_serializing_if = "is_zero_f32")]
32 pub relevance_score: f32,
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub last_edited_by: Option<String>,
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub last_edited_at: Option<i64>,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 pub last_delta_summary: Option<String>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 pub changelog: Option<String>,
41 /// Scope axis (P3). Distinct from `space` (category column). Set at creation
42 /// time from `CreateConceptRequest.workspace` or the `X-Origin-Space` header.
43 /// NULL = no workspace constraint. Enforced only by the scoped-recall page gate
44 /// on the cross-rerank search path; direct page lookups (search_pages MCP tool,
45 /// exports) do not filter by workspace.
46 #[serde(default)]
47 pub workspace: Option<String>,
48 /// Routing metadata: which mechanism created this page.
49 /// One of: "distilled" | "authored" | "research" | "imported".
50 /// NOT a trust signal (see `review_status` for that).
51 #[serde(default = "default_creation_kind")]
52 pub creation_kind: String,
53 /// Trust boundary: whether this page has been confirmed as accurate.
54 /// One of: "unconfirmed" | "confirmed".
55 /// Distilled pages start confirmed; authored/research pages start unconfirmed.
56 #[serde(default = "default_review_status")]
57 pub review_status: String,
58}
59
60fn default_creation_kind() -> String {
61 "distilled".to_string()
62}
63
64fn default_review_status() -> String {
65 "confirmed".to_string()
66}
67
68fn is_zero_f32(v: &f32) -> bool {
69 *v == 0.0
70}
71
72/// Typed provenance link for a page (P2 successor to `PageSource`).
73/// Backed by the `page_evidence` SQL table (migration 60).
74/// Additive — `PageSource` / `page_sources` are NOT removed.
75#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
76pub struct PageEvidence {
77 pub page_id: String,
78 pub source_kind: String, // memory | external_url | external_file | authored
79 pub locator: Option<String>,
80 pub title: Option<String>,
81 pub linked_at: i64,
82 pub link_reason: Option<String>,
83}