Skip to main content

pointlock_store/projection/
mod.rs

1//! The projection protocol (spine §10, R14): renderer-agnostic read-only
2//! DTOs — the ONLY contract between any renderer and the store.
3//!
4//! Five closed DTO families (spine §10.1): [`FlowGraphView`] (from FlowIR),
5//! [`RunTimelineEntry`] (from RunLog), [`StepDossierView`] (= the
6//! `pointlock locate` JSON shape), [`HumanInboxEntry`] (from the
7//! humanRequested/humanResponded pairing), and [`RunOverview`] (run
8//! summary + `revision` + per-step state map). Every top-level DTO carries
9//! `projectionVersion: 1`; evolution is additive-only, breaking changes
10//! bump the version, and the version is independent of `irVersion`
11//! (spine §10.3).
12//!
13//! Discipline (08 §1 iron law 1, typed here): projections fold ledger
14//! facts, they never judge — every verdict/state below is what the runner
15//! recorded. No coordinates, no layout, no React Flow concepts
16//! (spine §10.1/§10.5): rendering concerns stay in the renderer.
17
18mod dossier;
19mod graph;
20mod inbox;
21mod overview;
22mod schema;
23mod timeline;
24
25pub use dossier::{
26    AttemptView, FrameEnvironment, HandlerTriggerView, SourceLocation, StepDossierView,
27    VerdictRecordView, locate_step, step_dossier,
28};
29pub use graph::{
30    AssertionSummary, FlowGraphView, GraphEdge, GraphEdgeKind, GraphNode, GraphNodeBody, HookBadge,
31    NodeRegion, flow_graph_view,
32};
33pub use inbox::{HumanInboxEntry, human_inbox, run_inbox};
34pub use overview::{AlignmentSummary, RunOverview, StepStateSummary, run_overview};
35pub use schema::{
36    PROJECTION_SCHEMA_FAMILIES, ProjectionSchemaFamily, projection_schema, projection_schemas,
37};
38pub use timeline::{
39    BoundedValue, RunTimelineEntry, RunTimelineFilter, TIMELINE_EVIDENCE_MAX,
40    TIMELINE_JSON_MAX_BYTES, TIMELINE_JSON_MAX_DEPTH, TIMELINE_MAX_PAGE_SIZE,
41    TIMELINE_TEXT_MAX_BYTES, TimelineDetail, TimelineErrorView, TimelineEvidenceRef, TimelinePage,
42    timeline_page,
43};
44
45use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
46use serde::{Deserialize, Serialize};
47use std::borrow::Cow;
48
49/// The projection-protocol version marker, pinned to the JSON number `1`
50/// (spine §10.3). Additive evolution keeps the value; breaking changes
51/// bump it. Independent of `irVersion` — the projection is a read-side
52/// contract and never touches IR or checkpoint semantics.
53#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
54pub struct ProjectionVersion;
55
56impl ProjectionVersion {
57    /// The numeric value of this version marker.
58    pub const VALUE: u64 = 1;
59}
60
61impl Serialize for ProjectionVersion {
62    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
63        serializer.serialize_u64(Self::VALUE)
64    }
65}
66
67impl<'de> Deserialize<'de> for ProjectionVersion {
68    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
69        let value = u64::deserialize(deserializer)?;
70        if value == Self::VALUE {
71            Ok(ProjectionVersion)
72        } else {
73            Err(serde::de::Error::custom(format!(
74                "unsupported projectionVersion {value}: this crate implements projectionVersion {}",
75                Self::VALUE
76            )))
77        }
78    }
79}
80
81impl JsonSchema for ProjectionVersion {
82    fn inline_schema() -> bool {
83        true
84    }
85    fn schema_name() -> Cow<'static, str> {
86        Cow::Borrowed("ProjectionVersion")
87    }
88    fn schema_id() -> Cow<'static, str> {
89        Cow::Borrowed("pointlock_store::projection::ProjectionVersion")
90    }
91    fn json_schema(_generator: &mut SchemaGenerator) -> Schema {
92        json_schema!({ "const": 1 })
93    }
94}