use std::collections::HashSet;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
pub fn micros_to_iso(micros: i64) -> String {
chrono::DateTime::<chrono::Utc>::from_timestamp_micros(micros)
.unwrap_or_else(chrono::Utc::now)
.to_rfc3339_opts(chrono::SecondsFormat::Micros, true)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "snake_case")]
pub enum PresentationMode {
#[default]
Agent,
Verbose,
Human,
}
const LIFECYCLE_NULL_PRESERVE: &[&str] = &[
"completed_at",
"deleted_at",
"due_at",
"read_at",
"started_at",
"superseded_at",
"applied_at",
"withdrawn_at",
"reviewed_at",
"parent_id",
"superseded_by",
"replaced_by",
];
const SCORE_FIELDS: &[&str] = &[
"score",
"salience",
"decay_factor",
"rrf_score",
"similarity",
"cross_encoder_score",
"graph_proximity_score",
];
const UUID_CANONICAL_LEN: usize = 36;
fn should_shorten_uuid_field(key: &str) -> bool {
if key == "full_id" {
return false;
}
key == "id" || key.ends_with("_id") || matches!(key, "superseded_by" | "replaced_by")
}
pub fn present(value: Value, mode: PresentationMode, now_unix_seconds: i64) -> Value {
match mode {
PresentationMode::Verbose | PresentationMode::Human => value,
PresentationMode::Agent => {
let lifecycle_preserve: HashSet<&str> =
LIFECYCLE_NULL_PRESERVE.iter().copied().collect();
let score_fields: HashSet<&str> = SCORE_FIELDS.iter().copied().collect();
transform_agent(
value,
&lifecycle_preserve,
&score_fields,
now_unix_seconds,
false,
)
}
}
}
fn transform_agent(
value: Value,
lifecycle: &HashSet<&str>,
scores: &HashSet<&str>,
now: i64,
inside_properties: bool,
) -> Value {
match value {
Value::Object(map) => {
let mut out = Map::new();
for (k, v) in map {
let child_inside_properties = inside_properties || k == "properties";
let transformed =
transform_field_agent(&k, v, lifecycle, scores, now, child_inside_properties);
match transformed {
None => {} Some(tv) => {
out.insert(k, tv);
}
}
}
Value::Object(out)
}
Value::Array(arr) => {
let items: Vec<Value> = arr
.into_iter()
.map(|v| transform_agent(v, lifecycle, scores, now, inside_properties))
.collect();
Value::Array(items)
}
other => other,
}
}
fn transform_field_agent(
key: &str,
value: Value,
lifecycle: &HashSet<&str>,
scores: &HashSet<&str>,
now: i64,
inside_properties: bool,
) -> Option<Value> {
match &value {
Value::Null => {
if lifecycle.contains(key) {
Some(value)
} else {
None
}
}
Value::String(s) if s.is_empty() => None,
Value::Array(a) if a.is_empty() => None,
Value::Object(o) if o.is_empty() => None,
Value::Number(_) if scores.contains(key) => {
if let Some(f) = value.as_f64() {
Some(truncate_to_3_sig_figs(f))
} else {
Some(value)
}
}
Value::String(s) if is_canonical_uuid(s) && should_shorten_uuid_field(key) => {
Some(Value::String(s[..8].to_string()))
}
Value::String(s) if !inside_properties && looks_like_iso8601(s) => {
Some(Value::String(compact_timestamp(s, now)))
}
Value::Object(_) | Value::Array(_) => Some(transform_agent(
value,
lifecycle,
scores,
now,
inside_properties,
)),
_ => Some(value),
}
}
fn is_canonical_uuid(s: &str) -> bool {
if s.len() != UUID_CANONICAL_LEN {
return false;
}
let b = s.as_bytes();
b[8] == b'-'
&& b[13] == b'-'
&& b[18] == b'-'
&& b[23] == b'-'
&& b[..8].iter().all(|c| c.is_ascii_hexdigit())
&& b[9..13].iter().all(|c| c.is_ascii_hexdigit())
&& b[14..18].iter().all(|c| c.is_ascii_hexdigit())
&& b[19..23].iter().all(|c| c.is_ascii_hexdigit())
&& b[24..].iter().all(|c| c.is_ascii_hexdigit())
}
fn looks_like_iso8601(s: &str) -> bool {
if s.len() < 16 {
return false;
}
let b = s.as_bytes();
b[4] == b'-'
&& b[7] == b'-'
&& b[10] == b'T'
&& b[13] == b':'
&& b[..4].iter().all(|c| c.is_ascii_digit())
&& b[5..7].iter().all(|c| c.is_ascii_digit())
&& b[8..10].iter().all(|c| c.is_ascii_digit())
&& b[11..13].iter().all(|c| c.is_ascii_digit())
}
fn compact_timestamp(s: &str, now: i64) -> String {
if let Some(unix) = parse_iso8601_unix(s) {
let diff = now - unix;
if (0..86400).contains(&diff) {
return relative_time(diff);
}
}
s.chars().take(16).collect()
}
fn parse_iso8601_unix(s: &str) -> Option<i64> {
if s.len() < 19 {
return None;
}
let b = s.as_bytes();
let year: i64 = parse_digits(&b[0..4])?;
let month: i64 = parse_digits(&b[5..7])?;
let day: i64 = parse_digits(&b[8..10])?;
let hour: i64 = parse_digits(&b[11..13])?;
let minute: i64 = parse_digits(&b[14..16])?;
let second: i64 = parse_digits(&b[17..19])?;
let days_since_epoch = days_from_civil(year, month, day);
Some(days_since_epoch * 86400 + hour * 3600 + minute * 60 + second)
}
fn parse_digits(b: &[u8]) -> Option<i64> {
let s = std::str::from_utf8(b).ok()?;
s.parse().ok()
}
fn days_from_civil(y: i64, m: i64, d: i64) -> i64 {
let y = if m <= 2 { y - 1 } else { y };
let era = y.div_euclid(400);
let yoe = y - era * 400;
let doy = (153 * (if m > 2 { m - 3 } else { m + 9 }) + 2) / 5 + d - 1;
let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
era * 146097 + doe - 719468
}
fn relative_time(diff_secs: i64) -> String {
if diff_secs < 60 {
format!("{diff_secs}s ago")
} else if diff_secs < 3600 {
format!("{}m ago", diff_secs / 60)
} else {
format!("{}h ago", diff_secs / 3600)
}
}
fn truncate_to_3_sig_figs(f: f64) -> Value {
if f == 0.0 || !f.is_finite() {
return Value::from(f);
}
let magnitude = f.abs().log10().floor() as i32;
let factor = 10f64.powi(2 - magnitude);
let rounded = (f * factor).round() / factor;
serde_json::Number::from_f64(rounded)
.map(Value::Number)
.unwrap_or(Value::from(rounded))
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
const NOW: i64 = 1_748_016_480;
fn agent(v: Value) -> Value {
present(v, PresentationMode::Agent, NOW)
}
#[test]
fn verbose_passthrough() {
let v = json!({"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "title": "X"});
let out = present(v.clone(), PresentationMode::Verbose, NOW);
assert_eq!(out, v);
}
#[test]
fn agent_shortens_uuid() {
let v = json!({"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"});
let out = agent(v);
assert_eq!(out["id"], json!("a1b2c3d4"));
}
#[test]
fn agent_drops_empty_string() {
let v = json!({"title": "ok", "description": ""});
let out = agent(v);
assert!(out.get("description").is_none());
assert_eq!(out["title"], json!("ok"));
}
#[test]
fn agent_drops_empty_array() {
let v = json!({"tags": [], "title": "ok"});
let out = agent(v);
assert!(out.get("tags").is_none());
}
#[test]
fn agent_drops_empty_object() {
let v = json!({"properties": {}, "title": "ok"});
let out = agent(v);
assert!(out.get("properties").is_none());
}
#[test]
fn agent_drops_non_lifecycle_null() {
let v = json!({"result": null, "title": "ok"});
let out = agent(v);
assert!(out.get("result").is_none());
}
#[test]
fn agent_preserves_lifecycle_null() {
let v = json!({"completed_at": null, "due_at": null, "title": "ok"});
let out = agent(v);
assert_eq!(out["completed_at"], json!(null));
assert_eq!(out["due_at"], json!(null));
}
#[test]
fn agent_preserves_relationship_null() {
let v = json!({"parent_id": null, "superseded_by": null});
let out = agent(v);
assert_eq!(out["parent_id"], json!(null));
assert_eq!(out["superseded_by"], json!(null));
}
#[test]
fn agent_truncates_score_field() {
let v = json!({"score": 0.12345678});
let out = agent(v);
let s = out["score"].as_f64().unwrap();
assert!((s - 0.123).abs() < 1e-9, "expected ~0.123, got {s}");
}
#[test]
fn agent_compacts_old_timestamp_to_minutes() {
let v = json!({"created_at": "2020-01-01T10:30:45.123456Z"});
let out = agent(v);
assert_eq!(out["created_at"], json!("2020-01-01T10:30"));
}
#[test]
fn agent_compacts_recent_timestamp_to_relative() {
let ts_unix = NOW - 180;
let ts = unix_to_iso8601(ts_unix);
let v = json!({"updated_at": ts});
let out = agent(v);
assert_eq!(out["updated_at"], json!("3m ago"));
}
#[test]
fn agent_recurses_into_nested_objects() {
let v = json!({
"items": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"tags": [],
"score": 0.9999
}
]
});
let out = agent(v);
let item = &out["items"][0];
assert_eq!(item["id"], json!("a1b2c3d4"));
assert!(item.get("tags").is_none());
let s = item["score"].as_f64().unwrap();
assert!((s - 1.0).abs() < 1e-9);
}
#[test]
fn agent_preserves_full_id_as_36_chars() {
let uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
let v = json!({"id": uuid, "full_id": uuid, "title": "X"});
let out = agent(v);
assert_eq!(
out["id"],
json!("a1b2c3d4"),
"id should be 8-char short form"
);
assert_eq!(
out["full_id"].as_str().unwrap().len(),
36,
"full_id must be 36 chars in agent mode"
);
assert_eq!(
out["full_id"],
json!(uuid),
"full_id must equal the original UUID"
);
assert!(
out["full_id"]
.as_str()
.unwrap()
.starts_with(out["id"].as_str().unwrap()),
"full_id must start with the short id prefix"
);
}
#[test]
fn is_canonical_uuid_recognizes_valid() {
assert!(is_canonical_uuid("a1b2c3d4-e5f6-7890-abcd-ef1234567890"));
assert!(!is_canonical_uuid("a1b2c3d4"));
assert!(!is_canonical_uuid("not-a-uuid-at-all-here---------"));
}
#[test]
fn looks_like_iso8601_recognizes_valid() {
assert!(looks_like_iso8601("2026-05-23T16:18:15.234567Z"));
assert!(!looks_like_iso8601("not a timestamp"));
assert!(!looks_like_iso8601("2026-05-23"));
}
fn unix_to_iso8601(unix: i64) -> String {
let (y, mo, d, h, mi, s) = unix_to_civil(unix);
format!("{y:04}-{mo:02}-{d:02}T{h:02}:{mi:02}:{s:02}Z")
}
fn unix_to_civil(unix: i64) -> (i64, i64, i64, i64, i64, i64) {
let s = unix % 86400;
let days = unix / 86400;
let h = s / 3600;
let m = (s % 3600) / 60;
let sec = s % 60;
let z = days + 719468;
let era = z.div_euclid(146097);
let doe = z - era * 146097;
let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365;
let y = yoe + era * 400;
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100);
let mp = (5 * doy + 2) / 153;
let d = doy - (153 * mp + 2) / 5 + 1;
let mo = if mp < 10 { mp + 3 } else { mp - 9 };
let y = if mo <= 2 { y + 1 } else { y };
(y, mo, d, h, m, sec)
}
#[test]
fn agent_does_not_shorten_uuid_shaped_content_fields() {
let uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
let out = agent(json!({
"id": uuid,
"full_id": uuid,
"content": uuid,
"description": uuid,
"title": uuid,
"query": uuid,
}));
assert_eq!(out["id"], json!("a1b2c3d4"));
assert_eq!(out["full_id"], json!(uuid));
assert_eq!(out["content"], json!(uuid));
assert_eq!(out["description"], json!(uuid));
assert_eq!(out["title"], json!(uuid));
assert_eq!(out["query"], json!(uuid));
}
#[test]
fn agent_shortens_suffix_id_fields() {
let uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890";
let out = agent(json!({
"note_id": uuid,
"source_id": uuid,
"target_id": uuid,
"proposal_id": uuid,
}));
assert_eq!(out["note_id"], json!("a1b2c3d4"));
assert_eq!(out["source_id"], json!("a1b2c3d4"));
assert_eq!(out["target_id"], json!("a1b2c3d4"));
assert_eq!(out["proposal_id"], json!("a1b2c3d4"));
}
}