# fix: display the core a request actually dials (mirror list, auth status)

`7fbe7bc`→[main](/content/gh/entireio/cli/commits/main/index.html)·  
Soph·4w ago·8 files·+277 added/-20 removed

The `mirror list` stderr banner re-derived its core via ResolveControlPlaneTarget, which ignores ENTIRE_TOKEN. In env-token mode the request instead dials the token's own aud, so with both ENTIRE_TOKEN and a contexts.json present the banner named a core the request never talks to. The precedence (env-token-then-active-context) lives only inside coreapi.New, and the client hid its resolved core, so every "talking to X" display site was forced to re-derive it and could get it wrong.

Add coreapi.Client.CoreOrigin() — the single source of truth for "which core am I dialing", reporting whatever was wired in (active context, NewForCluster's cluster core, or the ENTIRE_TOKEN aud). Render the mirror list banner from the live client's CoreOrigin so it can never diverge from the request; this also makes it correct (rather than suppressed) in env-token mode.

Fix `entire auth status` the same way: it builds its own /me client outside coreapi, so it now applies the env-token-first precedence and reports the env token's core + bearer instead of a stale active context. logout stays on the active context: it manages a stored session, which an env token lacks.

Extract auth.ParseEnvToken as the single owner of the ENTIRE_TOKEN trim/blank/aud-validation sequence, shared by coreapi.New's bypass and auth status (was duplicated inline in both).

Document the convention in CLAUDE.md: to show which core, ask the client (CoreOrigin); never re-resolve for display.

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

## Sessions

affdb4b52da3View transcript

## Changes

8

- MCLAUDE.md+24

- cmd/entire/cli  
  
  - Mauth.go+43/-1

- auth

- Menv_token.go+19

- Menv_token_test.go+31

- Mauth_test.go+75

- Mrepo_mirror.go+13/-13

- internal/coreapi  
  
  - Mclient.go+14/-6

- Mclient_test.go+58

---

443 unmodified lines

---

### Control-Plane Core Resolution (which core am I talking to?)

Control-plane commands dial one of three cores: the active context's (`coreapi.New`), a specific cluster's (`coreapi.NewForCluster`), or — when `ENTIRE_TOKEN` is set — the env token's `aud` (the bypass inside `New`/`NewForCluster`). This precedence lives **only** inside `coreapi`; nothing else re-derives it.

**To display which core a request uses, ask the client: `client.CoreOrigin()`.** It returns whatever was actually wired in, so the shown core can never diverge from where the request goes. **Do NOT** re-resolve with `auth.ResolveControlPlaneTarget()` for display — it only knows the active context and silently ignores both `ENTIRE_TOKEN` and the cluster case, so it can name a core the request never touches (this was a real bug in the `mirror list` banner; see `repo_mirror.go` and `coreapi.Client.CoreOrigin`).

When a command resolves auth *outside* a `coreapi.Client` (e.g. `entire auth status`, which builds its own `/me` client), it must apply the same env-token-first precedence itself — see `resolveAuthStatusTarget` / `resolveEnvTokenStatusTarget` in `auth.go`, which branch on `auth.EnvTokenVar` before falling back to the active context. `logout` is the deliberate exception: it manages a *stored* login session, which an ephemeral env token has none of, so it stays on the active context.

### Session Strategy (`cmd/entire/cli/strategy/`)

The CLI uses a manual-commit strategy for managing session data and checkpoints.

---

// resolveAuthStatusTarget picks the target for `entire auth status`, honouring  
// ENTIRE_TOKEN: when it is set the request dials the token's own aud (exactly  
// as coreapi.New does), so status must report that core, not a stored context  
// that the request never touches. `logout` deliberately does NOT use this —  
// logout manages a stored login session, which an ephemeral env token has none  
// of, so it stays on resolveStatusTarget (the active context).  
func resolveAuthStatusTarget(ctx context.Context, listContexts contextsProvider, resolveLogin loginTokenResolver) (statusTarget, error) {  
    if raw, ok := os.LookupEnv(auth.EnvTokenVar); ok {  
        return resolveEnvTokenStatusTarget(raw)  
    }  
    return resolveStatusTarget(ctx, listContexts, resolveLogin)  
}

// resolveEnvTokenStatusTarget builds the status target from ENTIRE_TOKEN via the  
// shared auth.ParseEnvToken — the same trim/blank/aud validation coreapi.New  
// applies — so status reports exactly the core a request would dial. The token  
// is the bearer; fail-closed (a blank or malformed value errors, never falls  
// back to a stored context).  
func resolveEnvTokenStatusTarget(raw string) (statusTarget, error) {  
    coreURL, token, err := auth.ParseEnvToken(raw)  
    if err != nil {  
        return statusTarget{}, err //nolint:wrapcheck // auth.ParseEnvToken already prefixes with EnvTokenVar  
    }  
    return statusTarget{coreURL: coreURL, token: token, envToken: true}, nil  
}

// ParseEnvToken is the single owner of the ENTIRE_TOKEN validation sequence  
// shared by coreapi.New's bypass and `entire auth status`: it trims the raw  
// value, enforces fail-closed that it is non-blank, and derives the control-  
// plane core origin from its aud via CoreURLFromEnvToken. Callers pass the raw  
// env value (presence is the caller's LookupEnv decision) and send the returned  
// token verbatim as the bearer to coreURL. A blank or aud-less value is an  
// error, never a silent fall-back to context resolution.  
func ParseEnvToken(raw string) (coreURL, token string, err error) {  
    token = strings.TrimSpace(raw)  
    if token == "" {  
        return "", "", fmt.Errorf("%s is set but blank", EnvTokenVar)  
    }  
    coreURL, err = CoreURLFromEnvToken(token)  
    if err != nil {  
        return "", "", err  
    }  
    return coreURL, token, nil  
}
