# refactor(control-plane): resolve names server-side, drop client-side filtering

`7144c12`→[main](/content/gh/entireio/cli/commits/main/index.html)·

toothbrush·3w ago·3 files·+111 added/-215 removed

The control plane now does O(1), case-insensitive by-name lookups for orgs,
projects, and org-scoped projects (lower(name) indexes). Delegate to it and
delete the CLI's "list everything then filter" code.

- regenerate coreapi client: ListOrgs gains a name param + singular `org` in
  its response; GET /orgs/{orgId}/projects gains a name param + singular
  `project` (spec hand-authored ahead of deploy; idempotent on real refresh)
- resolveOrgRef/resolveProjectRef read the singular match the server returns
  and map 404 to a friendly "no X named" error
- project list --org --name now filters server-side instead of client-side
- drop pickOrg, pickProject, filterProjectsByName

Also fixes a latent bug: the name paths read out.Projects, but the server
returns a name match under the singular out.Project, so an existing project
resolved as "not found". Now reads the correct field.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

## Sessions

bb17fef4a163View transcript

## Changes

3

- cmd/entire/cli

- Mproject.go+23/-7
  
  - Mresolveref.go+48/-76
  
  - Mresolveref_test.go+40/-132

```go
92 unmodified lines
```

```go
1 unmodified line
```

#### Code Block

```go
// many places (repo create --project, project create --owner, grant org/project
// <id>, …). ULIDs are unfriendly to type, so these refs also accept a human
// name: looksLikeULID decides which form was given, and the resolveXRef helpers
// turn a name into its ULID via a list lookup. A ULID is always passed straight
// through with no network call, preserving the original behavior exactly.
// turn a name into its ULID. A ULID is always passed straight through with no
// network call. A name is resolved by the control plane's O(1), case-insensitive
// by-name lookup (the server matches on lower(name) and returns the single match
// under the response's singular `org`/`project` field, or 404) — the CLI never
// lists everything and filters client-side.
```

## Function Definitions

### isCoreNotFound

```go
// isCoreNotFound reports whether err is a control-plane 404. The by-name lookups
// (ListOrgs/ListProjects/ListOrgProjects with ?name=) return 404 when nothing
// matches; callers turn that into a friendly "no X named" message.
func isCoreNotFound(err error) bool {
    var se *coreapi.ErrorModelStatusCode
    return errors.As(err, &se) && se.StatusCode == http.StatusNotFound
}
```

### resolveOrgRef

```go
// resolveOrgRef turns an org reference (ULID or name) into its ULID. A ULID is
// returned unchanged; a name is looked up against the caller's visible orgs.
// returned unchanged; a name is resolved via the server's case-insensitive
// by-name lookup.
func resolveOrgRef(ctx context.Context, c *coreapi.Client, ref string) (string, error) {
    if looksLikeULID(ref) {
        return ref, nil
    }
    out, err := c.ListOrgs(ctx)
    out, err := c.ListOrgs(ctx, coreapi.ListOrgsParams{Name: coreapi.NewOptString(ref)})
    if err != nil {
        if isCoreNotFound(err) {
            return "", noOrgNamedErr(ref)
        }
        return "", err
    }
    return pickOrg(out.Orgs, ref)
    org, ok := out.Org.Get()
    if !ok {
        return "", noOrgNamedErr(ref)
    }
    return org.ID, nil
}
```

### resolveProjectRef

```go
// resolveProjectRef turns a project reference (ULID or name) into its ULID. A
// ULID is returned unchanged; a name is looked up via the server's name filter
// (the same call `entire project list --name` uses). Name matching is
// case-insensitive end to end: the server enforces lower(name) uniqueness and
// pickProject re-checks with EqualFold, so case-only differences resolve.
func resolveProjectRef(ctx context.Context, c *coreapi.Client, ref string) (string, error) {
    if looksLikeULID(ref) {
        return ref, nil
    }
    out, err := c.ListProjects(ctx, coreapi.ListProjectsParams{Name: coreapi.NewOptString(ref)})
    if err != nil {
        if isCoreNotFound(err) {
            return "", noProjectNamedErr(ref)
        }
        return "", err
    }
    return pickProject(out.Projects, ref)
    project, ok := out.Project.Get()
    if !ok {
        return "", noProjectNamedErr(ref)
    }
    return project.ID, nil
}
```

### Testing Functions

```go
// TestResolveOrgRef tests the resolveOrgRef function
func TestResolveOrgRef(t *testing.T) {
    // Test implementation
}
// TestResolveProjectRef tests the resolveProjectRef function
func TestResolveProjectRef(t *testing.T) {
    // Test implementation
}
```
