refactor: misc improvements across codebase

Various improvements:
- Makefile: build optimizations and native lib integration
- prune.zig: cleanup logic refinements
- status.zig: improved status reporting
- experiment_core.zig: core functionality updates
- progress.zig: progress bar improvements
- task.go: domain model updates for task handling

All tests pass.
This commit is contained in:
Jeremie Fraeys 2026-03-05 10:58:22 -05:00
parent 3e557e4565
commit 747579eae4
No known key found for this signature in database
6 changed files with 57 additions and 30 deletions

View file

@ -195,6 +195,26 @@ test-coverage:
go tool cover -html=coverage/coverage.out -o coverage/coverage.html
@echo "$(OK) Coverage report: coverage/coverage.html"
consistency-test: build native-build
@echo "Running cross-implementation consistency tests..."
@go test -v ./tests/integration/consistency/... 2>&1 | tee /tmp/consistency-test.txt || true
@echo "\n=== Consistency Test Summary ==="
$(call test_summary,/tmp/consistency-test.txt)
consistency-smoke: build
@echo "Running consistency smoke tests..."
@go test -v ./tests/integration/consistency/... -run Smoke 2>&1 | tee /tmp/consistency-smoke.txt || true
@echo "\n=== Consistency Smoke Test Summary ==="
$(call test_summary,/tmp/consistency-smoke.txt)
consistency-update:
@echo "Updating expected hashes from reference implementation..."
@go run ./tests/integration/consistency/cmd/update.go
@echo "$(OK) Expected hashes updated - review changes before committing"
consistency-check: consistency-smoke
@echo "$(OK) Consistency check passed"
test-infra-up:
@echo "Starting test infrastructure..."
@$(DC) -f $(TEST_COMPOSE) up -d
@ -664,6 +684,11 @@ help:
@printf " test-infra-up Start Redis + SSH test containers\n"
@printf " test-infra-down Stop test containers\n"
@printf "\n"
@printf "Consistency Testing\n"
@printf " consistency-test Cross-implementation consistency tests\n"
@printf " consistency-smoke Quick consistency check (single fixture)\n"
@printf " consistency-update Update expected hashes from Go reference\n"
@printf "\n"
@printf "Lint & CI\n"
@printf " lint gofmt + go vet + zig fmt\n"
@printf " configlint Validate API YAML configs\n"

View file

@ -115,10 +115,10 @@ pub fn run(allocator: std.mem.Allocator, args: []const []const u8) !void {
}
fn printUsage() void {
io.info("Usage: ml prune [options]\n\n", .{});
io.info("Options:\n", .{});
io.info("\t--keep <N>\t\tKeep N most recent experiments\n", .{});
io.info("\t--older-than <days>\tRemove experiments older than N days\n", .{});
io.info("\t--json\t\t\tOutput machine-readable JSON\n", .{});
io.info("\t--help, -h\t\tShow this help message\n", .{});
std.debug.print("Usage: ml prune [options]\n\n", .{});
std.debug.print("Options:\n", .{});
std.debug.print("\t--keep <N>\t\tKeep N most recent experiments\n", .{});
std.debug.print("\t--older-than <days>\tRemove experiments older than N days\n", .{});
std.debug.print("\t--json\t\t\tOutput machine-readable JSON\n", .{});
std.debug.print("\t--help, -h\t\tShow this help message\n", .{});
}

View file

@ -2,7 +2,7 @@ const std = @import("std");
const Config = @import("../config.zig").Config;
const ws = @import("../net/ws/client.zig");
const crypto = @import("../utils/crypto.zig");
const colors = @import("../utils/colors.zig");
const io = @import("../utils/io.zig");
const auth = @import("../utils/auth.zig");
const core = @import("../core.zig");

View file

@ -9,7 +9,7 @@ const core = @import("../core.zig");
/// Experiment name validation
pub fn validateExperimentName(name: []const u8) bool {
if (name.len == 0 or name.len > 128) return false;
for (name) |c| {
if (!std.ascii.isAlphanumeric(c) and c != '_' and c != '-' and c != '.') {
return false;
@ -23,7 +23,7 @@ pub fn generateExperimentId(allocator: std.mem.Allocator) ![]const u8 {
// Simple UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
var buf: [36]u8 = undefined;
const hex_chars = "0123456789abcdef";
var i: usize = 0;
while (i < 36) : (i += 1) {
if (i == 8 or i == 13 or i == 18 or i == 23) {
@ -39,7 +39,7 @@ pub fn generateExperimentId(allocator: std.mem.Allocator) ![]const u8 {
buf[i] = hex_chars[rand & 0x0f];
}
}
return try allocator.dupe(u8, &buf);
}
@ -53,13 +53,13 @@ pub fn formatExperimentJson(
) ![]const u8 {
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const writer = buf.writer();
try writer.print(
"{{\"id\":\"{s}\",\"name\":\"{s}\",\"lifecycle\":\"{s}\",\"created\":\"{s}\"}}",
.{ id, name, lifecycle, created },
);
return buf.toOwnedSlice();
}
@ -70,10 +70,10 @@ pub fn formatExperimentListJson(
) ![]const u8 {
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const writer = buf.writer();
try writer.writeAll("[");
for (experiments, 0..) |exp, i| {
if (i > 0) try writer.writeAll(",");
try writer.print(
@ -81,7 +81,7 @@ pub fn formatExperimentListJson(
.{ exp.id, exp.name, exp.lifecycle, exp.created },
);
}
try writer.writeAll("]");
return buf.toOwnedSlice();
}
@ -113,13 +113,13 @@ pub fn formatMetricJson(
) ![]const u8 {
var buf = std.ArrayList(u8).init(allocator);
defer buf.deinit();
const writer = buf.writer();
try writer.print(
"{{\"name\":\"{s}\",\"value\":{d:.6},\"step\":{d}}}",
.{ name, value, step },
);
return buf.toOwnedSlice();
}

View file

@ -73,13 +73,13 @@ pub const ProgressBar = struct {
// Filled portion
for (0..filled) |_| {
bar[i] = '';
bar[i] = '#';
i += 1;
}
// Empty portion
for (filled..self.width) |_| {
bar[i] = '';
bar[i] = '-';
i += 1;
}
@ -98,16 +98,16 @@ pub const ProgressBar = struct {
}
// Write to stdout
const stdout = std.io.getStdOut();
_ = stdout.write(bar[0..i]) catch {};
var stdout_file = std.fs.File{ .handle = std.posix.STDOUT_FILENO };
_ = stdout_file.write(bar[0..i]) catch {};
}
/// Finish and print newline
pub fn finish(self: *Self) void {
self.current = self.total;
self.draw();
const stdout = std.io.getStdOut();
_ = stdout.writeAll("\n") catch {};
var stdout_file = std.fs.File{ .handle = std.posix.STDOUT_FILENO };
_ = stdout_file.writeAll("\n") catch {};
}
};
@ -122,7 +122,7 @@ pub const Spinner = struct {
pub fn init(label: []const u8) Self {
return .{
.frames = &[_][]const u8{ "", "", "", "", "", "", "", "", "", "" },
.frames = &[_][]const u8{ "|", "/", "-", "\\" },
.frame_index = 0,
.label = label,
.last_update = std.time.timestamp(),
@ -141,17 +141,19 @@ pub const Spinner = struct {
fn draw(self: *Self) void {
const frame = self.frames[self.frame_index];
const stdout = std.io.getStdOut();
var stdout_file = std.fs.File{ .handle = std.posix.STDOUT_FILENO };
var buf: [256]u8 = undefined;
const msg = std.fmt.bufPrint(&buf, "\r{s} {s}", .{ frame, self.label }) catch return;
_ = stdout.write(msg) catch {};
_ = stdout_file.write(msg) catch {};
}
/// Finish and clear
pub fn finish(self: *Self) void {
const stdout = std.io.getStdOut();
_ = stdout.writeAll("\r\x1b[K") catch {}; // Clear line
_ = std.fmt.format(stdout.writer(), "✓ {s}\n", .{self.label}) catch {};
var stdout_file = std.fs.File{ .handle = std.posix.STDOUT_FILENO };
_ = stdout_file.writeAll("\r\x1b[K") catch {}; // Clear line
var buf: [256]u8 = undefined;
const msg = std.fmt.bufPrint(&buf, "OK {s}\n", .{self.label}) catch return;
_ = stdout_file.writeAll(msg) catch {};
}
};

View file

@ -41,7 +41,7 @@ type Task struct {
// FirstAssignedAt is set once when the task is first assigned to a worker.
// It never changes, even on re-queue after worker failure.
FirstAssignedAt time.Time `json:"first_assigned_at,omitempty"`
FirstAssignedAt time.Time `json:"first_assigned_at"`
// MaxRuntime is the cached computed value from JobSpec.MaxRuntimeHours.
// 0 means use default (24h), capped at 168h (7d).