# Merge pull request #1663 from entireio/soph/loosen-repo-list-enums

`21a7b10`→[main](/content/gh/entireio/cli/commits/main/index.html) · gtrrz-victor · 1w ago · 10 files · +160 added/-720 removed

fix(coreapi): loosen display-only Repo read enums for forward-compat

## Changes

10

- cmd/entire/cli

- Mrepo.go +1/-5

- Mrepo_test.go +1/-1

- internal/coreapi

- MUPSTREAM.md +22

- Mclient_test.go +45

- Moas_json_gen.go -221

- Moas_response_decoders_gen.go -27

- Moas_schemas_gen.go +20/-288

- Moas_validators_gen.go -156

- spec

- Mcore.gen.json -13

- Mnormalize.go +71/-9

```go
var repoColumns = []string{"ID", "NAME", "PROJECT", "CLUSTER", "STATE"}

func repoRow(r coreapi.Repo) []string {
    state := ""
    if v, ok := r.State.Get(); ok {
        state = string(v)
    }
    return []string{r.ID, r.Name, r.OwningProjectId, r.ClusterHost.Or("-"), state}
}
return []string{r.ID, r.Name, r.OwningProjectId, r.ClusterHost.Or("-"), r.State.Or("-")}
// repoDetailColumns / repoDetailRow extend the shared repo view with the
```

## 2. Display-only read enums hard-fail on unknown values

**Symptom:** read-model string fields the CLI only displays (`Repo.state`, `Repo.visibility`, `Repo.objectFormat`) are declared as `enum`. ogen turns each into a named type with a strict `Validate()` that the response decoder calls unconditionally, so the day the server adds a new value (a new repo lifecycle state, say) the whole `repo list` / repo-get request fails to decode — even though the client never branches on the value.

**Fix upstream:** model client-display fields that may grow new values as plain strings (drop `enum`), or have ogen treat them as open enums. Enums the *client sends* (request bodies like `SetRepoVisibilityInputBody`) should stay strict.

**Workaround:** `spec/normalize.go` (`loosenReadModelEnums`, allowlist `readModelEnumFields`) deletes the `enum` constraint from those response read-model fields, so ogen emits plain strings with no `Validate()` and unknown values pass through for display. Only response read models are loosened; request-body enums stay strict. Locked in by `TestListProjectRepos_UnknownEnumValuesPassThrough` in `client_test.go`.

### Test Function Example

```go
func TestListProjectRepos_UnknownEnumValuesPassThrough(t *testing.T) {
    t.Parallel()

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
        w.Header().Set("Content-Type", "application/json")
        w.WriteHeader(http.StatusOK)
        // Values the current spec's enums did NOT allow.
        if _, err := w.Write([]byte(`{"repos":[{"id":"01H000000000000000000000A1","owningProjectId":"01H000000000000000000000P1","name":"demo","state":"archiving","visibility":"internal","objectFormat":"sha512"}]}`)); err != nil {
            t.Errorf("writing test response: %v", err)
        }
    }))
    t.Cleanup(srv.Close)

c, err := NewClient(srv.URL, bearerOnlySource{})
    if err != nil {
        t.Fatalf("NewClient: %v", err)
    }

out, err := c.ListProjectRepos(context.Background(), ListProjectReposParams{ProjectId: "01H000000000000000000000P1"})
    if err != nil {
        t.Fatalf("ListProjectRepos with unknown enum values must not fail (forward-compat), got: %v", err)
    }
    if len(out.Repos) != 1 {
        t.Fatalf("Repos len = %d, want 1", len(out.Repos))
    }
    repo := out.Repos[0]
    if got := repo.State.Or(""); got != "archiving" {
        t.Errorf("State = %q, want the unknown value %q passed through verbatim", got, "archiving")
    }
    if got := repo.Visibility.Or(""); got != "internal" {
        t.Errorf("Visibility = %q, want the unknown value %q passed through verbatim", got, "internal")
    }
    if got := repo.ObjectFormat.Or(""); got != "sha512" {
        t.Errorf("ObjectFormat = %q, want the unknown value %q passed through verbatim", got, "sha512")
    }
}
```

## File Modifications
```go
internal/coreapi/UPSTREAM.md +22
internal/coreapi/client_test.go +45
internal/coreapi/oas_json_gen.go -221
internal/coreapi/oas_response_decoders_gen.go -27
internal/coreapi/oas_schemas_gen.go +20/-288
internal/coreapi/oas_validators_gen.go -156
spec/core.gen.json -13
spec/normalize.go +71/-9
```
