git_internal/internal/object/mod.rs
1//! Object model definitions for Git blobs, trees, commits, tags, and
2//! AI workflow objects.
3//!
4//! This module is the storage-layer contract for `git-internal`.
5//! Git-native objects (`Blob`, `Tree`, `Commit`, `Tag`) model repository
6//! content, while the AI objects model immutable workflow history that
7//! Libra orchestrates on top.
8//!
9//! # How Libra should use this module
10//!
11//! Libra should treat every AI object here as an immutable record:
12//!
13//! - construct the object in memory,
14//! - populate optional fields before persistence,
15//! - persist it once,
16//! - derive current state later from object history plus Libra
17//! projections.
18//!
19//! Libra should not store scheduler state, selected heads, active UI
20//! focus, or query caches in these objects. Those belong to Libra's own
21//! runtime and index layer.
22//!
23//! AI workflow objects are split into three layers:
24//!
25//! - **Snapshot objects** in `git-internal` answer "what was the stored
26//! fact at this revision?"
27//! - **Event objects** in `git-internal` answer "what happened later?"
28//! - **Libra projections** answer "what is the system's current view?"
29//!
30//! # Relationship Design Standard
31//!
32//! Relationship fields follow a simple storage rule:
33//!
34//! - Store the canonical ownership edge on the child object when the
35//! relationship is a historical fact.
36//! - Low-frequency, strongly aggregated relationships that benefit
37//! from fast parent-to-children traversal may additionally keep a
38//! reverse convenience link.
39//! - High-frequency, high-cardinality, event-stream relationships
40//! should remain single-directional to avoid turning parent objects
41//! into rewrite hotspots.
42//!
43//! # Three-Layer Design
44//!
45//! ```text
46//! +------------------------------------------------------------------+
47//! | Libra projection / runtime |
48//! |------------------------------------------------------------------|
49//! | thread heads / selected_plan_id / active_run / scheduler state |
50//! | live context window / UI focus / query indexes |
51//! +--------------------------------+---------------------------------+
52//! |
53//! v
54//! +------------------------------------------------------------------+
55//! | git-internal event objects |
56//! |------------------------------------------------------------------|
57//! | IntentEvent / TaskEvent / RunEvent / PlanStepEvent / RunUsage |
58//! | ToolInvocation / Evidence / Decision / ContextFrame |
59//! +--------------------------------+---------------------------------+
60//! |
61//! v
62//! +------------------------------------------------------------------+
63//! | git-internal snapshot objects |
64//! |------------------------------------------------------------------|
65//! | Intent / Plan / Task / Run / PatchSet / ContextSnapshot |
66//! | Provenance |
67//! +------------------------------------------------------------------+
68//! ```
69//!
70//! # Main Object Relationships
71//!
72//! ```text
73//! Snapshot layer
74//! ==============
75//!
76//! Intent --parents----------------------------> Intent
77//! Intent --analysis_context_frames-----------> ContextFrame
78//! Plan --intent-----------------------------> Intent
79//! Plan --context_frames---------------------> ContextFrame
80//! Plan --parents----------------------------> Plan
81//! Task --intent?----------------------------> Intent
82//! Task --parent?----------------------------> Task
83//! Task --origin_step_id?-------------------> PlanStep.step_id
84//! Run --task-------------------------------> Task
85//! Run --plan?------------------------------> Plan
86//! Run --snapshot?--------------------------> ContextSnapshot
87//! PatchSet --run----------------------------> Run
88//! Provenance --run_id-------------------------> Run
89//!
90//! Event layer
91//! ===========
92//!
93//! IntentEvent --intent_id-------------------> Intent
94//! IntentEvent --next_intent_id?-------------> Intent
95//! ContextFrame --intent_id?------------------> Intent
96//! TaskEvent --task_id---------------------> Task
97//! RunEvent --run_id----------------------> Run
98//! RunUsage --run_id----------------------> Run
99//! PlanStepEvent --plan_id + step_id + run_id-> Plan / Run / PlanStep
100//! ToolInvocation--run_id----------------------> Run
101//! Evidence --run_id / patchset_id?-------> Run / PatchSet
102//! Decision --run_id / chosen_patchset_id?> Run / PatchSet
103//! ContextFrame --run_id? / plan_id? / step_id?> Run / Plan / PlanStep
104//! ```
105//!
106//! # Libra read / write pattern
107//!
108//! A typical Libra call flow looks like this:
109//!
110//! 1. write snapshot objects when a new immutable revision is defined
111//! (`Intent`, `Plan`, `Task`, `Run`, `PatchSet`, `ContextSnapshot`,
112//! `Provenance`);
113//! 2. append event objects as execution progresses
114//! (`IntentEvent`, `TaskEvent`, `RunEvent`, `PlanStepEvent`,
115//! `RunUsage`, `ToolInvocation`, `Evidence`, `Decision`,
116//! `ContextFrame`);
117//! 3. rebuild current state in Libra from those immutable objects plus
118//! its own `Thread`, `Scheduler`, `UI`, and `Query Index`
119//! projections.
120//!
121//! ## Object Relationship Summary
122//!
123//! | From | Field | To | Cardinality |
124//! |------|-------|----|-------------|
125//! | Intent | `parents` | Intent | 0..N |
126//! | Intent | `analysis_context_frames` | ContextFrame | 0..N |
127//! | Plan | `intent` | Intent | 1 canonical |
128//! | Plan | `parents` | Plan | 0..N |
129//! | Plan | `context_frames` | ContextFrame | 0..N |
130//! | Task | `parent` | Task | 0..1 |
131//! | Task | `intent` | Intent | 0..1 |
132//! | Task | `origin_step_id` | PlanStep.step_id | 0..1 |
133//! | Task | `dependencies` | Task | 0..N |
134//! | Run | `task` | Task | 1 |
135//! | Run | `plan` | Plan | 0..1 |
136//! | Run | `snapshot` | ContextSnapshot | 0..1 |
137//! | PatchSet | `run` | Run | 1 |
138//! | Provenance | `run_id` | Run | 1 |
139//! | IntentEvent | `intent_id` | Intent | 1 |
140//! | IntentEvent | `next_intent_id` | Intent | 0..1 recommended follow-up |
141//! | ContextFrame | `intent_id` | Intent | 0..1 |
142//! | TaskEvent | `task_id` | Task | 1 |
143//! | RunEvent | `run_id` | Run | 1 |
144//! | RunUsage | `run_id` | Run | 1 |
145//! | PlanStepEvent | `plan_id` | Plan | 1 |
146//! | PlanStepEvent | `step_id` | PlanStep.step_id | 1 |
147//! | PlanStepEvent | `run_id` | Run | 1 |
148//! | ToolInvocation | `run_id` | Run | 1 |
149//! | Evidence | `run_id` | Run | 1 |
150//! | Evidence | `patchset_id` | PatchSet | 0..1 |
151//! | Decision | `run_id` | Run | 1 |
152//! | Decision | `chosen_patchset_id` | PatchSet | 0..1 |
153//! | ContextFrame | `run_id` | Run | 0..1 |
154//! | ContextFrame | `plan_id` | Plan | 0..1 |
155//! | ContextFrame | `step_id` | PlanStep.step_id | 0..1 |
156//!
157pub mod blob;
158pub mod commit;
159pub mod context;
160pub mod context_frame;
161pub mod decision;
162pub mod evidence;
163pub mod integrity;
164pub mod intent;
165pub mod intent_event;
166pub mod note;
167pub mod patchset;
168pub mod plan;
169pub mod plan_step_event;
170pub mod provenance;
171pub mod run;
172pub mod run_event;
173pub mod run_usage;
174pub mod signature;
175pub mod tag;
176pub mod task;
177pub mod task_event;
178pub mod tool;
179pub mod tree;
180pub mod types;
181pub mod utils;
182
183use std::{
184 fmt::Display,
185 io::{BufRead, Read},
186};
187
188use crate::{
189 errors::GitError,
190 hash::ObjectHash,
191 internal::{object::types::ObjectType, zlib::stream::inflate::ReadBoxed},
192};
193
194/// **The Object Trait**
195/// Defines the common interface for all Git object types, including blobs, trees, commits, and tags.
196pub trait ObjectTrait: Send + Sync + Display {
197 /// Creates a new object from a byte slice.
198 fn from_bytes(data: &[u8], hash: ObjectHash) -> Result<Self, GitError>
199 where
200 Self: Sized;
201
202 /// Generate a new Object from a `ReadBoxed<BufRead>`.
203 /// the input size,is only for new a vec with directive space allocation
204 /// the input data stream and output object should be plain base object .
205 fn from_buf_read<R: BufRead>(read: &mut ReadBoxed<R>, size: usize) -> Self
206 where
207 Self: Sized,
208 {
209 let mut content: Vec<u8> = Vec::with_capacity(size);
210 read.read_to_end(&mut content).unwrap();
211 let digest = read.hash.clone().finalize();
212 let hash = ObjectHash::from_bytes(&digest).unwrap();
213 Self::from_bytes(&content, hash).unwrap()
214 }
215
216 /// Returns the type of the object.
217 fn get_type(&self) -> ObjectType;
218
219 fn get_size(&self) -> usize;
220
221 fn to_data(&self) -> Result<Vec<u8>, GitError>;
222
223 fn object_hash(&self) -> Result<ObjectHash, GitError> {
224 let data = self.to_data()?;
225 Ok(ObjectHash::from_type_and_data(self.get_type(), &data))
226 }
227}