refactor(robot): add constructors to RobotMeta, support optional gitlab_base_url

RobotMeta previously required direct struct literal construction with only
elapsed_ms. This made it impossible to add optional fields without updating
every call site to include them.

Introduce two constructors:
- RobotMeta::new(elapsed_ms) — standard meta with timing only
- RobotMeta::with_base_url(elapsed_ms, base_url) — meta enriched with the
  GitLab instance URL, enabling consumers to construct entity links without
  needing config access

The gitlab_base_url field uses #[serde(skip_serializing_if = "Option::is_none")]
so existing JSON envelopes are byte-identical — no breaking change for any
robot mode consumer.

All 22 call sites across handlers, count, cron, drift, embed, generate_docs,
ingest, list (mrs/notes), related, show, stats, sync_status, and who are
updated from struct literals to RobotMeta::new(). Three tests verify the
new constructors and trailing-slash normalization.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
teernisse
2026-03-11 10:28:49 -04:00
parent 5c44ee91fb
commit d6d1686f8e
15 changed files with 66 additions and 33 deletions

View File

@@ -361,7 +361,7 @@ fn print_combined_ingest_json(
notes_upserted: mrs.notes_upserted,
},
},
meta: RobotMeta { elapsed_ms },
meta: RobotMeta::new(elapsed_ms),
};
println!(
@@ -975,9 +975,7 @@ async fn handle_auth_test(
name: result.name.clone(),
gitlab_url: result.base_url.clone(),
},
meta: RobotMeta {
elapsed_ms: start.elapsed().as_millis() as u64,
},
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
};
println!("{}", serde_json::to_string(&output)?);
} else {
@@ -1038,9 +1036,7 @@ async fn handle_doctor(
success: result.success,
checks: result.checks,
},
meta: RobotMeta {
elapsed_ms: start.elapsed().as_millis() as u64,
},
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
};
println!("{}", serde_json::to_string(&output)?);
} else {
@@ -1085,9 +1081,7 @@ fn handle_version(robot_mode: bool) -> Result<(), Box<dyn std::error::Error>> {
Some(git_hash)
},
},
meta: RobotMeta {
elapsed_ms: start.elapsed().as_millis() as u64,
},
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
};
println!("{}", serde_json::to_string(&output)?);
} else if git_hash.is_empty() {
@@ -1245,9 +1239,7 @@ async fn handle_migrate(
after_version,
migrated: after_version > before_version,
},
meta: RobotMeta {
elapsed_ms: start.elapsed().as_millis() as u64,
},
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
};
println!("{}", serde_json::to_string(&output)?);
} else if after_version > before_version {
@@ -1962,9 +1954,7 @@ async fn handle_health(
schema_version,
actions,
},
meta: RobotMeta {
elapsed_ms: start.elapsed().as_millis() as u64,
},
meta: RobotMeta::new(start.elapsed().as_millis() as u64),
};
println!("{}", serde_json::to_string(&output)?);
} else {