codetether_agent/session/tasks/event/task_event.rs
1//! Serialized session task-log events.
2
3use super::{GoalSourceKind, SessionTaskStatus};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6/// A single durable event in the session task log.
7///
8/// `TaskEvent` is the append-only record format for session goal governance and
9/// task lifecycle tracking. Each variant captures one fact that happened at a
10/// specific UTC timestamp. The current materialized task state is reconstructed
11/// by replaying these events in order, rather than by editing earlier records.
12///
13/// Events are serialized with an internally tagged Serde representation. The
14/// `kind` field stores the variant name in `snake_case`, which keeps persisted
15/// JSONL task logs readable and stable across releases.
16#[derive(Clone, Debug, Serialize, Deserialize)]
17#[serde(tag = "kind", rename_all = "snake_case")]
18pub enum TaskEvent {
19 /// Declares or replaces the active session goal.
20 ///
21 /// A goal contains the objective the agent should pursue, optional
22 /// completion criteria, explicit forbidden behaviors, and provenance fields
23 /// describing where the objective came from. When this event is folded into
24 /// task state, it supersedes any previously active goal.
25 GoalSet {
26 /// Time at which the goal was declared.
27 at: DateTime<Utc>,
28 /// Human-readable objective the agent should work toward.
29 objective: String,
30 /// Criteria that indicate the objective has been satisfied.
31 ///
32 /// Defaults to an empty list when omitted by older log entries or simple
33 /// goal-setting paths.
34 #[serde(default)]
35 success_criteria: Vec<String>,
36 /// Actions or behaviors that are explicitly out of scope.
37 ///
38 /// Defaults to an empty list when no additional forbidden behaviors were
39 /// recorded.
40 #[serde(default)]
41 forbidden: Vec<String>,
42 /// Identifier of the session containing the source evidence for this
43 /// goal.
44 ///
45 /// Empty when the producer did not capture a source session.
46 #[serde(default)]
47 source_session_id: String,
48 /// Turn identifier or turn index within the source session.
49 ///
50 /// Empty when the goal is not anchored to a specific raw transcript
51 /// turn.
52 #[serde(default)]
53 source_turn_id: String,
54 /// Hash of the source text used to derive the goal.
55 ///
56 /// This allows provenance comparisons without duplicating the full
57 /// source text in every event.
58 #[serde(default)]
59 source_text_hash: String,
60 /// Category describing how the goal was derived.
61 ///
62 /// Consumers can use this to distinguish strong provenance, such as raw
63 /// transcript turns or direct user input, from weaker provenance, such
64 /// as summarized recall, durable memory, or inference.
65 #[serde(default)]
66 source_kind: GoalSourceKind,
67 /// Producer-supplied confidence in the recorded provenance.
68 ///
69 /// `1.0` means the goal is directly supported by the recorded source
70 /// evidence. `0.0` means no confidence was supplied or the goal should be
71 /// treated as unverified.
72 #[serde(default)]
73 confidence: f32,
74 },
75 /// Records that the agent reaffirmed alignment with the active goal.
76 ///
77 /// Reaffirmation does not change the objective. It stores a progress note so
78 /// governance logic can reset drift counters and later explain why work
79 /// continued.
80 GoalReaffirmed {
81 /// Time at which the reaffirmation was recorded.
82 at: DateTime<Utc>,
83 /// Concise statement of completed work, remaining work, or the current
84 /// blocker.
85 progress_note: String,
86 },
87 /// Clears the active session goal.
88 ///
89 /// Folding the log after this event leaves the session without an active
90 /// goal until a later [`TaskEvent::GoalSet`] appears.
91 GoalCleared { at: DateTime<Utc>, reason: String },
92 /// Adds a task to the session task list.
93 ///
94 /// Added tasks start as pending in folded state. Later
95 /// [`TaskEvent::TaskStatus`] events update tasks by matching the `id` field.
96 TaskAdded {
97 /// Time at which the task was added.
98 at: DateTime<Utc>,
99 /// Stable identifier for this task within the session task log.
100 id: String,
101 /// Human-readable task description.
102 content: String,
103 /// Optional parent task identifier for nested task breakdowns.
104 ///
105 /// Defaults to `None` for top-level tasks and older log entries.
106 #[serde(default)]
107 parent_id: Option<String>,
108 },
109 /// Updates the lifecycle status of an existing task.
110 ///
111 /// Folding logic applies this transition to the task with the matching `id`
112 /// when that task exists in the materialized task map. The event remains in
113 /// the append-only log even if the task is missing.
114 TaskStatus {
115 /// Time at which the status transition was recorded.
116 at: DateTime<Utc>,
117 /// Identifier of the task being updated.
118 id: String,
119 /// New lifecycle status for the task.
120 status: SessionTaskStatus,
121 /// Optional note explaining the transition, such as a blocker,
122 /// cancellation reason, or completion summary.
123 #[serde(default)]
124 note: Option<String>,
125 },
126 /// Records that governance detected possible drift from the active goal.
127 ///
128 /// Drift events preserve the counters that triggered an alignment warning,
129 /// allowing later inspection to understand why the agent was asked to
130 /// reaffirm the goal or stop before continuing.
131 DriftDetected {
132 /// Time at which drift was detected.
133 at: DateTime<Utc>,
134 /// Number of tool calls since the last goal reaffirmation.
135 tool_calls_since_reaffirm: u32,
136 /// Number of errors since the last goal reaffirmation.
137 errors_since_reaffirm: u32,
138 },
139}