fix(14): WR-05 import every key of an object-shaped models repeater

A repeater saved with non-sequential keys was read only at keys 0 to
len-1, so a model at a higher key was dropped while the import reported
success and refused to run again. Every key is now read, numeric keys in
ascending order.
This commit is contained in:
Jakub Zych
2026-10-04 08:08:44 +02:00
parent 93b2b05476
commit 9f60b6138c
2 changed files with 44 additions and 5 deletions

View File

@@ -2,12 +2,15 @@
package console
import (
"cmp"
"context"
"encoding/json"
"errors"
"fmt"
"maps"
"math"
"os"
"slices"
"strconv"
"strings"
@@ -150,11 +153,11 @@ func repeaterItems(raw []byte) ([]map[string]any, error) {
case []any:
list = t
case map[string]any:
// A repeater saved with non-sequential keys decodes as an object.
for i := 0; i < len(t); i++ {
if item, ok := t[strconv.Itoa(i)]; ok {
list = append(list, item)
}
// A repeater saved with non-sequential keys decodes as an object
// ({"0":…,"2":…} after a middle item was deleted). Every key is
// read, numeric keys in ascending order, then any other key.
for _, k := range repeaterKeys(t) {
list = append(list, t[k])
}
case nil:
default:
@@ -169,6 +172,26 @@ func repeaterItems(raw []byte) ([]map[string]any, error) {
return out, nil
}
// repeaterKeys orders an object repeater's keys: integers ascending by
// value first, then the other keys in byte order.
func repeaterKeys(t map[string]any) []string {
keys := slices.Collect(maps.Keys(t))
slices.SortFunc(keys, func(a, b string) int {
ai, aerr := strconv.Atoi(a)
bi, berr := strconv.Atoi(b)
switch {
case aerr == nil && berr == nil:
return cmp.Compare(ai, bi)
case aerr == nil:
return -1
case berr == nil:
return 1
}
return strings.Compare(a, b)
})
return keys
}
func modelFromItem(item map[string]any) models.AiModel {
row := models.AiModel{
Name: str(item["name"]),