pub fn tasks_from_ledger(
entries: &[Entry],
providers: &BTreeMap<String, (String, String)>,
) -> Vec<IntentWorkUnit>Expand description
The tasks of a ledger, each with every episode that worked on it, the provider of each
episode where a record names one, the handovers that carried it, and the issues its episodes
moved. providers maps an episode to its provider and provider session, as the open episode
files name them; the ledger’s own provider events add to it.
A plan transition is attributed to the task whose event last preceded it in the same episode, so an episode that ran two tasks in turn does not credit the first with the second’s issues.
use majordomus_cli::intent_realization::tasks_from_ledger;
use majordomus_cli::ledger::Entry;
let line = |s: &str| serde_json::from_str::<Entry>(s).unwrap();
let env = r#""head":"h","by":"majordomus/0""#;
let entries = vec![
line(&format!(r#"{{"ts":"1","event":"task.started",{env},"branch":"m","session":"s-a",
"task_id":"t-1","scope":"lib docs"}}"#)),
line(&format!(r#"{{"ts":"2","event":"provider.event.received",{env},"branch":"m",
"session":"s-a","provider":"claude-code","provider_session":"x"}}"#)),
line(&format!(r#"{{"ts":"3","event":"task.handed_over",{env},"branch":"m","session":"s-a",
"task_id":"t-1","handover_path":"h.md"}}"#)),
line(&format!(r#"{{"ts":"4","event":"plan_start",{env},"branch":"m","session":"s-b",
"issue":"I0001"}}"#)),
line(&format!(r#"{{"ts":"5","event":"task.checkpoint",{env},"branch":"m","session":"s-b",
"task_id":"t-1"}}"#)),
line(&format!(r#"{{"ts":"6","event":"plan_done",{env},"branch":"m","session":"s-b",
"issue":"I0002"}}"#)),
];
let tasks = tasks_from_ledger(&entries, &Default::default());
let t = &tasks[0];
assert_eq!(t.scope, ["lib", "docs"]);
assert_eq!(t.handovers, ["h.md"]);
assert_eq!(t.providers(), ["claude-code"]);
// I0001 moved before t-1 was resumed in s-b, so only I0002 is its own
assert_eq!(t.moved_issues, ["I0002"]);
assert_eq!(t.outcome, "active");