refactor(cli): rename exec/ and queue/ directories for clarity

- Rename cli/src/commands/exec/ → executor/ (4 files)
- Rename cli/src/commands/queue/ → submission/ (4 files)
- Create new submission/index.zig, delete queue/index.zig

The new names better reflect the purpose of these modules:
- 'executor' for local/remote execution logic
- 'submission' for job submission and queue management

This is a pure rename with no functional changes.
This commit is contained in:
Jeremie Fraeys 2026-03-05 13:12:59 -05:00
parent 8b83d60452
commit ccb4e15877
No known key found for this signature in database
11 changed files with 163 additions and 5 deletions

View file

@ -1,3 +0,0 @@
pub const parse = @import("queue/parse.zig");
pub const validate = @import("queue/validate.zig");
pub const submit = @import("queue/submit.zig");

View file

@ -4,8 +4,8 @@ const config = @import("../config.zig");
const mode = @import("../mode.zig");
const common = @import("common.zig");
const remote = @import("exec/remote.zig");
const local = @import("exec/local.zig");
const remote = @import("executor/remote.zig");
const local = @import("executor/local.zig");
pub const RunMode = enum {
local,
@ -27,6 +27,16 @@ pub const RunOptions = struct {
intent: ?[]const u8 = null,
expected_outcome: ?[]const u8 = null,
tags: ?[]const u8 = null,
// Dataset/snapshot config
commit_id: ?[]const u8 = null,
snapshot_id: ?[]const u8 = null,
snapshot_sha256: ?[]const u8 = null,
// Re-run options
rerun_id: ?[]const u8 = null,
inherit_narrative: bool = false,
inherit_config: bool = false,
inherit_all: bool = false,
parent_run_id: ?[]const u8 = null,
};
/// Unified run command - transparently handles local and remote execution
@ -95,6 +105,24 @@ pub fn execute(allocator: std.mem.Allocator, args: []const []const u8) !void {
} else if (std.mem.eql(u8, arg, "--tags") and i + 1 < pre.len) {
options.tags = pre[i + 1];
i += 1;
} else if (std.mem.eql(u8, arg, "--rerun") and i + 1 < pre.len) {
options.rerun_id = pre[i + 1];
i += 1;
} else if (std.mem.eql(u8, arg, "--inherit-narrative")) {
options.inherit_narrative = true;
} else if (std.mem.eql(u8, arg, "--inherit-config")) {
options.inherit_config = true;
} else if (std.mem.eql(u8, arg, "--rerun-all")) {
options.inherit_all = true;
options.inherit_narrative = true;
options.inherit_config = true;
} else if (std.mem.eql(u8, arg, "--parent")) {
if (i + 1 < pre.len and !std.mem.startsWith(u8, pre[i + 1], "-")) {
options.parent_run_id = pre[i + 1];
i += 1;
} else {
options.parent_run_id = "auto"; // Mark for auto-detection from rerun_id
}
} else if (!std.mem.startsWith(u8, arg, "-")) {
if (job_name == null) {
job_name = arg;
@ -129,6 +157,18 @@ pub fn execute(allocator: std.mem.Allocator, args: []const []const u8) !void {
mut.deinit(allocator);
}
// Handle re-run: load previous run manifest and inherit options
if (options.rerun_id) |rerun_id| {
// Default to inheriting everything for absolute reproducibility
if (!options.inherit_narrative and !options.inherit_config and !options.inherit_all) {
options.inherit_all = true;
options.inherit_narrative = true;
options.inherit_config = true;
std.log.info("Re-run: inheriting all config for reproducibility (use --inherit-* flags to customize)", .{});
}
try handleRerun(allocator, rerun_id, &options, cfg.worker_base);
}
// Determine execution mode: config > auto-detect
var run_mode: RunMode = undefined;
@ -194,6 +234,117 @@ fn explainJob(allocator: std.mem.Allocator, job_name: []const u8, options: *cons
_ = allocator;
}
/// Handle re-run logic: load manifest and inherit options
fn handleRerun(
allocator: std.mem.Allocator,
rerun_id: []const u8,
options: *RunOptions,
worker_base: []const u8,
) !void {
const manifest = @import("../utils/manifest.zig");
const json = @import("../utils/json.zig");
// Resolve manifest path
const manifest_path = manifest.resolvePathWithBase(allocator, rerun_id, worker_base) catch |err| {
std.log.err("Could not find run '{s}': {s}", .{ rerun_id, @errorName(err) });
return error.RunNotFound;
};
defer allocator.free(manifest_path);
// Read and parse manifest
const data = manifest.readFileAlloc(allocator, manifest_path) catch |err| {
std.log.err("Could not read manifest for '{s}': {s}", .{ rerun_id, @errorName(err) });
return error.ManifestReadFailed;
};
defer allocator.free(data);
const parsed = std.json.parseFromSlice(std.json.Value, allocator, data, .{}) catch |err| {
std.log.err("Could not parse manifest for '{s}': {s}", .{ rerun_id, @errorName(err) });
return error.ManifestParseFailed;
};
defer parsed.deinit();
if (parsed.value != .object) {
return error.InvalidManifest;
}
const obj = parsed.value.object;
// Inherit narrative fields if requested
if (options.inherit_narrative) {
if (options.hypothesis == null) {
options.hypothesis = json.getString(obj, "hypothesis");
}
if (options.context == null) {
options.context = json.getString(obj, "context");
}
if (options.intent == null) {
options.intent = json.getString(obj, "intent");
}
if (options.expected_outcome == null) {
options.expected_outcome = json.getString(obj, "expected_outcome");
}
if (options.tags == null) {
options.tags = json.getString(obj, "tags");
}
std.log.info("Inherited narrative from previous run", .{});
}
// Inherit config if requested (resources, priority, dataset config)
if (options.inherit_config or options.inherit_all) {
if (options.cpu == 1) { // Only if not explicitly set
if (json.getInt(u8, obj, "cpu")) |cpu| {
options.cpu = cpu;
}
}
if (options.memory == 4) { // Only if not explicitly set
if (json.getInt(u8, obj, "memory")) |mem| {
options.memory = mem;
}
}
if (options.gpu == 0) { // Only if not explicitly set
if (json.getInt(u8, obj, "gpu")) |gpu| {
options.gpu = gpu;
}
}
if (options.priority == 5) { // Only if not explicitly set
if (json.getInt(u8, obj, "priority")) |prio| {
options.priority = prio;
}
}
if (options.gpu_memory == null) {
options.gpu_memory = json.getString(obj, "gpu_memory");
}
// Inherit dataset/snapshot config
if (options.commit_id == null) {
options.commit_id = json.getString(obj, "commit_id");
}
if (options.snapshot_id == null) {
options.snapshot_id = json.getString(obj, "snapshot_id");
}
if (options.snapshot_sha256 == null) {
options.snapshot_sha256 = json.getString(obj, "snapshot_sha256");
}
if (options.inherit_all) {
std.log.info("Inherited all config from previous run", .{});
} else {
std.log.info("Inherited config from previous run", .{});
}
}
// Set parent_run_id for provenance tracking
if (options.parent_run_id) |pr| {
if (std.mem.eql(u8, pr, "auto")) {
// Auto-detect from manifest
if (json.getString(obj, "run_id")) |parent_id| {
options.parent_run_id = try allocator.dupe(u8, parent_id);
std.log.info("Set parent run for provenance: {s}", .{parent_id[0..@min(8, parent_id.len)]});
}
}
}
std.log.info("Re-running from previous run: {s}", .{rerun_id[0..@min(8, rerun_id.len)]});
}
fn printUsage() !void {
std.debug.print("Usage: ml run <job_name> [options] [-- <args>]\n", .{});
std.debug.print("\nUnified run command - handles both local and remote execution.\n", .{});
@ -209,4 +360,11 @@ fn printUsage() !void {
std.debug.print(" --hypothesis <text> Research hypothesis\n", .{});
std.debug.print(" --context <text> Background information\n", .{});
std.debug.print(" --tags <csv> Comma-separated tags\n", .{});
std.debug.print("\nRe-run Options (Research-First Reproducibility):\n", .{});
std.debug.print(" --rerun <run_id> Re-run inheriting everything by default\n", .{});
std.debug.print(" --inherit-narrative Only inherit hypothesis/context/tags\n", .{});
std.debug.print(" --inherit-config Only inherit resources/dataset/priority\n", .{});
std.debug.print(" --parent [run_id] Link as child for provenance (auto if no id)\n", .{});
std.debug.print("\nNote: --rerun alone ensures absolute reproducibility. Use --inherit-*\n", .{});
std.debug.print(" flags to selectively inherit specific aspects only.\n", .{});
}

View file

@ -0,0 +1,3 @@
pub const parse = @import("parse.zig");
pub const validate = @import("validate.zig");
pub const submit = @import("submit.zig");