use chrono::NaiveDateTime;
use serde_json::{Value, json};
pub use crate::engine::TRIGGER_KEY;
pub struct TriggerFacts<'a> {
pub channel_name: &'a str,
pub trigger_type: &'a str,
pub occurrence_id: &'a str,
pub scheduled_for: NaiveDateTime,
pub started_at: NaiveDateTime,
pub timezone: &'a str,
pub attempt: i64,
pub singleton_key: Option<&'a str>,
}
pub fn occurrence_metadata(facts: TriggerFacts<'_>, vars: Option<&Value>) -> Value {
let mut metadata = json!({
"channel": facts.channel_name,
TRIGGER_KEY: {
"type": facts.trigger_type,
"occurrence_id": facts.occurrence_id,
"scheduled_for": facts.scheduled_for.and_utc().to_rfc3339(),
"started_at": facts.started_at.and_utc().to_rfc3339(),
"timezone": facts.timezone,
"attempt": facts.attempt,
},
});
if let Some(key) = facts.singleton_key {
metadata[TRIGGER_KEY]["singleton_key"] = json!(key);
}
crate::engine::clear_error_context(&mut metadata);
crate::engine::stamp_vars(&mut metadata, vars);
metadata
}
#[cfg(test)]
mod tests {
use super::*;
use chrono::NaiveDate;
fn at(hh: u32, mm: u32) -> NaiveDateTime {
NaiveDate::from_ymd_opt(2026, 9, 5)
.expect("date")
.and_hms_opt(hh, mm, 0)
.expect("time")
}
fn facts() -> TriggerFacts<'static> {
TriggerFacts {
channel_name: "nightly-rollup",
trigger_type: "cron",
occurrence_id: "occ-1",
scheduled_for: at(2, 15),
started_at: at(2, 15),
timezone: "Asia/Kolkata",
attempt: 1,
singleton_key: None,
}
}
#[test]
fn the_trigger_object_carries_the_occurrences_identity() {
let metadata = occurrence_metadata(facts(), None);
assert_eq!(metadata["channel"], "nightly-rollup");
assert_eq!(metadata["trigger"]["type"], "cron");
assert_eq!(metadata["trigger"]["occurrence_id"], "occ-1");
assert_eq!(
metadata["trigger"]["scheduled_for"],
"2026-09-05T02:15:00+00:00"
);
assert_eq!(metadata["trigger"]["timezone"], "Asia/Kolkata");
assert_eq!(metadata["trigger"]["attempt"], 1);
assert!(metadata["trigger"].get("singleton_key").is_none());
}
#[test]
fn a_late_run_reports_both_instants() {
let metadata = occurrence_metadata(
TriggerFacts {
started_at: at(6, 30),
attempt: 3,
singleton_key: Some("order-pipeline"),
..facts()
},
None,
);
assert_eq!(
metadata["trigger"]["scheduled_for"],
"2026-09-05T02:15:00+00:00"
);
assert_eq!(
metadata["trigger"]["started_at"],
"2026-09-05T06:30:00+00:00"
);
assert_eq!(metadata["trigger"]["attempt"], 3);
assert_eq!(metadata["trigger"]["singleton_key"], "order-pipeline");
}
#[test]
fn vars_are_stamped_the_way_every_other_ingress_stamps_them() {
let vars = json!({"region": "eu-west-1"});
let metadata = occurrence_metadata(facts(), Some(&vars));
assert_eq!(metadata["vars"]["region"], "eu-west-1");
assert!(occurrence_metadata(facts(), None).get("vars").is_none());
}
}