pub struct Episode {Show 16 fields
pub session_id: String,
pub path: String,
pub provider: String,
pub provider_session: String,
pub owner: String,
pub worker: String,
pub worktree: String,
pub branch: String,
pub start_head: String,
pub started_at: String,
pub standing: EpisodeStanding,
pub events: usize,
pub last_activity: String,
pub last_event: String,
pub tasks: Vec<String>,
pub note: String,
}Expand description
One open episode, as its file records it and as the ledger has seen it.
Everything here is recorded rather than derived, and almost everything is optional,
which is the point: an episode opened by hand has no provider, a worker that supplied no
identity has none, and an episode that opened and did nothing has no ledger line and so
no last_activity. Each of those is ordinary and none is a fault, so each is carried as
absence — the empty fields are skipped on the wire — and a reader must handle their
absence rather than expect a placeholder.
The two fields that are always there are standing and note: where the episode stands,
and why it stands there in words. A standing a reader cannot act on is the failure this
subsystem was corrected for, so note is never empty.
use majordomus_cli::capability::builtin::lifecycle::{Episode, EpisodeStanding};
use serde_json::json;
// the smallest true record: an episode opened by hand that has written nothing yet
let e: Episode = serde_json::from_value(json!({
"session_id": "s-0001",
"path": ".ai/local/state/sessions-open/by-hand.yaml",
"standing": "open",
"events": 0,
"note": "open in this worktree; the pointer names another episode",
})).unwrap();
assert_eq!(e.standing, EpisodeStanding::Open);
assert!(e.provider.is_empty(), "no provider session owns a hand-opened episode");
assert!(e.last_activity.is_empty(), "it has written no ledger line");
assert!(e.tasks.is_empty(), "work outside a task is permitted");
assert!(!e.note.is_empty(), "a standing always says why");
// and absence stays absence: the empty fields are not serialised back as ""
let wire = serde_json::to_value(&e).unwrap();
assert!(wire.get("provider").is_none());
assert_eq!(wire["events"], 0, "a count of zero is a measurement, so it is kept");Fields§
§session_id: StringThe episode id the ledger stamps on every line this worker wrote.
path: StringRepository-relative path of the open record. The body is at the path.
provider: StringThe provider whose event opened it, when one did. Empty for an episode opened by hand, which is the one episode no provider session owns.
provider_session: StringThat provider’s own session identity: the file’s stem, and the string the prompt archive stamps on the same worker’s records.
owner: StringWho opened it.
worker: StringThe worker identity, when one was supplied. Never inferred.
worktree: StringThe worktree it opened in, absolute, as recorded.
branch: StringThe branch it opened on.
start_head: StringThe commit it opened at.
started_at: StringWhen it opened, as recorded.
standing: EpisodeStandingWhere it stands.
events: usizeHow many ledger lines carry this episode id. Zero for an episode that opened and did nothing, which is ordinary and not a fault.
last_activity: StringThe timestamp of the newest ledger line carrying this episode id, as recorded. Empty when it has written none.
last_event: StringThat line’s event name.
tasks: Vec<String>The tasks this episode’s ledger lines name, in the order it first touched each.
A relation, not a container. An episode may touch three tasks or none, and a task may span three episodes; the two are joined here by what the ledger recorded rather than by either one owning the other. An episode with no task is ordinary — work outside a task is permitted — and it is emphatically not a reason for the episode’s own records to go unwritten, which is the premise ADR 0052 removes.
note: StringWhy it stands where it does, in words. Never empty: a standing a reader cannot act on is the failure this subsystem is being corrected for.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Episode
impl<'de> Deserialize<'de> for Episode
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for Episode
Source§impl JsonSchema for Episode
impl JsonSchema for Episode
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn inline_schema() -> bool
fn inline_schema() -> bool
$ref keyword. Read moreimpl StructuralPartialEq for Episode
Auto Trait Implementations§
impl Freeze for Episode
impl RefUnwindSafe for Episode
impl Send for Episode
impl Sync for Episode
impl Unpin for Episode
impl UnsafeUnpin for Episode
impl UnwindSafe for Episode
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.