herdr phase 1a: missions runtime_kind + target_node schema
First slice of the second-runtime path. Missions now carry
runtime_kind ('zeroclaw' | 'local_herdr') + target_node_id (FK to
nodes) so the mission_orchestrator + phase executors can dispatch
differently depending on where the operator wants execution.
Migration:
- 0055_missions_runtime_kind.sql — adds runtime_kind (NOT NULL
DEFAULT 'zeroclaw' + CHECK), target_node_id (nullable FK ON
DELETE SET NULL). All existing missions backfill to 'zeroclaw'
so behavior is unchanged.
- topology_runs also grows herdr_workspace_id / herdr_tab_id /
herdr_pane_id text columns so a resumed run can reattach to the
same Herdr pane instead of spawning a duplicate.
Code:
- cm-db::repo::missions — Mission + NewMission carry the two new
fields; all SELECTs updated; INSERT COALESCE-defaults
runtime_kind to 'zeroclaw' when unspecified.
- routes::missions::create — validates runtime_kind and requires
target_node_id when kind='local_herdr' (400 otherwise).
- lib/api/missions.ts — RuntimeKind type; Mission carries both;
CreateMissionRequest optional fields.
Behavior is opt-in: no path exists yet to actually create a
local_herdr mission — that lands in Phase 1c (wizard picker). This
commit just makes the schema + validation in place so Phase 1b's
fleet_herdr dispatch module can key on it.
Tests: mission_orchestrator integration test still green.
This commit is contained in:
@@ -35,6 +35,9 @@ pub struct CreateMissionRequest {
|
||||
pub config: Value,
|
||||
#[serde(default)]
|
||||
pub phases: Vec<PhaseSpec>,
|
||||
/// Defaults to "zeroclaw". "local_herdr" requires target_node_id.
|
||||
pub runtime_kind: Option<String>,
|
||||
pub target_node_id: Option<Uuid>,
|
||||
}
|
||||
|
||||
fn default_schedule() -> Value {
|
||||
@@ -120,6 +123,18 @@ pub async fn create(
|
||||
if body.title.trim().is_empty() {
|
||||
return Err(ApiError::BadRequest);
|
||||
}
|
||||
// Validate runtime_kind + require target_node when local_herdr.
|
||||
let runtime_kind = body.runtime_kind.as_deref().unwrap_or("zeroclaw");
|
||||
match runtime_kind {
|
||||
"zeroclaw" => {}
|
||||
"local_herdr" => {
|
||||
if body.target_node_id.is_none() {
|
||||
return Err(ApiError::BadRequest);
|
||||
}
|
||||
}
|
||||
_ => return Err(ApiError::BadRequest),
|
||||
}
|
||||
|
||||
let new = NewMission {
|
||||
workspace_id: user.workspace_id.as_uuid(),
|
||||
title: body.title.trim(),
|
||||
@@ -130,6 +145,8 @@ pub async fn create(
|
||||
schedule: body.schedule,
|
||||
description: body.description.as_deref(),
|
||||
config: body.config,
|
||||
runtime_kind: Some(runtime_kind),
|
||||
target_node_id: body.target_node_id,
|
||||
phases: body
|
||||
.phases
|
||||
.into_iter()
|
||||
|
||||
Reference in New Issue
Block a user