Skip to content

Use a numeric --in as given, without walking /projects.json - #916

Merged
jeremy merged 2 commits into
mainfrom
resolve-numeric-project-without-listing
Oct 19, 2026
Merged

jeremy merged 2 commits into
mainfrom
resolve-numeric-project-without-listing

Conversation

@jeremy

@jeremy jeremy commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

What

A numeric project ID (--in 123, --project 123) is now used as given, with no request. Until now ResolveProject walked every page of /projects.json (resolver.go:432) to find the project's name. It did this on every command that takes --in <id>. Most of the 85 callers discard the name. An ID that wasn't in the list was already passed through for the API to judge, so the walk validated nothing.

The name comes back only when the session already holds the project list. The two callers that show it now get it another way:

  • config project --project <id> reads that one project with the new ProjectName (GET /projects/<id>.json) to confirm the project exists before saving it. A 404 or 403 still says "not found".
  • timeline --in <id> takes the name from the events' bucket. With no events it falls back to "project #id", the fallback it already had.

Name resolution (--in "Project name") is unchanged and still lists projects.

Why

BC5's API hosts are short of CPU. See this Basecamp card: Ops found that basecamp-cli/* requests use 18% of Rails CPU on the API hosts, and that ProjectsController#index is the third most expensive endpoint there.

In 5 minutes of API-host logs (19 Oct, 18:56–19:01 UTC), the CLI's ProjectsController#index requests used about 193 s of CPU. About 4.5% of all API-host Rails CPU in that window went to these walks. 161 s of it came from requests that sent If-None-Match, and only the SDK's raw GetAll path sends that on page 1, which is the path this resolver uses. Those requests broke down as:

  • about 3,500 page-1 requests, one per walk,
  • about 4,200 later pages,
  • 109 s spent answering 304s.

The bug-triage tooling we run ourselves calls basecamp cards list --in <id> and its siblings many times per sync. Each call walked the whole list first.

Name-based --in still walks the list, and versions already installed keep walking until they upgrade. #909 (pace every request) is complementary to this change, not overlapping.

Behaviour changes

  • An archived project's ID now gets its name from config project, so it can be saved. Before, the archived project was missing from the active list, so it was refused as not found.
  • An ID with leading zeros is normalized ("00123" → "123") without a list lookup. Before, it was normalized only when the list had it, and otherwise passed through as typed.

Testing

  • New resolver tests:
    • a numeric ID makes no request at all;
    • ProjectName reads exactly one project;
    • a 404 or 403 gives an empty name;
    • a 500 is an error;
    • a project missing from a cached list (an archived one) is still read by ID;
    • 00123 and +123 resolve to 123.
  • The template-copy tests now expect one request fewer: the walk they used to record is gone.
  • The config tests serve /projects/<id>.json.
  • bin/ci exits 0 on Linux at 47125c4.
    • On macOS, make lint flags internal/connector/driver/proctime_darwin.go (gosec G115, unconvert). That fails on main too and is untouched here.

Summary by cubic

A numeric project ID (--in 123, --project 123) is now used as given, without walking every page of /projects.json first. That walk ran on every command taking --in <id> and returned a name most callers discard; the API-host CPU cost it caused was called out by Ops as significant.

Behavior changes

  • config project --project <id> reads that one project (GET /projects/<id>.json) to confirm it exists before saving.
  • timeline --in <id> takes the project name from the events' bucket, keeping the fallback format for empty timelines.
  • An archived project's ID is now accepted by config project; ProjectName reads the project itself when it is missing from the session's active-only list.
  • Numeric IDs are canonicalized ("00123" → "123") even without a cached list, so callers that compare IDs with bucket strings still match.
  • Name-based resolution (--in "Name") is unchanged and still lists projects.

Written for commit 47125c4. Summary will update on new commits.

View guided diff Turn on auto-fix

Resolving a numeric project ID walked every page of /projects.json to find
the project's name, on every command given --in <id>. Most callers discard
the name, and an ID missing from the list was already passed through for the
API to judge, so the walk bought nothing but a request per page.

A numeric ID now resolves with no request. Its name comes back only when the
session already holds the project list. The two callers that show it get it
another way: config project reads that one project (ProjectName) to confirm
it exists before saving it, and timeline takes it from the events' bucket.
Copilot AI balanced review requested due to automatic review settings October 19, 2026 19:37
@jeremy
jeremy requested a review from a team as a code owner October 19, 2026 19:37
@github-actions github-actions Bot added commands CLI command implementations tests Tests (unit and e2e) labels Oct 19, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-19T21:17:01.801547Z 47125c4 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 589b1aeb82

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/names/resolver.go

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A populated active-project cache incorrectly prevents name lookup for accessible archived projects.

1 open issue
What changed in this PR

This PR reduces API load by using numeric project IDs without listing projects, complementing #909’s request pacing.

Changes:

  • Skip project-list requests for numeric IDs.
  • Fetch project names directly for configuration and from event buckets for timelines.
  • Update tests for lookup behavior and reduced request counts.

[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or run gh pr ready --undo.
Click "Ready for review" or run gh pr ready to reengage.

File Description
internal/​names/​resolver.go Adds numeric-ID passthrough and direct name lookup.
internal/​names/​resolver_test.go Tests request counts, caching, and lookup errors.
internal/​commands/​timeline.go Uses event buckets for project names.
internal/​commands/​templates_test.go Updates expected request counts.
internal/​commands/​config.go Looks up unnamed projects before saving.
internal/​commands/​config_test.go Serves individual project lookup responses.

Review effort: Balanced

Comment thread internal/names/resolver.go Outdated
ResolveProject now returns a numeric ID in canonical form ("00123" →
"123") even when no project list is cached. Callers such as the wormhole
conflict check compare it with bucket IDs as strings, so passing the
spelling through as typed rejected a same-project move.

ProjectName uses the session's project list only for a positive match.
That list holds active projects only, so a miss falls through to reading
the one project, as a fresh resolver already did; an archived project's
name no longer depends on whether the list was fetched first.
Copilot AI balanced review requested due to automatic review settings October 19, 2026 20:55
Copilot AI previously approved these changes Oct 19, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

The focused changes preserve name-based resolution and cover numeric-ID behavior without identified blocking issues.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@jeremy
jeremy requested a balanced review from Copilot October 19, 2026 21:00
@jeremy

jeremy commented Oct 19, 2026

Copy link
Copy Markdown
Member Author

@codex review

Copilot AI dismissed their stale review, a newer Copilot review was requested October 19, 2026 21:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approved

The focused changes have supporting regression coverage and no unresolved findings; tests were not executed during this review.

No open issues 🎉

Review effort: Balanced

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. You're on a roll.

Reviewed commit: 47125c4841

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@jeremy

jeremy commented Oct 19, 2026

Copy link
Copy Markdown
Member Author

Review threads: 2 resolved (2 fixed in 47125c4: numeric IDs come back canonical, and a project missing from the cached list is read by ID).
Nothing open on 47125c4: CI is green, Copilot approved it, and Codex finished with no findings.

@jeremy
jeremy merged commit 6de515f into main Oct 19, 2026
33 checks passed
@jeremy
jeremy deleted the resolve-numeric-project-without-listing branch October 19, 2026 22:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands CLI command implementations tests Tests (unit and e2e)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants