From 8ef36f98ca4a1f378c0be224d3bcac799beb4ffb Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 15:57:27 +0000 Subject: [PATCH 1/6] chore: replace interface{} with any (Go 1.18+ alias) --- cmd/cmd_expand_status.go | 4 ++-- cmd/cmd_live.go | 2 +- cmd/cmd_query.go | 2 +- ingest.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cmd/cmd_expand_status.go b/cmd/cmd_expand_status.go index 8fe4681..76e768a 100644 --- a/cmd/cmd_expand_status.go +++ b/cmd/cmd_expand_status.go @@ -80,8 +80,8 @@ func runExpandStatus(cmd *cli.Command, args []string) error { return nil } -// toInt converts an interface{} (typically from QueryRows) to int. -func toInt(v interface{}) int { +// toInt converts an any (typically from QueryRows) to int. +func toInt(v any) int { switch n := v.(type) { case int: return n diff --git a/cmd/cmd_live.go b/cmd/cmd_live.go index 49a3e7d..cd7eebf 100644 --- a/cmd/cmd_live.go +++ b/cmd/cmd_live.go @@ -71,7 +71,7 @@ func runLive(cmd *cli.Command, args []string) error { } // sqlScalar extracts the first numeric value from a QuerySQL result. -func sqlScalar(rows []map[string]interface{}) int { +func sqlScalar(rows []map[string]any) int { if len(rows) == 0 { return 0 } diff --git a/cmd/cmd_query.go b/cmd/cmd_query.go index 795c64f..70f2bdf 100644 --- a/cmd/cmd_query.go +++ b/cmd/cmd_query.go @@ -129,7 +129,7 @@ func runQuery(cmd *cli.Command, args []string) error { return nil } -func formatValue(v interface{}) string { +func formatValue(v any) string { if v == nil { return "NULL" } diff --git a/ingest.go b/ingest.go index a5a906c..de894cc 100644 --- a/ingest.go +++ b/ingest.go @@ -362,7 +362,7 @@ func extractIteration(label string) int { return n } -// toFloat64 converts a JSON-decoded interface{} value to float64. +// toFloat64 converts a JSON-decoded any value to float64. // Handles float64 (standard json.Unmarshal), json.Number, and string values. func toFloat64(v any) (float64, bool) { switch val := v.(type) { From 7ae5fee661e1353e759e0f6bded5ea84ab491fdd Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 15:58:11 +0000 Subject: [PATCH 2/6] =?UTF-8?q?chore:=20fmt.Errorf(static)=20=E2=86=92=20e?= =?UTF-8?q?rrors.New?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend_http.go | 2 +- backend_http_textmodel.go | 4 ++-- cmd/cmd_ab.go | 5 +++-- cmd/cmd_approve.go | 3 ++- cmd/cmd_benchmark.go | 25 +++++++++++++------------ cmd/cmd_coverage.go | 3 ++- cmd/cmd_expand.go | 13 +++++++------ cmd/cmd_expand_status.go | 3 ++- cmd/cmd_export.go | 3 ++- cmd/cmd_import.go | 5 +++-- cmd/cmd_ingest.go | 6 +++--- cmd/cmd_inventory.go | 3 ++- cmd/cmd_lesson.go | 11 ++++++----- cmd/cmd_metrics.go | 3 ++- cmd/cmd_normalize.go | 3 ++- cmd/cmd_probe.go | 3 ++- cmd/cmd_query.go | 3 ++- cmd/cmd_sandwich.go | 5 +++-- cmd/cmd_seed_influx.go | 3 ++- cmd/cmd_sequence.go | 13 +++++++------ cmd/cmd_train.go | 24 +++++++++++++----------- convert.go | 3 ++- coverage.go | 3 ++- ingest.go | 5 +++-- normalize.go | 3 ++- publish.go | 5 +++-- service.go | 3 ++- worker.go | 3 ++- 28 files changed, 97 insertions(+), 71 deletions(-) diff --git a/backend_http.go b/backend_http.go index 9313d43..6348f45 100644 --- a/backend_http.go +++ b/backend_http.go @@ -161,7 +161,7 @@ func (b *HTTPBackend) doRequest(ctx context.Context, body []byte) (string, error } if len(chatResp.Choices) == 0 { - return "", fmt.Errorf("no choices in response") + return "", errors.New("no choices in response") } return chatResp.Choices[0].Message.Content, nil diff --git a/backend_http_textmodel.go b/backend_http_textmodel.go index 568042e..569d329 100644 --- a/backend_http_textmodel.go +++ b/backend_http_textmodel.go @@ -4,7 +4,7 @@ package ml import ( "context" - "fmt" + "errors" "iter" "forge.lthn.ai/core/go-inference" @@ -73,7 +73,7 @@ func (m *HTTPTextModel) Chat(ctx context.Context, messages []inference.Message, // Classify is not supported by HTTP backends. Returns an error. func (m *HTTPTextModel) Classify(_ context.Context, _ []string, _ ...inference.GenerateOption) ([]inference.ClassifyResult, error) { - return nil, fmt.Errorf("classify not supported by HTTP backend") + return nil, errors.New("classify not supported by HTTP backend") } // BatchGenerate processes multiple prompts sequentially via Generate. diff --git a/cmd/cmd_ab.go b/cmd/cmd_ab.go index f475378..6b28301 100644 --- a/cmd/cmd_ab.go +++ b/cmd/cmd_ab.go @@ -5,6 +5,7 @@ package cmd import ( "context" "encoding/json" + "errors" "fmt" "log/slog" "maps" @@ -319,7 +320,7 @@ func runAB(cmd *cli.Command, args []string) error { } if len(results) == 0 { - return fmt.Errorf("no results to compare") + return errors.New("no results to compare") } // Build condition summaries @@ -551,7 +552,7 @@ func loadABProbes() ([]abProbe, error) { func loadABKernels() ([]abKernelDef, error) { if len(abKernels) == 0 { - return nil, fmt.Errorf("at least one --kernel is required (raw file content is used as system message with zero instruction)") + return nil, errors.New("at least one --kernel is required (raw file content is used as system message with zero instruction)") } var defs []abKernelDef diff --git a/cmd/cmd_approve.go b/cmd/cmd_approve.go index 18b73f2..1f761db 100644 --- a/cmd/cmd_approve.go +++ b/cmd/cmd_approve.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "os" "path/filepath" @@ -32,7 +33,7 @@ func runApprove(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB required") + return errors.New("--db or LEM_DB required") } output := approveOutput diff --git a/cmd/cmd_benchmark.go b/cmd/cmd_benchmark.go index 1224289..8baab2f 100644 --- a/cmd/cmd_benchmark.go +++ b/cmd/cmd_benchmark.go @@ -5,6 +5,7 @@ package cmd import ( "context" "encoding/json" + "errors" "fmt" "log/slog" "math" @@ -13,9 +14,9 @@ import ( "sort" "time" + "forge.lthn.ai/core/cli/pkg/cli" "forge.lthn.ai/core/go-i18n/reversal" "forge.lthn.ai/core/go-ml" - "forge.lthn.ai/core/cli/pkg/cli" ) // grammarScore holds grammar v3 quality signals derived from a GrammarImprint. @@ -176,16 +177,16 @@ type benchmarkResult struct { // benchmarkSummary holds aggregate comparison metrics. type benchmarkSummary struct { - BaselineModel string `json:"baseline_model"` - TrainedModel string `json:"trained_model"` - TotalPrompts int `json:"total_prompts"` - AvgBaselineLEK float64 `json:"avg_baseline_lek"` - AvgTrainedLEK float64 `json:"avg_trained_lek"` - AvgDelta float64 `json:"avg_delta"` - Improved int `json:"improved"` - Regressed int `json:"regressed"` - Unchanged int `json:"unchanged"` - Duration string `json:"duration"` + BaselineModel string `json:"baseline_model"` + TrainedModel string `json:"trained_model"` + TotalPrompts int `json:"total_prompts"` + AvgBaselineLEK float64 `json:"avg_baseline_lek"` + AvgTrainedLEK float64 `json:"avg_trained_lek"` + AvgDelta float64 `json:"avg_delta"` + Improved int `json:"improved"` + Regressed int `json:"regressed"` + Unchanged int `json:"unchanged"` + Duration string `json:"duration"` // Grammar v3 aggregates AvgBaselineGrammar float64 `json:"avg_baseline_grammar"` @@ -351,7 +352,7 @@ func runBenchmark(cmd *cli.Command, args []string) error { n := float64(len(results)) if n == 0 { - return fmt.Errorf("no results to compare") + return errors.New("no results to compare") } summary := benchmarkSummary{ diff --git a/cmd/cmd_coverage.go b/cmd/cmd_coverage.go index 86faeaf..31dd416 100644 --- a/cmd/cmd_coverage.go +++ b/cmd/cmd_coverage.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "os" @@ -21,7 +22,7 @@ func runCoverage(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB required") + return errors.New("--db or LEM_DB required") } db, err := ml.OpenDB(path) diff --git a/cmd/cmd_expand.go b/cmd/cmd_expand.go index a731c86..99bc9c0 100644 --- a/cmd/cmd_expand.go +++ b/cmd/cmd_expand.go @@ -2,6 +2,7 @@ package cmd import ( "context" + "errors" "fmt" "os" @@ -10,10 +11,10 @@ import ( ) var ( - expandWorker string - expandOutput string - expandLimit int - expandDryRun bool + expandWorker string + expandOutput string + expandLimit int + expandDryRun bool ) var expandCmd = &cli.Command{ @@ -32,7 +33,7 @@ func init() { func runExpand(cmd *cli.Command, args []string) error { if modelName == "" { - return fmt.Errorf("--model is required") + return errors.New("--model is required") } path := dbPath @@ -40,7 +41,7 @@ func runExpand(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB env is required") + return errors.New("--db or LEM_DB env is required") } if expandWorker == "" { diff --git a/cmd/cmd_expand_status.go b/cmd/cmd_expand_status.go index 76e768a..a541886 100644 --- a/cmd/cmd_expand_status.go +++ b/cmd/cmd_expand_status.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "os" @@ -21,7 +22,7 @@ func runExpandStatus(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB required") + return errors.New("--db or LEM_DB required") } db, err := ml.OpenDB(path) diff --git a/cmd/cmd_export.go b/cmd/cmd_export.go index 9337f47..c053986 100644 --- a/cmd/cmd_export.go +++ b/cmd/cmd_export.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "os" @@ -46,7 +47,7 @@ func runExport(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB env is required") + return errors.New("--db or LEM_DB env is required") } db, err := ml.OpenDB(path) diff --git a/cmd/cmd_import.go b/cmd/cmd_import.go index b02eae8..dbd154a 100644 --- a/cmd/cmd_import.go +++ b/cmd/cmd_import.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "os" "path/filepath" @@ -17,7 +18,7 @@ var importCmd = &cli.Command{ } var ( - importSkipM3 bool + importSkipM3 bool importDataDir string importM3Host string ) @@ -34,7 +35,7 @@ func runImportAll(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB required") + return errors.New("--db or LEM_DB required") } dataDir := importDataDir diff --git a/cmd/cmd_ingest.go b/cmd/cmd_ingest.go index 862bcb3..43299d5 100644 --- a/cmd/cmd_ingest.go +++ b/cmd/cmd_ingest.go @@ -1,7 +1,7 @@ package cmd import ( - "fmt" + "errors" "os" "forge.lthn.ai/core/cli/pkg/cli" @@ -33,10 +33,10 @@ func init() { func runIngest(cmd *cli.Command, args []string) error { if modelName == "" { - return fmt.Errorf("--model is required") + return errors.New("--model is required") } if ingestContent == "" && ingestCapability == "" && ingestTraining == "" { - return fmt.Errorf("at least one of --content, --capability, or --training-log is required") + return errors.New("at least one of --content, --capability, or --training-log is required") } influx := ml.NewInfluxClient(influxURL, influxDB) diff --git a/cmd/cmd_inventory.go b/cmd/cmd_inventory.go index a9f0c10..07b61b3 100644 --- a/cmd/cmd_inventory.go +++ b/cmd/cmd_inventory.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "os" @@ -21,7 +22,7 @@ func runInventory(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB required") + return errors.New("--db or LEM_DB required") } db, err := ml.OpenDB(path) diff --git a/cmd/cmd_lesson.go b/cmd/cmd_lesson.go index 376e6c0..ca7bfab 100644 --- a/cmd/cmd_lesson.go +++ b/cmd/cmd_lesson.go @@ -5,6 +5,7 @@ package cmd import ( "context" "encoding/json" + "errors" "fmt" "log/slog" "os" @@ -13,8 +14,8 @@ import ( "strings" "time" - "forge.lthn.ai/core/go-ml" "forge.lthn.ai/core/cli/pkg/cli" + "forge.lthn.ai/core/go-ml" "gopkg.in/yaml.v3" ) @@ -90,9 +91,9 @@ type lessonPrompt struct { // lessonState tracks progress through a lesson. type lessonState struct { - LessonID string `json:"lesson_id"` - Completed map[string]lessonResult `json:"completed"` - UpdatedAt string `json:"updated_at"` + LessonID string `json:"lesson_id"` + Completed map[string]lessonResult `json:"completed"` + UpdatedAt string `json:"updated_at"` } type lessonResult struct { @@ -162,7 +163,7 @@ func runLesson(cmd *cli.Command, args []string) error { ) if len(lesson.Prompts) == 0 { - return fmt.Errorf("lesson has no prompts") + return errors.New("lesson has no prompts") } // Load state for resume diff --git a/cmd/cmd_metrics.go b/cmd/cmd_metrics.go index 6ac6375..072afb8 100644 --- a/cmd/cmd_metrics.go +++ b/cmd/cmd_metrics.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "os" @@ -21,7 +22,7 @@ func runMetrics(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB required") + return errors.New("--db or LEM_DB required") } db, err := ml.OpenDB(path) diff --git a/cmd/cmd_normalize.go b/cmd/cmd_normalize.go index de65c36..e9428f5 100644 --- a/cmd/cmd_normalize.go +++ b/cmd/cmd_normalize.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "os" @@ -27,7 +28,7 @@ func runNormalize(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB env is required") + return errors.New("--db or LEM_DB env is required") } db, err := ml.OpenDBReadWrite(path) diff --git a/cmd/cmd_probe.go b/cmd/cmd_probe.go index c31a930..fb1246b 100644 --- a/cmd/cmd_probe.go +++ b/cmd/cmd_probe.go @@ -3,6 +3,7 @@ package cmd import ( "context" "encoding/json" + "errors" "fmt" "os" @@ -27,7 +28,7 @@ func init() { func runProbe(cmd *cli.Command, args []string) error { if apiURL == "" { - return fmt.Errorf("--api-url is required") + return errors.New("--api-url is required") } model := modelName diff --git a/cmd/cmd_query.go b/cmd/cmd_query.go index 70f2bdf..179edf6 100644 --- a/cmd/cmd_query.go +++ b/cmd/cmd_query.go @@ -2,6 +2,7 @@ package cmd import ( "encoding/json" + "errors" "fmt" "maps" "os" @@ -35,7 +36,7 @@ func runQuery(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB env is required") + return errors.New("--db or LEM_DB env is required") } db, err := ml.OpenDB(path) diff --git a/cmd/cmd_sandwich.go b/cmd/cmd_sandwich.go index 662314b..9d9341e 100644 --- a/cmd/cmd_sandwich.go +++ b/cmd/cmd_sandwich.go @@ -5,14 +5,15 @@ package cmd import ( "context" "encoding/json" + "errors" "fmt" "log/slog" "os" "runtime" "time" - "forge.lthn.ai/core/go-ml" "forge.lthn.ai/core/cli/pkg/cli" + "forge.lthn.ai/core/go-ml" ) var sandwichCmd = &cli.Command{ @@ -108,7 +109,7 @@ func runSandwich(cmd *cli.Command, args []string) error { ) if len(seeds) == 0 { - return fmt.Errorf("no seed prompts found") + return errors.New("no seed prompts found") } // Open output file diff --git a/cmd/cmd_seed_influx.go b/cmd/cmd_seed_influx.go index c477387..6ccca5b 100644 --- a/cmd/cmd_seed_influx.go +++ b/cmd/cmd_seed_influx.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "fmt" "os" @@ -31,7 +32,7 @@ func runSeedInflux(cmd *cli.Command, args []string) error { path = os.Getenv("LEM_DB") } if path == "" { - return fmt.Errorf("--db or LEM_DB required") + return errors.New("--db or LEM_DB required") } db, err := ml.OpenDB(path) diff --git a/cmd/cmd_sequence.go b/cmd/cmd_sequence.go index 9e58a2b..981032c 100644 --- a/cmd/cmd_sequence.go +++ b/cmd/cmd_sequence.go @@ -4,6 +4,7 @@ package cmd import ( "encoding/json" + "errors" "fmt" "log/slog" "os" @@ -11,8 +12,8 @@ import ( "strings" "time" - "forge.lthn.ai/core/go-ml" "forge.lthn.ai/core/cli/pkg/cli" + "forge.lthn.ai/core/go-ml" "gopkg.in/yaml.v3" ) @@ -70,10 +71,10 @@ type sequenceDef struct { // sequenceState tracks progress through a sequence. type sequenceState struct { - SequenceID string `json:"sequence_id"` - Completed map[string]bool `json:"completed"` // lesson ID → done - Current string `json:"current"` - UpdatedAt string `json:"updated_at"` + SequenceID string `json:"sequence_id"` + Completed map[string]bool `json:"completed"` // lesson ID → done + Current string `json:"current"` + UpdatedAt string `json:"updated_at"` } func runSequence(cmd *cli.Command, args []string) error { @@ -103,7 +104,7 @@ func runSequence(cmd *cli.Command, args []string) error { modelPath = seq.ModelPath } if modelPath == "" { - return fmt.Errorf("model-path is required (flag or sequence YAML)") + return errors.New("model-path is required (flag or sequence YAML)") } // Resolve output diff --git a/cmd/cmd_train.go b/cmd/cmd_train.go index 5b4e849..1bda073 100644 --- a/cmd/cmd_train.go +++ b/cmd/cmd_train.go @@ -10,6 +10,7 @@ package cmd import ( "bufio" "encoding/json" + "errors" "fmt" "log/slog" "os" @@ -17,9 +18,10 @@ import ( "strings" "time" + "forge.lthn.ai/core/cli/pkg/cli" "forge.lthn.ai/core/go-ml" "forge.lthn.ai/core/go-mlx" - "forge.lthn.ai/core/cli/pkg/cli" + "github.com/ollama/ollama/tokenizer" ) var trainCmd = &cli.Command{ @@ -36,15 +38,15 @@ Training data format (one JSON object per line): } var ( - trainModelPath string - trainData string - trainOutput string - trainRank int - trainAlpha float64 - trainLR float64 - trainEpochs int - trainMaxSeqLen int - trainTargets string + trainModelPath string + trainData string + trainOutput string + trainRank int + trainAlpha float64 + trainLR float64 + trainEpochs int + trainMaxSeqLen int + trainTargets string trainMemoryLimit int ) @@ -113,7 +115,7 @@ func runTrain(cmd *cli.Command, args []string) error { slog.Info("training data loaded", "samples", len(samples)) if len(samples) == 0 { - return fmt.Errorf("no training samples loaded") + return errors.New("no training samples loaded") } // --- Training loop --- diff --git a/convert.go b/convert.go index 9babfa5..db42acc 100644 --- a/convert.go +++ b/convert.go @@ -3,6 +3,7 @@ package ml import ( "encoding/binary" "encoding/json" + "errors" "fmt" "log" "maps" @@ -52,7 +53,7 @@ func ReadSafetensors(path string) (map[string]SafetensorsTensorInfo, []byte, err } if len(data) < 8 { - return nil, nil, fmt.Errorf("file too small") + return nil, nil, errors.New("file too small") } headerSize := int(binary.LittleEndian.Uint64(data[:8])) diff --git a/coverage.go b/coverage.go index 4a2363b..98c5d45 100644 --- a/coverage.go +++ b/coverage.go @@ -1,6 +1,7 @@ package ml import ( + "errors" "fmt" "io" "strings" @@ -21,7 +22,7 @@ func PrintCoverage(db *DB, w io.Writer) error { return fmt.Errorf("count seeds: %w (run: core ml import-all first)", err) } if len(rows) == 0 { - return fmt.Errorf("no seeds table found (run: core ml import-all first)") + return errors.New("no seeds table found (run: core ml import-all first)") } total := toInt(rows[0]["total"]) diff --git a/ingest.go b/ingest.go index de894cc..9bd575d 100644 --- a/ingest.go +++ b/ingest.go @@ -3,6 +3,7 @@ package ml import ( "bufio" "encoding/json" + "errors" "fmt" "io" "os" @@ -59,10 +60,10 @@ var ( // At least one of ContentFile, CapabilityFile, or TrainingLog must be set. func Ingest(influx *InfluxClient, cfg IngestConfig, w io.Writer) error { if cfg.ContentFile == "" && cfg.CapabilityFile == "" && cfg.TrainingLog == "" { - return fmt.Errorf("at least one of --content, --capability, or --training-log is required") + return errors.New("at least one of --content, --capability, or --training-log is required") } if cfg.Model == "" { - return fmt.Errorf("--model is required") + return errors.New("--model is required") } if cfg.RunID == "" { cfg.RunID = cfg.Model diff --git a/normalize.go b/normalize.go index eb78bde..fda2daa 100644 --- a/normalize.go +++ b/normalize.go @@ -1,6 +1,7 @@ package ml import ( + "errors" "fmt" "io" "strings" @@ -29,7 +30,7 @@ func NormalizeSeeds(db *DB, cfg NormalizeConfig, w io.Writer) error { fmt.Fprintf(w, "Seeds table: %d rows\n", seedCount) if seedCount == 0 { - return fmt.Errorf("seeds table is empty, nothing to normalize") + return errors.New("seeds table is empty, nothing to normalize") } // 2. Drop and recreate expansion_prompts. diff --git a/publish.go b/publish.go index 5c21118..d3c658a 100644 --- a/publish.go +++ b/publish.go @@ -2,6 +2,7 @@ package ml import ( "bytes" + "errors" "fmt" "io" "net/http" @@ -34,12 +35,12 @@ type uploadEntry struct { // or ~/.huggingface/token, in that order. func Publish(cfg PublishConfig, w io.Writer) error { if cfg.InputDir == "" { - return fmt.Errorf("input directory is required") + return errors.New("input directory is required") } token := resolveHFToken(cfg.Token) if token == "" && !cfg.DryRun { - return fmt.Errorf("HuggingFace token required (--token, HF_TOKEN env, or ~/.huggingface/token)") + return errors.New("HuggingFace token required (--token, HF_TOKEN env, or ~/.huggingface/token)") } files, err := collectUploadFiles(cfg.InputDir) diff --git a/service.go b/service.go index eddcaa9..985e493 100644 --- a/service.go +++ b/service.go @@ -2,6 +2,7 @@ package ml import ( "context" + "errors" "fmt" "iter" "slices" @@ -165,7 +166,7 @@ func (s *Service) Generate(ctx context.Context, backendName, prompt string, opts // ScoreResponses scores a batch of responses using the configured engine. func (s *Service) ScoreResponses(ctx context.Context, responses []Response) (map[string][]PromptScore, error) { if s.engine == nil { - return nil, fmt.Errorf("scoring engine not configured (set JudgeURL and JudgeModel)") + return nil, errors.New("scoring engine not configured (set JudgeURL and JudgeModel)") } return s.engine.ScoreAll(ctx, responses), nil } diff --git a/worker.go b/worker.go index bd0aa3a..7693e03 100644 --- a/worker.go +++ b/worker.go @@ -3,6 +3,7 @@ package ml import ( "bytes" "encoding/json" + "errors" "fmt" "io" "log" @@ -271,7 +272,7 @@ func workerInfer(cfg *WorkerConfig, task APITask) (string, error) { } if len(chatResp.Choices) == 0 { - return "", fmt.Errorf("no choices in response") + return "", errors.New("no choices in response") } content := chatResp.Choices[0].Message.Content From 2c2f2784a9c54549cfadcfb5171f434d37dc6ace Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 16:00:38 +0000 Subject: [PATCH 3/6] =?UTF-8?q?chore:=20sort.Slice=20=E2=86=92=20slices.So?= =?UTF-8?q?rtFunc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/cmd_benchmark.go | 5 +++-- gguf.go | 7 ++++--- status.go | 11 ++++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/cmd/cmd_benchmark.go b/cmd/cmd_benchmark.go index 8baab2f..9970fa9 100644 --- a/cmd/cmd_benchmark.go +++ b/cmd/cmd_benchmark.go @@ -3,6 +3,7 @@ package cmd import ( + "cmp" "context" "encoding/json" "errors" @@ -11,7 +12,7 @@ import ( "math" "os" "runtime" - "sort" + "slices" "time" "forge.lthn.ai/core/cli/pkg/cli" @@ -465,6 +466,6 @@ func loadBenchmarkPrompts() ([]benchPrompt, error) { prompts = append(prompts, benchPrompt{id: id, prompt: r.Prompt}) } - sort.Slice(prompts, func(i, j int) bool { return prompts[i].id < prompts[j].id }) + slices.SortFunc(prompts, func(a, b benchPrompt) int { return cmp.Compare(a.id, b.id) }) return prompts, nil } diff --git a/gguf.go b/gguf.go index a212971..d857fc6 100644 --- a/gguf.go +++ b/gguf.go @@ -1,6 +1,7 @@ package ml import ( + "cmp" "encoding/binary" "encoding/json" "fmt" @@ -8,7 +9,7 @@ import ( "math" "os" "regexp" - "sort" + "slices" "strconv" "strings" ) @@ -174,8 +175,8 @@ func ConvertMLXtoGGUFLoRA(safetensorsPath, configPath, outputPath, architecture } } - sort.Slice(ggufTensors, func(i, j int) bool { - return ggufTensors[i].name < ggufTensors[j].name + slices.SortFunc(ggufTensors, func(a, b ggufTensor) int { + return cmp.Compare(a.name, b.name) }) metadata := []ggufMetadata{ diff --git a/status.go b/status.go index 2c3c013..e4b4f66 100644 --- a/status.go +++ b/status.go @@ -1,9 +1,10 @@ package ml import ( + "cmp" "fmt" "io" - "sort" + "slices" ) // trainingRow holds deduplicated training status + loss for a single model. @@ -146,8 +147,8 @@ func dedupeTraining(statusRows, lossRows []map[string]any) []trainingRow { rows = append(rows, tr) } - sort.Slice(rows, func(i, j int) bool { - return rows[i].model < rows[j].model + slices.SortFunc(rows, func(a, b trainingRow) int { + return cmp.Compare(a.model, b.model) }) return rows @@ -172,8 +173,8 @@ func dedupeGeneration(rows []map[string]any) []genRow { }) } - sort.Slice(result, func(i, j int) bool { - return result[i].worker < result[j].worker + slices.SortFunc(result, func(a, b genRow) int { + return cmp.Compare(a.worker, b.worker) }) return result From bf911d72981d19c0493f449c07932940c8e886aa Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 16:02:03 +0000 Subject: [PATCH 4/6] chore: use min()/max() builtins (Go 1.21+) --- cmd/cmd_benchmark.go | 8 ++++---- heuristic.go | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/cmd/cmd_benchmark.go b/cmd/cmd_benchmark.go index 9970fa9..ec6385a 100644 --- a/cmd/cmd_benchmark.go +++ b/cmd/cmd_benchmark.go @@ -67,10 +67,10 @@ func computeGrammarScore(imp reversal.GrammarImprint) grammarScore { } tenseNorm := gs.TenseEntropy / 1.585 // max entropy for 3 tenses = log2(3) - vocabNorm := math.Min(gs.VocabRichness*10, 1.0) - questionNorm := math.Min(gs.QuestionRatio*5, 1.0) - verbNorm := math.Min(float64(gs.VerbDiversity)/30.0, 1.0) - nounNorm := math.Min(float64(gs.NounDiversity)/40.0, 1.0) + vocabNorm := min(gs.VocabRichness*10, 1.0) + questionNorm := min(gs.QuestionRatio*5, 1.0) + verbNorm := min(float64(gs.VerbDiversity)/30.0, 1.0) + nounNorm := min(float64(gs.NounDiversity)/40.0, 1.0) gs.Composite = 0.25*tenseNorm + 0.25*vocabNorm + diff --git a/heuristic.go b/heuristic.go index 407ac6c..e473ec4 100644 --- a/heuristic.go +++ b/heuristic.go @@ -1,7 +1,6 @@ package ml import ( - "math" "regexp" "strings" ) @@ -122,7 +121,7 @@ func scoreCreativeForm(response string) int { // Metaphor density. metaphorCount := len(metaphorPattern.FindAllString(response, -1)) - score += int(math.Min(float64(metaphorCount), 3)) + score += min(metaphorCount, 3) return score } @@ -147,7 +146,7 @@ func scoreEngagementDepth(response string) int { // Tech depth. techCount := len(techDepthPattern.FindAllString(response, -1)) - score += int(math.Min(float64(techCount), 3)) + score += min(techCount, 3) // Word count bonuses. words := len(strings.Fields(response)) From 4060bc28a344c96abe9deb6e245ac974c3b473c4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 16:02:32 +0000 Subject: [PATCH 5/6] chore: use range-over-integer (Go 1.22+) --- cmd/cmd_train.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/cmd_train.go b/cmd/cmd_train.go index 1bda073..5912372 100644 --- a/cmd/cmd_train.go +++ b/cmd/cmd_train.go @@ -131,7 +131,7 @@ func runTrain(cmd *cli.Command, args []string) error { var totalLoss float64 var totalSteps int - for epoch := 0; epoch < trainEpochs; epoch++ { + for epoch := range trainEpochs { var epochLoss float64 epochStart := time.Now() From b1e6787b24391bc6eeae724e46e7a5671c4b9892 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 24 Feb 2026 16:03:25 +0000 Subject: [PATCH 6/6] chore: use slices.Sorted(maps.Keys()) for ordered iteration --- compare.go | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/compare.go b/compare.go index e46ee86..af8c8a7 100644 --- a/compare.go +++ b/compare.go @@ -2,7 +2,8 @@ package ml import ( "fmt" - "sort" + "maps" + "slices" ) // RunCompare reads two score files and prints a comparison table for each @@ -28,13 +29,7 @@ func RunCompare(oldPath, newPath string) error { } // Sort model names for deterministic output. - sortedModels := make([]string, 0, len(models)) - for m := range models { - sortedModels = append(sortedModels, m) - } - sort.Strings(sortedModels) - - for _, model := range sortedModels { + for _, model := range slices.Sorted(maps.Keys(models)) { oldAvgs := oldOutput.ModelAverages[model] newAvgs := newOutput.ModelAverages[model] @@ -54,13 +49,7 @@ func RunCompare(oldPath, newPath string) error { metrics[k] = true } - sortedMetrics := make([]string, 0, len(metrics)) - for k := range metrics { - sortedMetrics = append(sortedMetrics, k) - } - sort.Strings(sortedMetrics) - - for _, metric := range sortedMetrics { + for _, metric := range slices.Sorted(maps.Keys(metrics)) { oldVal := oldAvgs[metric] newVal := newAvgs[metric] delta := newVal - oldVal