cli: address Bugbot/Copilot review on cell routing fallback · Entire

cli: address Bugbot/Copilot review on cell routing fallback

86a21a8→main·

Soph·1w ago·3 files·+24 added/-9 removed

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

Sessions

76ad7ee5e8b2View transcript

?\ Multi-cell Fan-out and Cell Routing InfrastructureClaude Code·Fable 5·4 steps

Changes

3

546 unmodified lines

547
548
549
550
550
551
552
553
554
555
556

546 unmodified lines

var matches []clusterListingRow
    sawJurisdiction := false
    for _, row := range listing.Clusters {
        if row.Jurisdiction != jurisdiction {
        // jurisdiction is already a folded lowercase label (resolveJurisdiction);
        // fold the catalog row too so a differently-cased row still matches
        // instead of misreporting "no cell for jurisdiction".
        if !strings.EqualFold(strings.TrimSpace(row.Jurisdiction), jurisdiction) {
            continue
        }
        sawJurisdiction = true

Mcmd/entire/cli/auth/cell_data_api.go+4/-1

4 unmodified lines

5
6
7
8
9
10
11
2 unmodified lines

14
15
16
17
18
19
20
21
22
23
24
45 unmodified lines

70
71
72
73
74
75
76
77
78

4 unmodified lines

"errors"
    "io"
    "strings"
    "time"

"github.com/entireio/cli/cmd/entire/cli/api"
    "github.com/entireio/cli/cmd/entire/cli/auth"
2 unmodified lines

"github.com/entireio/cli/internal/coreapi"
// currentRepoIDTimeout bounds currentRepoID's control-plane lookup. The lookup
// is best-effort decoration (recap degrades to personal-only without it), so a
// stalled core must not hang the command — mirror expertsCellResolveTimeout.
const currentRepoIDTimeout = 5 * time.Second

// runAuthenticatedActivityAPI runs fn with an authenticated client for the
// activity/recap surface. It prefers the caller's home entire-api cell (the same
// shared client the experts commands use), which serves the /me/* endpoints
45 unmodified lines

// no extra resolution is needed. Any failure returns "" — recap then shows the
// personal side only rather than erroring.
func currentRepoID(ctx context.Context) string {
    ctx, cancel := context.WithTimeout(ctx, currentRepoIDTimeout)
    defer cancel()

forge, owner, repo, err := gitremote.ResolveRemoteRepo(ctx, "origin")
    if err != nil {
        return ""

Mcmd/entire/cli/entireapi_client.go+9

122 unmodified lines

123
124
125
126
126
127
128
129
13 unmodified lines

143
144
145
146
146
147
148
149
1 unmodified line

151
152
153
154
154
155
156
157
158
159
160
160
161
162
163
30 unmodified lines

194
195
196
197
198
199
200
197
198
199
200
201
202
203
204
205
206

122 unmodified lines

if err != nil {
        return err
    }
    client, repoSlug, err := newRecapClient(ctx, f.insecureHTTP)
    client, repoScope, err := newRecapClient(ctx, f.insecureHTTP)
    if err != nil {
        if errors.Is(err, api.ErrInsecureHTTP) {
            fmt.Fprintf(errW, "ENTIRE_API_BASE_URL is set to an insecure http:// URL (%s). Use https:// for production, or pass --insecure-http-auth for local dev.\n", api.BaseURL())
        }
13 unmodified lines

// actually scoped (a repo query was sent), so an unscoped recap isn't
    // mislabelled as scoped to the current repo.
    repoName := ""
    if repoSlug != "" {
        if repoScope != "" {
            repoName = currentRepoSlug(ctx)
        }
        if f.useTUI(interactive.IsTerminalWriter(w), interactive.CanPromptInteractively(), IsAccessibleMode()) {
1 unmodified line

Range:    rangeKey,
            View:     mode,
            Agent:    f.agentName(),
            Repo:     repoSlug,
            Repo:     repoScope,
            RepoName: repoName,
            Color:    color,
        })
    }
    start, end := rangeKey.Bounds(time.Now())
    resp, err := recap.FetchMeRecap(ctx, client, start, end, repoSlug, 0)
    resp, err := recap.FetchMeRecap(ctx, client, start, end, repoScope, 0)
    if err != nil {
        return handleRecapFetchError(errW, err)
    }
30 unmodified lines

// the data API (which addresses them by name). Empty when the current repo
// can't be resolved — recap then shows the personal side only.
//
// It prefers the caller's home entire-api cell (the shared client), falling back
// to the data API when the region has no cell yet (ErrNoCellForJurisdiction) or
// the caller isn't logged in — recap tolerates the latter, rendering and letting
// the server answer 401 rather than hard-failing. Every other failure surfaces.
// It prefers the caller's home entire-api cell (the shared client) and falls
// back to the data API on ANY cell-client failure — the cell path is a
// best-effort upgrade, so a cell problem must never break a command that worked
// before it existed. Expected fallbacks (region has no cell yet, not logged in)
// are silent; unexpected ones are debug-logged (logCellClientFallback). Only
// failures of the data-API path itself surface — except ErrNotLoggedIn, which
// recap tolerates, rendering and letting the server answer 401.
func newRecapClient(ctx context.Context, insecureHTTP bool) (*api.Client, string, error) {
    // Best-effort upgrade: on any cell failure fall back to the data API path
    // below, which tolerates a missing login (renders, lets the server 401) so