Absorb everything-aggregates bucket-grouped family (bc3 #11627, PR-5b of 2)#438
Absorb everything-aggregates bucket-grouped family (bc3 #11627, PR-5b of 2)#438jeremy wants to merge 1 commit into
Conversation
…R-5b of 2)
Complete the everything-aggregates absorption with the second contract family:
the 9 todo/card filter sub-routes that return a Link-paginated array of buckets,
each grouping the matching recordings (with their embedded steps) under their
parent project.
- 9 operations on EverythingService: GetEverythingOpen/Completed/Unassigned/
NoDueDate Todos and Open/Completed/Unassigned/NoDueDate/NotNow Cards, each
Link-paginated with a single-member output → bare array of groups via the
smithy-bare-arrays transform.
- Group shapes BucketTodosGroup {bucket, todos} and BucketCardsGroup
{bucket, cards}, reusing the full Todo/Card shapes (which already model steps,
assignees, due_on, etc.). Kotlin needed both group types added to the
generator TYPE_ALIASES to emit typed models.
- Go wrappers (OpenTodos/… and OpenCards/…/NotNowCards) with multi-page
Link-following; Go tests cover multi-page pagination and the
{bucket, todos|cards}-with-steps grouping.
All 17 everything routes are now modeled, generated across the six SDKs,
Go-wrapped, and decode-tested, so everything-aggregates.md flips to
absorbed-in-sdk. Conformance paths.json path-assertions + per-runner dispatch
and per-group live-canary entries remain as supplementary verification infra
(the live canary is dormant); the modeled surface itself is complete.
Spec Change ImpactSummary of Changes
Breaking API ChangeYes, this change removes the SDK Regeneration RequiredThis change affects all SDKs due to modifications in type definitions and resource structure. Checklist of SDKs Needing Updates:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 04279fa186
ℹ️ 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".
| @basecampRetry(maxAttempts: 3, baseDelayMs: 1000, backoff: "exponential", retryOn: [429, 503]) | ||
| @basecampPagination(style: "link", totalCountHeader: "X-Total-Count", maxPageSize: 50) | ||
| @http(method: "GET", uri: "/{accountId}/todos/open.json") | ||
| operation GetEverythingOpenTodos { |
There was a problem hiding this comment.
Add required cross-SDK tests for the nine operations
These nine new wire operations are generated for TypeScript, Ruby, and Python, but this commit adds no corresponding service tests; repo-wide searches of the existing Everything test files find none of the new todo/card methods. Consequently, their paths, pagination, response decoding, and error handling can regress without coverage, and the repository explicitly requires happy-path and error tests in all three SDKs for every new operation.
AGENTS.md reference: AGENTS.md:L295-L307
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
This PR completes the everything-aggregates absorption by modeling the bucket-grouped todo/card filter sub-routes (9 ops) and fanning them out through Smithy → OpenAPI → generated SDKs, plus Go wrappers + tests and registry flip to absorbed-in-sdk.
Changes:
- Adds 9 Everything aggregate filter operations (todos + cards) returning Link-paginated arrays of
{ bucket, todos|cards }groups. - Introduces
BucketTodosGroup/BucketCardsGroupmodels across SDKs and updates generator wiring/metadata. - Updates Go wrappers + tests for multi-page Link-following and grouped decode; flips the api-gap entry to absorbed.
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.
Reviewed changes
Copilot reviewed 9 out of 30 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| behavior-model.json | Registers readonly/pagination/retry behavior for the new Everything operations. |
| go/pkg/basecamp/everything.go | Adds Go wrapper APIs and group types for bucket-grouped todo/card filters. |
| go/pkg/basecamp/everything_test.go | Adds decode/pagination tests for the new bucket-grouped Everything wrappers. |
| go/pkg/basecamp/url-routes.json | Adds route metadata for the new Everything endpoints. |
| kotlin/generator/src/main/kotlin/com/basecamp/sdk/generator/Config.kt | Adds type aliases so the Kotlin generator emits typed models for the new group shapes. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/Metadata.kt | Adds retry configuration entries for the new operations. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/models/BucketCardsGroup.kt | Adds Kotlin model for {bucket, cards} group entries. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/models/BucketTodosGroup.kt | Adds Kotlin model for {bucket, todos} group entries. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/services/everything.kt | Adds Kotlin service methods for the new bucket-grouped filters. |
| python/src/basecamp/generated/metadata.json | Adds retry config entries for the new Everything operations. |
| python/src/basecamp/generated/services/everything.py | Adds sync/async Python service methods for the new bucket-grouped filters. |
| python/src/basecamp/generated/types.py | Adds BucketTodosGroup / BucketCardsGroup TypedDicts. |
| ruby/lib/basecamp/generated/metadata.json | Adds retry/pagination metadata for the new operations. |
| ruby/lib/basecamp/generated/services/everything_service.rb | Adds Ruby generated service methods for the new bucket-grouped filters. |
| ruby/lib/basecamp/generated/types.rb | Adds Ruby generated type classes for the new group shapes. |
| spec/api-gaps/README.md | Flips everything-aggregates registry status to absorbed-in-sdk. |
| spec/api-gaps/everything-aggregates.md | Marks absorption complete and records Smithy refs for bucket-grouped family + shapes. |
| spec/basecamp.smithy | Adds Smithy operations + shapes for the bucket-grouped todo/card filter family. |
| spec/overlays/tags.smithy | Tags the new operations under the Everything service grouping. |
| swift/Sources/Basecamp/Generated/Metadata.swift | Adds retry config entries for the new Everything operations. |
| swift/Sources/Basecamp/Generated/Models/BucketCardsGroup.swift | Adds Swift model for {bucket, cards} group entries. |
| swift/Sources/Basecamp/Generated/Models/BucketTodosGroup.swift | Adds Swift model for {bucket, todos} group entries. |
| swift/Sources/Basecamp/Generated/Services/EverythingService.swift | Adds Swift service methods + pagination options structs for the new endpoints. |
| typescript/src/generated/metadata.ts | Adds retry/pagination metadata for the new Everything operations. |
| typescript/src/generated/path-mapping.ts | Maps new Everything paths to their operation names. |
| typescript/src/generated/schema.d.ts | Adds new paths/operations/schemas for bucket-grouped Everything filters. |
| typescript/src/generated/services/everything.ts | Adds TypeScript EverythingService methods + options types for the new endpoints. |
Comments suppressed due to low confidence (8)
go/pkg/basecamp/everything.go:495
- The
pageargument is documented as selecting a specific page, but this call always fetches page 1 because nopagequery is ever set. Passingpage=2will still return the first page (and just disables auto-pagination). Consider adding a per-request editor to set?page=whenpage > 0so callers can request an explicit page number.
r, err := s.client.parent.gen.GetEverythingCompletedTodosWithResponse(ctx, s.client.accountID)
if err != nil {
return nil, err
}
return s.finishTodoGroupsPage(ctx, r.HTTPResponse, r.Body, r.JSON200, page)
go/pkg/basecamp/everything.go:509
- The
pageargument is documented as selecting a specific page, but this call always fetches page 1 because nopagequery is ever set. Passingpage=2will still return the first page (and just disables auto-pagination). Consider adding a per-request editor to set?page=whenpage > 0so callers can request an explicit page number.
r, err := s.client.parent.gen.GetEverythingUnassignedTodosWithResponse(ctx, s.client.accountID)
if err != nil {
return nil, err
}
return s.finishTodoGroupsPage(ctx, r.HTTPResponse, r.Body, r.JSON200, page)
go/pkg/basecamp/everything.go:523
- The
pageargument is documented as selecting a specific page, but this call always fetches page 1 because nopagequery is ever set. Passingpage=2will still return the first page (and just disables auto-pagination). Consider adding a per-request editor to set?page=whenpage > 0so callers can request an explicit page number.
r, err := s.client.parent.gen.GetEverythingNoDueDateTodosWithResponse(ctx, s.client.accountID)
if err != nil {
return nil, err
}
return s.finishTodoGroupsPage(ctx, r.HTTPResponse, r.Body, r.JSON200, page)
go/pkg/basecamp/everything.go:537
- The
pageargument is documented as selecting a specific page, but this call always fetches page 1 because nopagequery is ever set. Passingpage=2will still return the first page (and just disables auto-pagination). Consider adding a per-request editor to set?page=whenpage > 0so callers can request an explicit page number.
r, err := s.client.parent.gen.GetEverythingOpenCardsWithResponse(ctx, s.client.accountID)
if err != nil {
return nil, err
}
return s.finishCardGroupsPage(ctx, r.HTTPResponse, r.Body, r.JSON200, page)
go/pkg/basecamp/everything.go:551
- The
pageargument is documented as selecting a specific page, but this call always fetches page 1 because nopagequery is ever set. Passingpage=2will still return the first page (and just disables auto-pagination). Consider adding a per-request editor to set?page=whenpage > 0so callers can request an explicit page number.
r, err := s.client.parent.gen.GetEverythingCompletedCardsWithResponse(ctx, s.client.accountID)
if err != nil {
return nil, err
}
return s.finishCardGroupsPage(ctx, r.HTTPResponse, r.Body, r.JSON200, page)
go/pkg/basecamp/everything.go:565
- The
pageargument is documented as selecting a specific page, but this call always fetches page 1 because nopagequery is ever set. Passingpage=2will still return the first page (and just disables auto-pagination). Consider adding a per-request editor to set?page=whenpage > 0so callers can request an explicit page number.
r, err := s.client.parent.gen.GetEverythingUnassignedCardsWithResponse(ctx, s.client.accountID)
if err != nil {
return nil, err
}
return s.finishCardGroupsPage(ctx, r.HTTPResponse, r.Body, r.JSON200, page)
go/pkg/basecamp/everything.go:579
- The
pageargument is documented as selecting a specific page, but this call always fetches page 1 because nopagequery is ever set. Passingpage=2will still return the first page (and just disables auto-pagination). Consider adding a per-request editor to set?page=whenpage > 0so callers can request an explicit page number.
r, err := s.client.parent.gen.GetEverythingNoDueDateCardsWithResponse(ctx, s.client.accountID)
if err != nil {
return nil, err
}
return s.finishCardGroupsPage(ctx, r.HTTPResponse, r.Body, r.JSON200, page)
go/pkg/basecamp/everything.go:594
- The
pageargument is documented as selecting a specific page, but this call always fetches page 1 because nopagequery is ever set. Passingpage=2will still return the first page (and just disables auto-pagination). Consider adding a per-request editor to set?page=whenpage > 0so callers can request an explicit page number.
r, err := s.client.parent.gen.GetEverythingNotNowCardsWithResponse(ctx, s.client.accountID)
if err != nil {
return nil, err
}
return s.finishCardGroupsPage(ctx, r.HTTPResponse, r.Body, r.JSON200, page)
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| r, err := s.client.parent.gen.GetEverythingOpenTodosWithResponse(ctx, s.client.accountID) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return s.finishTodoGroupsPage(ctx, r.HTTPResponse, r.Body, r.JSON200, page) |
There was a problem hiding this comment.
3 issues found across 30 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="go/pkg/basecamp/everything.go">
<violation number="1" location="go/pkg/basecamp/everything.go:477">
P2: Passing a positive `page` currently only disables Link-following but still fetches the first page, because the initial request never sends a `page` query parameter. This makes `page` behave differently from its doc comment and can return unexpected results for explicit-page callers.</violation>
<violation number="2" location="go/pkg/basecamp/everything.go:625">
P3: Pagination behavior now has two near-identical implementations. Future fixes to Link handling, metadata, or decode errors can diverge; extract the shared page-finalization flow with typed conversion callbacks, leaving only todo/card conversion local.</violation>
</file>
<file name="typescript/src/generated/services/everything.ts">
<violation number="1" location="typescript/src/generated/services/everything.ts:162">
P2: These new Everything todo/card service methods are added in TypeScript, Ruby, and Python without corresponding service test coverage in this change. Adding happy-path and error-path tests for the new operations would reduce regression risk around path wiring, pagination behavior, and response decoding.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| return nil, err | ||
| } | ||
| defer done(&err) | ||
| r, err := s.client.parent.gen.GetEverythingOpenTodosWithResponse(ctx, s.client.accountID) |
There was a problem hiding this comment.
P2: Passing a positive page currently only disables Link-following but still fetches the first page, because the initial request never sends a page query parameter. This makes page behave differently from its doc comment and can return unexpected results for explicit-page callers.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At go/pkg/basecamp/everything.go, line 477:
<comment>Passing a positive `page` currently only disables Link-following but still fetches the first page, because the initial request never sends a `page` query parameter. This makes `page` behave differently from its doc comment and can return unexpected results for explicit-page callers.</comment>
<file context>
@@ -416,6 +416,240 @@ func (s *EverythingService) OverdueCards(ctx context.Context) (result []Card, er
+ return nil, err
+ }
+ defer done(&err)
+ r, err := s.client.parent.gen.GetEverythingOpenTodosWithResponse(ctx, s.client.accountID)
+ if err != nil {
+ return nil, err
</file context>
| @@ -26,6 +26,36 @@ export type Todo = components["schemas"]["Todo"]; | |||
| export interface EverythingBoostsEverythingOptions extends PaginationOptions { | |||
There was a problem hiding this comment.
P2: These new Everything todo/card service methods are added in TypeScript, Ruby, and Python without corresponding service test coverage in this change. Adding happy-path and error-path tests for the new operations would reduce regression risk around path wiring, pagination behavior, and response decoding.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At typescript/src/generated/services/everything.ts, line 162:
<comment>These new Everything todo/card service methods are added in TypeScript, Ruby, and Python without corresponding service test coverage in this change. Adding happy-path and error-path tests for the new operations would reduce regression risk around path wiring, pagination behavior, and response decoding.</comment>
<file context>
@@ -95,6 +149,106 @@ export class EverythingService extends BaseService {
+ * const result = await client.everything.everythingCompletedCards();
+ * ```
+ */
+ async everythingCompletedCards(options?: EverythingCompletedCardsEverythingOptions): Promise<components["schemas"]["GetEverythingCompletedCardsResponseContent"]> {
+ return this.requestPaginated(
+ {
</file context>
| return &BucketTodosGroupsPage{Groups: groups, Meta: ListMeta{TotalCount: totalCount, Truncated: truncated}}, nil | ||
| } | ||
|
|
||
| func (s *EverythingService) finishCardGroupsPage(ctx context.Context, httpResp *http.Response, body []byte, json200 *[]generated.BucketCardsGroup, page int32) (*BucketCardsGroupsPage, error) { |
There was a problem hiding this comment.
P3: Pagination behavior now has two near-identical implementations. Future fixes to Link handling, metadata, or decode errors can diverge; extract the shared page-finalization flow with typed conversion callbacks, leaving only todo/card conversion local.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At go/pkg/basecamp/everything.go, line 625:
<comment>Pagination behavior now has two near-identical implementations. Future fixes to Link handling, metadata, or decode errors can diverge; extract the shared page-finalization flow with typed conversion callbacks, leaving only todo/card conversion local.</comment>
<file context>
@@ -416,6 +416,240 @@ func (s *EverythingService) OverdueCards(ctx context.Context) (result []Card, er
+ return &BucketTodosGroupsPage{Groups: groups, Meta: ListMeta{TotalCount: totalCount, Truncated: truncated}}, nil
+}
+
+func (s *EverythingService) finishCardGroupsPage(ctx context.Context, httpResp *http.Response, body []byte, json200 *[]generated.BucketCardsGroup, page int32) (*BucketCardsGroupsPage, error) {
+ if err := checkResponse(httpResp, body); err != nil {
+ return nil, err
</file context>
Completes #434 (the everything-aggregates absorption). Part of the post-#401 BC3 follow-up program (PR-5b, the final unit).
Summary
The second everything-aggregates contract family: the 9 todo/card filter sub-routes returning a Link-paginated array of buckets, each grouping the matching recordings (with embedded steps) under their parent project.
EverythingService:GetEverythingOpen/Completed/Unassigned/NoDueDate TodosandOpen/Completed/Unassigned/NoDueDate/NotNow Cards— each Link-paginated, single-member output → bare array of groups (smithy-bare-arrays).BucketTodosGroup {bucket, todos}/BucketCardsGroup {bucket, cards}, reusing the fullTodo/Cardshapes (which already modelsteps/assignees/due_on). Kotlin needed both group types in the generatorTYPE_ALIASESto emit typed models.OpenTodos/… andOpenCards/…/NotNowCards) with multi-page Link-following; Go tests cover multi-page pagination and the{bucket, todos|cards}-with-steps grouping.Absorption complete
All 17 everything routes are now modeled, generated across the six SDKs, Go-wrapped, and decode-tested — so
everything-aggregates.mdflips toabsorbed-in-sdk. Conformancepaths.jsonpath-assertions + per-runner dispatch and per-group live-canary entries remain as supplementary verification infra (the live canary is dormant); the modeled surface itself is complete.Verification
make generate && make check— clean (all six SDK suites, conformance, wrapper/Kotlin drift at 223 operations, 24 api-gap entries).Summary by cubic
Adds bucket-grouped todo/card filters to
EverythingService, returning Link-paginated arrays of{bucket, todos|cards}groups. Completes the everything-aggregates absorption across all SDKs and flips the gap doc to absorbed-in-sdk.Open,Completed,Unassigned,NoDueDate) and Cards (Open,Completed,Unassigned,NoDueDate,NotNow), all Link-paginated with bare array outputs viasmithy-bare-arrays.BucketTodosGroupandBucketCardsGroupmodels reusingTodo/Card(with embedded steps); Kotlin generator addsTYPE_ALIASESfor both.Written for commit 04279fa. Summary will update on new commits.