From a3e9a1e0355a524115d324d298fb36d83b50d6a2 Mon Sep 17 00:00:00 2001 From: Snider Date: Sun, 22 Feb 2026 19:03:41 +0000 Subject: [PATCH] fix: handle error in score resume merge path ReadScorerOutput error was silently discarded during resume merge, risking partial data loss on TOCTOU file changes. Also clean up compare command construction to pass RunE directly to NewCommand. Co-Authored-By: Claude Opus 4.6 --- cmd/lemcmd/score.go | 15 ++++++++------- pkg/lem/score_cmd.go | 5 ++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/cmd/lemcmd/score.go b/cmd/lemcmd/score.go index 67ea14e..63cf0aa 100644 --- a/cmd/lemcmd/score.go +++ b/cmd/lemcmd/score.go @@ -14,16 +14,17 @@ func addScoreCommands(root *cli.Command) { scoreGroup.AddCommand(passthrough("probe", "Generate responses and score them", lem.RunProbe)) // compare has a different signature — it takes two named args, not []string. - compareCmd := cli.NewCommand("compare", "Compare two score files", "", nil) var compareOld, compareNew string + compareCmd := cli.NewCommand("compare", "Compare two score files", "", + func(cmd *cli.Command, args []string) error { + if compareOld == "" || compareNew == "" { + return fmt.Errorf("--old and --new are required") + } + return lem.RunCompare(compareOld, compareNew) + }, + ) cli.StringFlag(compareCmd, &compareOld, "old", "", "", "Old score file (required)") cli.StringFlag(compareCmd, &compareNew, "new", "", "", "New score file (required)") - compareCmd.RunE = func(cmd *cli.Command, args []string) error { - if compareOld == "" || compareNew == "" { - return fmt.Errorf("--old and --new are required") - } - return lem.RunCompare(compareOld, compareNew) - } scoreGroup.AddCommand(compareCmd) scoreGroup.AddCommand(passthrough("tier", "Score expansion responses (heuristic/judge tiers)", lem.RunTierScore)) diff --git a/pkg/lem/score_cmd.go b/pkg/lem/score_cmd.go index 9e2fb5e..b87587a 100644 --- a/pkg/lem/score_cmd.go +++ b/pkg/lem/score_cmd.go @@ -78,7 +78,10 @@ func RunScore(args []string) { if *resume { if _, statErr := os.Stat(*output); statErr == nil { - existing, _ := ReadScorerOutput(*output) + existing, readErr := ReadScorerOutput(*output) + if readErr != nil { + log.Fatalf("re-read scores for merge: %v", readErr) + } for model, scores := range existing.PerPrompt { perPrompt[model] = append(scores, perPrompt[model]...) }