pub fn append(
root: &Path,
vocabulary: &Vocabulary,
git: &GitState,
now: &str,
event: &str,
payload: &[Field<'_>],
) -> Result<String, LedgerError>Expand description
Append one line to the ledger of root.
The line is composed in full, validated against the vocabulary, and only then appended.
now is passed in rather than read here so that a test can write a line whose timestamp
it knows; every caller in the executable passes now.
use majordomus_cli::git::GitState;
use majordomus_cli::ledger::{self, Vocabulary};
let vocabulary = Vocabulary::load(&dir.join("events.yaml")).unwrap();
let git = GitState::Unavailable { reason: "not a work tree".into() };
let line = ledger::append(&dir, &vocabulary, &git, "2026-09-11T12:00:00Z",
"plan_done", &[("issue", "I0001".into())]).unwrap();
// Where git cannot answer, the two fields are spelled with the literals the shell uses,
// so a reader never meets a second spelling of "unknown".
assert!(line.contains(r#""head":"NONE""#), "{line}");
assert!(line.contains(r#""branch":"DETACHED""#), "{line}");
// A declared event whose payload omits a required key writes nothing at all.
let err = ledger::append(&dir, &vocabulary, &git, "2026-09-11T12:00:00Z",
"plan_done", &[]).unwrap_err();
assert_eq!(err.to_string(), "event 'plan_done' is missing the required field 'issue'");
assert_eq!(ledger::read(&dir).0.len(), 1, "the refusal appended nothing");