返回 CodeWhale
mod.rs
根目录 / crates / tui / src / work_graph / mod.rs
1 //! Work Graph — the single authoritative work ledger for a session.
2 //!
3 //! One graph carries objectives, plan steps, operations, evidence, blockers,
4 //! and approvals. **Invariant: one graph writes every projection; projections
5 //! never write each other.** Plan and todo views, work-surface rows, and the
6 //! inspector all derive from [`WorkGraphSnapshot`] through pure functions.
7 //!
8 //! Why a graph instead of parallel trackers: flat status lists let an agent
9 //! mark work "done" by assertion, lose dependency structure, and cannot say
10 //! what evidence backed a completion. Here completion and verification are
11 //! distinct states, `Verified` is unreachable without a satisfying evidence
12 //! path (V4, fail-closed), dependencies are first-class edges (acyclic, V1),
13 //! and liveness truth stays with the owning subsystems — the graph records
14 //! observations, it never invents them.
15 //!
16 //! This slice is the core only: model, changes, pure reducer, validation.
17 //! Session persistence, legacy import, UI projections, and liveness adapters
18 //! land in later slices; nothing in the app or engine calls this yet.
19 // Staged cutover: later slices wire persistence, UI, and liveness; until
20 // then the public surface (including re-exports) has no external callers.
21 #![allow(dead_code)]
22 #![allow(unused_imports)]
23
24 mod compat;
25 mod digest;
26 mod events;
27 mod ids;
28 mod liveness;
29 mod migration;
30 mod model;
31 mod reducer;
32 mod runtime;
33 mod validate;
34
35 #[cfg(test)]
36 mod tests;
37
38 pub use compat::{PlanProjection, TodoProjection, project_plan, project_todos};
39 pub use digest::{format_operation_digest, format_operation_digest_parts};
40 pub use events::{
41 ApprovalRef, CancelOutcome, ChangeCtx, ChangeReceipt, ObservationSummary, OperationObservation,
42 OwnerState, ProposedNodeUpdate, WorkGraphChange, WorkGraphProposal, WorkNodePatch,
43 };
44 pub use ids::{BindingId, ChangeId, ProposalId, WorkEdgeId, WorkNodeId};
45 pub use liveness::{
46 OperationIntent, OperationOwnerSnapshot, fleet_task_owner_snapshot, lane_owner_snapshot,
47 task_owner_snapshot,
48 };
49 pub use migration::import_legacy;
50 pub(crate) use model::constrained_effective_reasoning_for_route;
51 pub use model::{
52 ACTIVITY_CAP, AcceptanceRequirement, BoundedSet, BoundedVec, CompatPlanMetadata,
53 CompatProjectionState, CompatTodoBinding, EdgeKind, EvidenceKind, EvidenceKindTag, EvidenceRef,
54 EvidenceRefError, HISTORY_CAP, IdempotencyKey, NodeKind, NodeState, OperationBinding,
55 Provenance, ReasoningEffortTier, SCHEMA_VERSION, SEEN_KEYS_CAP, Ts, WorkActivityEvent,
56 WorkEdge, WorkGraphSnapshot, WorkNode, external_identity_is_well_formed,
57 };
58 pub use reducer::apply;
59 pub(crate) use runtime::{ACTIVE_OPERATION_SUMMARY_END, ACTIVE_OPERATION_SUMMARY_START};
60 pub use runtime::{SharedWorkRuntime, WorkRuntime, WorkRuntimeSnapshot, new_shared_work_runtime};
61 pub use validate::{ValidationCode, ValidationReport, Violation, validate};
62
63 /// Convenience wrapper owning the current snapshot. [`WorkGraph::apply`]
64 /// commits the reducer's result on success and leaves the snapshot untouched
65 /// on rejection — the fail-closed contract, packaged.
66 #[derive(Debug, Clone, PartialEq)]
67 pub struct WorkGraph {
68 snapshot: WorkGraphSnapshot,
69 }
70
71 impl WorkGraph {
72 #[must_use]
73 pub fn new() -> Self {
74 Self {
75 snapshot: WorkGraphSnapshot::new(),
76 }
77 }
78
79 #[must_use]
80 pub fn from_snapshot(snapshot: WorkGraphSnapshot) -> Self {
81 Self { snapshot }
82 }
83
84 #[must_use]
85 pub fn snapshot(&self) -> &WorkGraphSnapshot {
86 &self.snapshot
87 }
88
89 #[must_use]
90 pub fn into_snapshot(self) -> WorkGraphSnapshot {
91 self.snapshot
92 }
93
94 /// Apply one change through the reducer. On `Ok` the new snapshot is
95 /// committed; on `Err` the held snapshot is unchanged.
96 pub fn apply(
97 &mut self,
98 change: WorkGraphChange,
99 ctx: ChangeCtx,
100 ) -> Result<ChangeReceipt, ValidationReport> {
101 let (next, receipt) = reducer::apply(&self.snapshot, change, ctx)?;
102 self.snapshot = next;
103 Ok(receipt)
104 }
105 }
106
107 impl Default for WorkGraph {
108 fn default() -> Self {
109 Self::new()
110 }
111 }
112
112 lines RUST