返回 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 //! Session persistence, legacy import, UI projections, and liveness adapters
17 //! are wired: `session_manager` stores a snapshot, `tools/shell` and
18 //! `tools/tasks` observe operations, and the engine records owner liveness.
19 #![allow(dead_code)]
20 #![allow(unused_imports)]
21
22 mod compat;
23 mod digest;
24 mod events;
25 mod ids;
26 mod liveness;
27 mod migration;
28 mod model;
29 mod reducer;
30 mod runtime;
31 mod validate;
32
33 #[cfg(test)]
34 mod tests;
35
36 pub use compat::{PlanProjection, TodoProjection, project_plan, project_todos};
37 pub use digest::{format_operation_digest, format_operation_digest_parts};
38 pub use events::{
39 ApprovalRef, CancelOutcome, ChangeCtx, ChangeReceipt, ObservationSummary, OperationObservation,
40 OwnerState, ProposedNodeUpdate, WorkGraphChange, WorkGraphProposal, WorkNodePatch,
41 };
42 pub use ids::{BindingId, ChangeId, ProposalId, WorkEdgeId, WorkNodeId};
43 pub use liveness::{
44 OperationIntent, OperationOwnerSnapshot, fleet_task_owner_snapshot, lane_owner_snapshot,
45 task_owner_snapshot,
46 };
47 pub use migration::import_legacy;
48 pub(crate) use model::constrained_effective_reasoning_for_route;
49 pub use model::{
50 ACTIVITY_CAP, AcceptanceRequirement, BoundedSet, BoundedVec, CompatPlanMetadata,
51 CompatProjectionState, CompatTodoBinding, EdgeKind, EvidenceKind, EvidenceKindTag, EvidenceRef,
52 EvidenceRefError, HISTORY_CAP, IdempotencyKey, NodeKind, NodeState, OperationBinding,
53 Provenance, ReasoningEffortTier, SCHEMA_VERSION, SEEN_KEYS_CAP, Ts, WorkActivityEvent,
54 WorkEdge, WorkGraphSnapshot, WorkNode, external_identity_is_well_formed,
55 };
56 pub use reducer::apply;
57 pub(crate) use runtime::{ACTIVE_OPERATION_SUMMARY_END, ACTIVE_OPERATION_SUMMARY_START};
58 pub use runtime::{SharedWorkRuntime, WorkRuntime, WorkRuntimeSnapshot, new_shared_work_runtime};
59 pub use validate::{ValidationCode, ValidationReport, Violation, validate};
60
61 /// Convenience wrapper owning the current snapshot. [`WorkGraph::apply`]
62 /// commits the reducer's result on success and leaves the snapshot untouched
63 /// on rejection — the fail-closed contract, packaged.
64 #[derive(Debug, Clone, PartialEq)]
65 pub struct WorkGraph {
66 snapshot: WorkGraphSnapshot,
67 }
68
69 impl WorkGraph {
70 #[must_use]
71 pub fn new() -> Self {
72 Self {
73 snapshot: WorkGraphSnapshot::new(),
74 }
75 }
76
77 #[must_use]
78 pub fn from_snapshot(snapshot: WorkGraphSnapshot) -> Self {
79 Self { snapshot }
80 }
81
82 #[must_use]
83 pub fn snapshot(&self) -> &WorkGraphSnapshot {
84 &self.snapshot
85 }
86
87 #[must_use]
88 pub fn into_snapshot(self) -> WorkGraphSnapshot {
89 self.snapshot
90 }
91
92 /// Apply one change through the reducer. On `Ok` the new snapshot is
93 /// committed; on `Err` the held snapshot is unchanged.
94 pub fn apply(
95 &mut self,
96 change: WorkGraphChange,
97 ctx: ChangeCtx,
98 ) -> Result<ChangeReceipt, ValidationReport> {
99 let (next, receipt) = reducer::apply(&self.snapshot, change, ctx)?;
100 self.snapshot = next;
101 Ok(receipt)
102 }
103 }
104
105 impl Default for WorkGraph {
106 fn default() -> Self {
107 Self::new()
108 }
109 }
110
110 lines RUST