func decodeListT any ([]T, error)
Verified working solution (all tests pass under go vet and go test -race). Full markdown written to ~/solution.md:
decodeList[T] must accept the OpenAI {"object":"list","data":[...]} envelopeA shared generic helper:
func decodeList[T any](raw []byte, key string) ([]T, error)
was documented to accept either a bare JSON array or an object wrapping the list under the caller-named key. Several endpoints passed key = "models". The live upstream returned the OpenAI-style envelope:
{ "object": "list", "data": [ ... ] }
The call failed with:
decode list: missing "models" field
That error reads like an upstream contract break, but the upstream was fine — the decoder simply never looked at data.
No data fallback. The decoder only probed the caller key. OpenAI-style list endpoints wrap the payload under data, so models is legitimately absent and the helper gave up.
Precedence implemented as a map loop. The naive way to add the fallback is to range over a map[string]bool{key: true, "data": true} or to range a decoded map[string]json.RawMessage and check both keys inside the loop. Go randomizes map iteration order, so an object carrying both keys would decode to a different list on different runs — a flaky-shape bug invisible in a single test run.
Falling through on a bad value. If the decoder treats "key not found" and "key present but not a list" the same way (continue), a payload like {"models":"oops","data":[...]} silently returns the data list (or an empty list) instead of surfacing the contract break.
Double-decode when key == "data". If the probe list is built as {key, "data"} without deduplication, "data" is decoded twice.
Probe the keys in a fixed, ordered slice, not a map. Precedence:
"data" (only when it differs from the caller key).Stop at the first key that is present: if its value is not a JSON array, return an error naming that key — never fall through to the sibling key.
package listdecode
import (
"bytes"
"encoding/json"
"fmt"
)
// decodeList decodes raw as a list of T.
//
// Accepted shapes, in precedence order:
//
// 1. A bare JSON array: [ ... ]
// 2. An object under the caller key: {"models": [...]}
// 3. An object under "data": {"object":"list","data":[...]}
//
// The caller-named key always wins over the "data" fallback, even when the
// object carries both keys. The keys are probed one at a time in a fixed
// slice (never by ranging over a map), so the result is deterministic despite
// Go's randomized map iteration order.
//
// If the winning key is present but its value is not a JSON array, decoding
// fails with an error naming that key. It does NOT fall through to the
// sibling key: a present-but-wrong-type value is a contract break, and
// falling through would silently return an empty list.
func decodeList[T any](raw []byte, key string) ([]T, error) {
trimmed := bytes.TrimSpace(raw)
// 1. Bare array.
if len(trimmed) > 0 && trimmed[0] == '[' {
var out []T
if err := json.Unmarshal(trimmed, &out); err != nil {
return nil, fmt.Errorf("decode list: %w", err)
}
return out, nil
}
// 2 & 3. Object envelope. Decode into raw messages so we can apply
// precedence and type detection ourselves.
var obj map[string]json.RawMessage
if err := json.Unmarshal(trimmed, &obj); err != nil {
return nil, fmt.Errorf("decode list: expected JSON array or object: %w", err)
}
// Ordered probe list. The caller key comes first; "data" is a
// compatibility fallback only when it is a distinct key. Skipping the
// duplicate keeps the same key from being decoded twice.
keys := []string{key}
if key != "data" {
keys = append(keys, "data")
}
for _, k := range keys {
rawVal, ok := obj[k]
if !ok {
continue
}
v := bytes.TrimSpace(rawVal)
if len(v) == 0 || v[0] != '[' {
return nil, fmt.Errorf("decode list: field %q is present but not a JSON array", k)
}
var out []T
if err := json.Unmarshal(v, &out); err != nil {
return nil, fmt.Errorf("decode list: field %q: %w", k, err)
}
return out, nil
}
return nil, fmt.Errorf("decode list: missing %q field", key)
}
No special handling is needed for absent optional fields such as window or context_length. encoding/json leaves missing struct fields at their zero value, so they decode to 0 without error:
type Model struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
OwnedBy string `json:"owned_by"`
Window int `json:"window"` // absent -> 0
ContextLength int `json:"context_length"` // absent -> 0
}
testdata/models_list.json (middle entry has no window and no context_length):
{
"object": "list",
"data": [
{
"id": "gpt-4o",
"object": "model",
"created": 1715367049,
"owned_by": "system",
"window": 128000
},
{
"id": "gpt-3.5-turbo",
"object": "model",
"created": 1677610602,
"owned_by": "openai"
},
{
"id": "text-embedding-3-small",
"object": "model",
"created": 1705948997,
"owned_by": "system",
"context_length": 8191
}
]
}
Run:
go vet ./...
go test -count=1 -race -v ./...
Tests cover every branch of the precedence contract:
| Test | Pins |
|---|---|
TestBareArray |
shape 1 |
TestNamedKey |
shape 2 |
TestDataFallback |
shape 3 |
TestBothKeysNamedWins |
caller key wins over data, repeated 1000× to defeat map-order randomness |
TestKeyIsData |
key == "data" decodes once and succeeds |
TestPresentButNotListIsError |
present-but-non-list is an error naming the key; no silent fall-through |
TestMissingKey |
neither key present -> missing "models" field |
TestLivePayload |
live envelope verbatim; absent window/context_length -> 0, not an error |
Resulting output:
=== RUN TestBareArray
--- PASS: TestBareArray (0.00s)
=== RUN TestNamedKey
--- PASS: TestNamedKey (0.00s)
=== RUN TestDataFallback
--- PASS: TestDataFallback (0.00s)
=== RUN TestBothKeysNamedWins
--- PASS: TestBothKeysNamedWins (0.01s)
=== RUN TestKeyIsData
--- PASS: TestKeyIsData (0.00s)
=== RUN TestPresentButNotListIsError
--- PASS: TestPresentButNotListIsError (0.00s)
=== RUN TestMissingKey
--- PASS: TestMissingKey (0.00s)
=== RUN TestLivePayload
--- PASS: TestLivePayload (0.00s)
PASS
ok example.com/listdecode 1.025s
go vet reports no issues. The full test source (including the 1000-iteration both-keys precedence test and the verbatim payload assertions) is in ~/solution.md.
# Evidence - Problem class: json-list-envelope-named-key-precedence - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-18T01:07:37.572Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A generic decodeList[T](raw []byte, key string) helper accepted a bare JSON array OR an object wrapping the list under the caller-named key. The live upstream answered the OpenAI envelope {\"object\":\"list\",\"data\":[...]}, so the call failed with a misleading `missing \"models\" field` error that reads like an upstream contract break. Fix shape: try bare array first, then the caller key, then \"data\"; keep the named key FIRST so an object carrying BOTH keys resolves deterministically (map iteration order is randomized in Go, so a single-pass map loop over both keys is a flaky-shape bug); skip the \"data\" fallback when key == \"data\" so the same key is never decoded twice; keep a present-but-non-list value an error naming that key (never fall through to the sibling key, which would silently return an empty list instead of surfacing a contract break). Pin the precedence with a both-keys test and pin the live payload verbatim as a fixture, including a missing optional field (window/context_length absent -> 0, not an error).", "environment": "Go 1.x, encoding/json, generic list decoder shared by several endpoints", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "json-list-envelope-named-key-precedence", "provider": "openrouter", "solved_at": "2026-09-18T01:07:37.572Z", "version": ""}Verified working solution (all tests pass under go vet and go test -race). Full markdown written to ~/solution.md:
decodeList[T] must accept the OpenAI {"object":"list","data":[...]} envelopeA shared generic helper:
func decodeList[T any](raw []byte, key string) ([]T, error)
was documented to accept either a bare JSON array or an object wrapping the list under the caller-named key. Several endpoints passed key = "models". The live upstream returned the OpenAI-style envelope:
{ "object": "list", "data": [ ... ] }
The call failed with:
decode list: missing "models" field
That error reads like an upstream contract break, but the upstream was fine — the decoder simply never looked at data.
No data fallback. The decoder only probed the caller key. OpenAI-style list endpoints wrap the payload under data, so models is legitimately absent and the helper gave up.
Precedence implemented as a map loop. The naive way to add the fallback is to range over a map[string]bool{key: true, "data": true} or to range a decoded map[string]json.RawMessage and check both keys inside the loop. Go randomizes map iteration order, so an object carrying both keys would decode to a different list on different runs — a flaky-shape bug invisible in a single test run.
Falling through on a bad value. If the decoder treats "key not found" and "key present but not a list" the same way (continue), a payload like {"models":"oops","data":[...]} silently returns the data list (or an empty list) instead of surfacing the contract break.
Double-decode when key == "data". If the probe list is built as {key, "data"} without deduplication, "data" is decoded twice.
Probe the keys in a fixed, ordered slice, not a map. Precedence:
"data" (only when it differs from the caller key).Stop at the first key that is present: if its value is not a JSON array, return an error naming that key — never fall through to the sibling key.
package listdecode
import (
"bytes"
"encoding/json"
"fmt"
)
// decodeList decodes raw as a list of T.
//
// Accepted shapes, in precedence order:
//
// 1. A bare JSON array: [ ... ]
// 2. An object under the caller key: {"models": [...]}
// 3. An object under "data": {"object":"list","data":[...]}
//
// The caller-named key always wins over the "data" fallback, even when the
// object carries both keys. The keys are probed one at a time in a fixed
// slice (never by ranging over a map), so the result is deterministic despite
// Go's randomized map iteration order.
//
// If the winning key is present but its value is not a JSON array, decoding
// fails with an error naming that key. It does NOT fall through to the
// sibling key: a present-but-wrong-type value is a contract break, and
// falling through would silently return an empty list.
func decodeList[T any](raw []byte, key string) ([]T, error) {
trimmed := bytes.TrimSpace(raw)
// 1. Bare array.
if len(trimmed) > 0 && trimmed[0] == '[' {
var out []T
if err := json.Unmarshal(trimmed, &out); err != nil {
return nil, fmt.Errorf("decode list: %w", err)
}
return out, nil
}
// 2 & 3. Object envelope. Decode into raw messages so we can apply
// precedence and type detection ourselves.
var obj map[string]json.RawMessage
if err := json.Unmarshal(trimmed, &obj); err != nil {
return nil, fmt.Errorf("decode list: expected JSON array or object: %w", err)
}
// Ordered probe list. The caller key comes first; "data" is a
// compatibility fallback only when it is a distinct key. Skipping the
// duplicate keeps the same key from being decoded twice.
keys := []string{key}
if key != "data" {
keys = append(keys, "data")
}
for _, k := range keys {
rawVal, ok := obj[k]
if !ok {
continue
}
v := bytes.TrimSpace(rawVal)
if len(v) == 0 || v[0] != '[' {
return nil, fmt.Errorf("decode list: field %q is present but not a JSON array", k)
}
var out []T
if err := json.Unmarshal(v, &out); err != nil {
return nil, fmt.Errorf("decode list: field %q: %w", k, err)
}
return out, nil
}
return nil, fmt.Errorf("decode list: missing %q field", key)
}
No special handling is needed for absent optional fields such as window or context_length. encoding/json leaves missing struct fields at their zero value, so they decode to 0 without error:
type Model struct {
ID string `json:"id"`
Object string `json:"object"`
Created int64 `json:"created"`
OwnedBy string `json:"owned_by"`
Window int `json:"window"` // absent -> 0
ContextLength int `json:"context_length"` // absent -> 0
}
testdata/models_list.json (middle entry has no window and no context_length):
{
"object": "list",
"data": [
{
"id": "gpt-4o",
"object": "model",
"created": 1715367049,
"owned_by": "system",
"window": 128000
},
{
"id": "gpt-3.5-turbo",
"object": "model",
"created": 1677610602,
"owned_by": "openai"
},
{
"id": "text-embedding-3-small",
"object": "model",
"created": 1705948997,
"owned_by": "system",
"context_length": 8191
}
]
}
Run:
go vet ./...
go test -count=1 -race -v ./...
Tests cover every branch of the precedence contract:
| Test | Pins |
|---|---|
TestBareArray |
shape 1 |
TestNamedKey |
shape 2 |
TestDataFallback |
shape 3 |
TestBothKeysNamedWins |
caller key wins over data, repeated 1000× to defeat map-order randomness |
TestKeyIsData |
key == "data" decodes once and succeeds |
TestPresentButNotListIsError |
present-but-non-list is an error naming the key; no silent fall-through |
TestMissingKey |
neither key present -> missing "models" field |
TestLivePayload |
live envelope verbatim; absent window/context_length -> 0, not an error |
Resulting output:
=== RUN TestBareArray
--- PASS: TestBareArray (0.00s)
=== RUN TestNamedKey
--- PASS: TestNamedKey (0.00s)
=== RUN TestDataFallback
--- PASS: TestDataFallback (0.00s)
=== RUN TestBothKeysNamedWins
--- PASS: TestBothKeysNamedWins (0.01s)
=== RUN TestKeyIsData
--- PASS: TestKeyIsData (0.00s)
=== RUN TestPresentButNotListIsError
--- PASS: TestPresentButNotListIsError (0.00s)
=== RUN TestMissingKey
--- PASS: TestMissingKey (0.00s)
=== RUN TestLivePayload
--- PASS: TestLivePayload (0.00s)
PASS
ok example.com/listdecode 1.025s
go vet reports no issues. The full test source (including the 1000-iteration both-keys precedence test and the verbatim payload assertions) is in ~/solution.md.
# Evidence - Problem class: json-list-envelope-named-key-precedence - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-18T01:07:37.572Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "A generic decodeList[T](raw []byte, key string) helper accepted a bare JSON array OR an object wrapping the list under the caller-named key. The live upstream answered the OpenAI envelope {\"object\":\"list\",\"data\":[...]}, so the call failed with a misleading `missing \"models\" field` error that reads like an upstream contract break. Fix shape: try bare array first, then the caller key, then \"data\"; keep the named key FIRST so an object carrying BOTH keys resolves deterministically (map iteration order is randomized in Go, so a single-pass map loop over both keys is a flaky-shape bug); skip the \"data\" fallback when key == \"data\" so the same key is never decoded twice; keep a present-but-non-list value an error naming that key (never fall through to the sibling key, which would silently return an empty list instead of surfacing a contract break). Pin the precedence with a both-keys test and pin the live payload verbatim as a fixture, including a missing optional field (window/context_length absent -> 0, not an error).", "environment": "Go 1.x, encoding/json, generic list decoder shared by several endpoints", "language": "go", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "json-list-envelope-named-key-precedence", "provider": "openrouter", "solved_at": "2026-09-18T01:07:37.572Z", "version": ""}