Absorb everything-aggregates flat family (bc3 #11627, PR-5 of 2)#435
Absorb everything-aggregates flat family (bc3 #11627, PR-5 of 2)#435jeremy wants to merge 6 commits into
Conversation
…e api-gaps entries Advance the bc3 provenance pin from ca1d34bc to d7bc88da (bc3 master at 2026-07-24). The ca1d34bc..d7bc88da range is 30 commits, all reviewed no-ops for the SDK: 26 UI/CSS/JS/lexxy commits plus the duplicate-cookie migration auth commits (88cb86d2a/52f1e9974/7d86f1d06), which touch only the by_cookie session-cookie concern and its test — no route, controller, doc, or modeled API-contract change. Pin date is unchanged (2026-07-24), so no SDK version bump. Also correct two api-gaps entries whose upstream tails have since closed: - dock-tool-create-contract: bc3#12366 (8f938281) rewrote doc/api/sections/tools.md for the tool_type contract, closing the doc tail the entry still tracked as the open bc3#12364 note. Add top-level bc3_pr: 12366. - schedule-recurrence-writes: bc3#12362 (ec17b83c) merged and now rejects week_instance: 0 (and other uncomputable schedules) at create time, so the mandatory SDK-side guard is downgraded to optional hygiene.
The dock-tool create endpoint gained an optional top-level visible_to_clients boolean in bc3 #12386 (bee714c74). Only tool types that manage their own client visibility — Chat::Transcript and Kanban::Board, which otherwise start hidden — honor it; every other tool type ignores it and inherits the project default. Absorb it as a tri-state optional, mirroring the six content-create inputs from #401: - Smithy: add visible_to_clients: Boolean to CreateToolInput (plain Boolean → Go *bool), documenting the two-tool-type honoring rule on the member. - Go: CreateToolOptions.VisibleToClients *bool with a pass-through in ToolsService.Create; nil omits the field, explicit false reaches the wire. - Tests: Go tri-state transport test plus one body-encoding test in each of TS/Ruby/Python/Kotlin/Swift asserting explicit false is sent, not dropped. Flip dock-tool-visible-to-clients.md to absorbed-in-sdk with the smithy_ref and update the api-gaps README row.
The merged doc/api/sections/timeline.md and the bc3 timeline event view (api/timelines/events/_event.json.jbuilder) carry event fields the SDK did not yet type. No new operations — GetProgressReport, GetProjectTimeline, and GetPersonProgress already model the three routes. Extend TimelineEvent: - kind: kept an open, non-exhaustive String (documentation only, no closed enum) — BC3 adds new kinds over time; document common values including the live-only project_access_changed, dock_created, google_document_created. - data: new TimelineEventData sub-struct for schedule_entry_* events. Per the bc3 view (starts_at_date_or_time), starts_at/ends_at are date-or-timestamp (a bare date when all_day is true), so they are NOT plain timestamps: modeled as ISO8601Timestamp mirroring ScheduleEntry, with a Go enhancement pass mapping them to types.FlexibleTime; other SDKs type them as strings. - avatars_sample: StringList (chat-rollup participants). - attachments: heterogeneous per the bc3 view — an upload-kind recording contributes its full Upload shape, every other recording a rich-text attachment/blob partial. These variants share no required field set, so reusing an existing attachment shape is not possible. Modeled as an optional-field superset struct (TimelineAttachment) so one element type decodes either variant (the untagged-polymorphism default; no union needed). width/height get the nullable *types.FlexInt Go enhancement (float-spelled 1024.0, null for non-image blobs), matching RichTextAttachment. Runtime decode proof: every SDK (Go, TS, Ruby, Python, Kotlin, Swift) has a non-empty, per-variant test decoding BOTH attachment variants in one array, plus the all-day date-only data payload and a non-empty avatars_sample. The Go wrapper's TimelineAttachment routes decoding through the generated FlexInt type via a custom UnmarshalJSON (mirroring RichTextAttachment). Add a GetProgressReport entry to the live-my-surface canary (validates statically; live canary dormant) and flip activity-timeline.md to absorbed-in-sdk with smithy_refs.
doc/api/sections/my_notifications.md (codified by bc3 #11628) documents the BC5 bubble-up surface that memories-emptied-regression.md explicitly defers to a separate additive PR. Absorb it: - GetMyNotificationsOutput: add required bubble_ups_count and scheduled_bubble_ups_count (top-level UI counts, present independent of the limit_bubble_ups cap and even when the scheduled_bubble_ups array is omitted). - GetMyNotificationsInput: add optional limit_bubble_ups boolean @httpquery (true caps bubble_ups at 2 current items and omits scheduled_bubble_ups). - New GetBubbleUps operation (GET /my/readings/bubble_ups.json): a paginated bare array (50/page, Link-header pagination, page query param) of current bubble-ups first (most recently bubbled up) then scheduled bubble-ups (scheduled time). Same Notification item shape as GetMyNotifications. Added to the service operations list and tagged MyNotifications. Go wrapper: MyNotificationsService.BubbleUps follows the Link header across all pages by default; a positive page returns only that page. Get gained a non-breaking WithLimitBubbleUps() functional option. Tests: a multi-page Link-following pagination test (with X-Total-Count metadata and current-then-scheduled ordering), a single-page test, and a test proving limit_bubble_ups=true sends the param and decodes a response omitting scheduled_bubble_ups while keeping the counts. The grouped bubble_ups/scheduled_bubble_ups arrays and their item fields were already modeled and are not re-added. memories-emptied-regression.md is left intact; a new bubble-ups-surface.md entry records this absorption. Updated the GetMyNotifications conformance validator fixtures for the now-required counts and added a GetBubbleUps canary entry (validates statically; live dormant).
…mposite (bc3 #12375) bc3 #12375 documents the external-link (historically "door") resource. A pre-implementation spike scoped this to the cleanly-absorbable surface: Absorbed: - Make Door reachable through the EXISTING polymorphic ListRecordings query (GET /projects/recordings.json?type=Door) rather than a new operation: ListRecordings already carries a type query and Recording.url. Add Door to the RecordingType documented enum and optional position/description/service (DoorService struct) to the shared Recording projection. - Go wrapper: RecordingTypeDoor constant, clean DoorService type, door fields on Recording, mapper wiring. Runtime decode tests prove the full door shape (external url + service struct + description + position) decodes through the projection, and that a non-door recording leaves the door fields empty. - Get/rename/trash already reuse GetTool/UpdateTool/DeleteTool (no work). - type=Door ListRecordings canary entry (validates statically; live dormant). Deferred as residual gaps (entry is partial-coverage, not absorbed-in-sdk): - Create (POST .../dock/doors.json) returns 302 + empty body redirecting cross-origin. The spike found the six SDK transports handle this inconsistently — Go/TS/Kotlin/Swift follow the redirect; Python/Ruby do not but face empty-body decode — so modeling "return only the 302/empty" response needs a cross-cutting per-operation transport change, out of scope for an additive absorption. - image thumbnail is multipart-only; unmodeled. - The SPEC §18 create-and-discover composite depends on a shippable create. Additive only (Door enum + optional Recording fields); no operation change.
BC5's account-wide recording listings (everything/*_controller.rb, documented by bc3 #11627 in doc/api/sections/everything.md) had no SDK surface. Add a new EverythingService with the 8 flat-family operations, mirroring the flat aggregate pattern of GetMyAssignments: - Six recency-ordered, Link-paginated roots: GetEverythingMessages/Comments/ Checkins/Forwards (element = the generic Recording projection the wire actually returns, embedding bucket), GetEverythingBoosts (element = Boost, with its booster + nested recording), and GetEverythingFiles. - Two unpaginated, oldest-due-date-first arrays: GetEverythingOverdueTodos (Todo) and GetEverythingOverdueCards (Card), modeled as plain full arrays (single-member output, no pagination → bare array via smithy-bare-arrays) and tested with no Link-following. - /files.json is heterogeneous (Upload + Document + attachment-envelope): modeled as the optional-field superset EverythingFile with the kind and repeatable people_ids[] filters. Width/height get the nullable *FlexInt Go enhancement (and Kotlin needed EverythingFile added to the generator TYPE_ALIASES so it emits a typed model instead of JsonElement). Runtime decode proof for the heterogeneous feed in every SDK (Go, TS, Ruby, Python, Kotlin, Swift): a non-empty test decoding all three file variants in one array. Go wrappers add multi-page Link-following (paginated roots) and plain full-array decode (overdue); Go tests cover multi-page pagination, unpaginated-with-Link-header-ignored, per-variant files decode, and the kind/people_ids[] filters. Service auto-derives from the Everything tag; client wiring added where hand-written (Go accessor, TS defineService, Ruby method, Python sync+async properties; Kotlin/Swift auto-wired). everything-aggregates.md moves to partial-coverage with a two-phase absorption note; it flips to absorbed-in-sdk only after PR-5b models the bucket-grouped family. Conformance paths.json + per-runner dispatch and per-group canary entries are tracked as follow-ups landing with PR-5b.
Spec Change Impact
Checklist of SDKs Needing Updates:
|
There was a problem hiding this comment.
⚠️ Not ready to approve
The Go wrapper’s page parameter is currently not applied to requests (so page>1 can’t work as documented), and the TS/Python client typings have a few inconsistencies that should be corrected before merging.
Pull request overview
Adds first-phase SDK surface for BC5 “everything” account-wide aggregates (flat family, 8 ops) by introducing a new EverythingService across all six SDKs, backed by Smithy/OpenAPI updates, runtime decode fixtures for the heterogeneous /files.json feed, and updated api-gaps registry status.
[!TIP]
If you aren't ready for review, convert to a draft PR.
Click "Convert to draft" or rungh pr ready --undo.
Click "Ready for review" or rungh pr readyto reengage.
Changes:
- Model and generate the flat “everything” aggregate routes (messages/comments/checkins/forwards/boosts/files + overdue todos/cards) and tag them into a new
Everythingservice group. - Add per-SDK wiring so
client.everything/account.everythingis available, plus metadata/path mapping updates. - Add runtime decode tests proving
/files.jsonheterogeneous variants (Upload/Document/Attachment) decode correctly across SDKs.
File summaries
| File | Description |
|---|---|
| typescript/tests/services/everything.test.ts | Adds TS decode test for heterogeneous /files.json results. |
| typescript/src/generated/services/index.ts | Exports generated EverythingService. |
| typescript/src/generated/services/everything.ts | Implements generated TS EverythingService methods for the flat family. |
| typescript/src/generated/schema.d.ts | Adds new operations/paths and EverythingFile schema typing. |
| typescript/src/generated/path-mapping.ts | Maps Everything endpoints to operation IDs for routing/metadata. |
| typescript/src/generated/openapi-stripped.json | Updates stripped OpenAPI with Everything routes/schemas used by TS generator. |
| typescript/src/generated/metadata.ts | Adds retry/pagination metadata entries for Everything operations. |
| typescript/src/client.ts | Wires client.everything service accessor. |
| swift/Tests/BasecampTests/GeneratedServiceTests.swift | Adds Swift runtime decode test for heterogeneous /files.json. |
| swift/Sources/Basecamp/Generated/Services/EverythingService.swift | Adds generated Swift EverythingService. |
| swift/Sources/Basecamp/Generated/Models/EverythingFile.swift | Adds generated Swift EverythingFile model. |
| swift/Sources/Basecamp/Generated/Metadata.swift | Registers retry metadata for Everything operations. |
| swift/Sources/Basecamp/Generated/AccountClient+Services.swift | Wires Swift account.everything accessor. |
| spec/overlays/tags.smithy | Tags the 8 flat-family operations into the Everything service group. |
| spec/basecamp.smithy | Adds Smithy operations + EverythingFile superset shape. |
| spec/api-gaps/README.md | Marks everything-aggregates as partial-coverage pending PR-5b. |
| spec/api-gaps/everything-aggregates.md | Updates registry entry with phased plan/status + smithy refs. |
| scripts/enhance-openapi-go-types.sh | Enhances EverythingFile width/height to nullable FlexInt in Go OpenAPI post-pass. |
| ruby/test/basecamp/services/everything_service_test.rb | Adds Ruby decode test for heterogeneous /files.json. |
| ruby/lib/basecamp/generated/types.rb | Adds generated Ruby EverythingFile type class. |
| ruby/lib/basecamp/generated/services/everything_service.rb | Adds generated Ruby EverythingService. |
| ruby/lib/basecamp/generated/metadata.json | Registers Ruby operation metadata for Everything operations. |
| ruby/lib/basecamp/client.rb | Wires Ruby client.everything accessor. |
| python/tests/services/test_everything.py | Adds Python decode test for heterogeneous /files.json. |
| python/src/basecamp/generated/types.py | Adds EverythingFile TypedDict. |
| python/src/basecamp/generated/services/everything.py | Adds generated Python sync/async EverythingService. |
| python/src/basecamp/generated/services/init.py | Exposes Everything services via package exports. |
| python/src/basecamp/generated/metadata.json | Registers retry metadata for Everything operations. |
| python/src/basecamp/client.py | Wires Python sync client.everything property. |
| python/src/basecamp/async_client.py | Wires Python async client.everything property. |
| openapi.json | Adds Everything paths/operations/schemas to the canonical OpenAPI output. |
| kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/EverythingFilesDecodeTest.kt | Adds Kotlin decode test for heterogeneous /files.json. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/services/Types.kt | Adds options type for Everything files filters/pagination. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/services/everything.kt | Adds generated Kotlin EverythingService. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/ServiceAccessors.kt | Wires Kotlin accountClient.everything accessor. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/models/EverythingFile.kt | Adds generated Kotlin EverythingFile model. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/Metadata.kt | Registers retry config entries for Everything operations. |
| kotlin/generator/src/main/kotlin/com/basecamp/sdk/generator/Config.kt | Adds EverythingFile to Kotlin generator TYPE_ALIASES. |
| go/pkg/basecamp/url-routes.json | Registers Everything routes in Go URL routing table. |
| go/pkg/basecamp/everything.go | Adds Go EverythingService wrapper + EverythingFile public model conversion. |
| go/pkg/basecamp/everything_test.go | Adds Go tests for Link-following, filters, and heterogeneous decode. |
| go/pkg/basecamp/client.go | Wires Go AccountClient.Everything() accessor. |
| behavior-model.json | Adds behavior-model entries for Everything operations (retry/pagination/readonly). |
Review details
- Files reviewed: 21/44 changed files
- Comments generated: 1
- Review effort level: Low
Note
Your feedback helps us improve the quality of this feature.
Please use 👍 or 👎 to tell us whether this assessment is correct.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| resp, err := s.client.parent.gen.GetEverythingMessagesWithResponse(ctx, s.client.accountID) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| return s.finishRecordingsPage(ctx, resp.HTTPResponse, resp.Body, resp.JSON200, page) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 62dad6fa41
ℹ️ 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".
| describe("everythingFiles", () => { | ||
| it("should decode the heterogeneous /files.json feed: Upload, Document, and Attachment variants in one array", async () => { |
There was a problem hiding this comment.
Add contract tests for all eight operations
The new TypeScript suite exercises only the happy path for everythingFiles, and the Ruby and Python suites have the same limitation; the other seven operations have neither happy-path nor error tests, while everythingFiles has no error test. Consequently, incorrect routes, response shapes, and error propagation for most of this service can ship undetected. The repository's completeness bar explicitly requires happy-path and error coverage in all three SDKs for every new operation.
AGENTS.md reference: AGENTS.md:L305-L307
Useful? React with 👍 / 👎.
| @@ -1,5 +1,6 @@ | |||
| export { AccountService } from "./account.js"; | |||
| export { AttachmentsService } from "./attachments.js"; | |||
| export { EverythingService } from "./everything.js"; | |||
There was a problem hiding this comment.
Export EverythingService from the package root
Although this adds EverythingService to the generated services barrel, the package entry point typescript/src/index.ts explicitly enumerates public service exports and is not updated here. Consumers therefore cannot import EverythingService or its option types from @37signals/basecamp, unlike the other public services; add the corresponding root export.
AGENTS.md reference: AGENTS.md:L304-L304
Useful? React with 👍 / 👎.
| // Rails controller namespace, not part of the URL). Documented by BC3 #11627 in | ||
| // doc/api/sections/everything.md. This is the flat family: six recency-ordered, |
There was a problem hiding this comment.
Refresh provenance for this upstream absorption
This Smithy addition explicitly absorbs the BC3 #11627 contract, but the commit does not update spec/api-provenance.json. That leaves no recorded upstream HEAD/date for the sync and prevents the provenance pin from demonstrating which BC3 state was verified; refresh the pin and run make provenance-sync.
AGENTS.md reference: AGENTS.md:L265-L270
Useful? React with 👍 / 👎.
| return nil, err | ||
| } | ||
| defer done(&err) | ||
| resp, err := s.client.parent.gen.GetEverythingMessagesWithResponse(ctx, s.client.accountID) |
There was a problem hiding this comment.
Forward the requested page in Go
When a caller passes page > 1, this request still invokes the generated operation without a page parameter, so it always fetches the API's default first page and merely disables Link following afterward. The same omission affects Comments, Checkins, Forwards, Boosts, and Files. Add the page query parameter to the six Smithy inputs, regenerate, and pass it through so requesting page 2 does not silently return page 1.
AGENTS.md reference: AGENTS.md:L76-L76
Useful? React with 👍 / 👎.
| * const result = await client.everything.everythingBoosts(); | ||
| * ``` | ||
| */ | ||
| async everythingBoosts(options?: EverythingBoostsEverythingOptions): Promise<components["schemas"]["GetEverythingBoostsResponseContent"]> { |
There was a problem hiding this comment.
Preserve ListResult in the TypeScript return types
For everythingBoosts, the declared response alias resolves to Boost[], even though requestPaginated returns ListResult<Boost> and the method documentation promises .meta.totalCount. TypeScript consumers therefore get a compile-time error when accessing the advertised metadata; everythingFiles has the same issue. Update the generator's entity mapping so these signatures are ListResult<Boost> and ListResult<EverythingFile>.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
6 issues found across 44 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:62">
P3: False API values are lost when callers marshal `EverythingFile`. Keep JSON tags on these response booleans without `omitempty` so `false` is represented.</violation>
<violation number="2" location="go/pkg/basecamp/everything.go:63">
P3: Attachment variants with no timestamps serialize zero-time sentinels instead of preserving field absence. Use `*time.Time` for optional timestamps and populate them only when the generated value is present/non-zero.</violation>
<violation number="3" location="go/pkg/basecamp/everything.go:169">
P2: Passing a positive page returns the server's first page, not the requested page, across every paginated Everything method. Add `page` to the initial request query (for example via a request editor) or document/remove this parameter rather than promising a page-specific result.</violation>
</file>
<file name="typescript/src/client.ts">
<violation number="1" location="typescript/src/client.ts:411">
P2: EverythingService is wired into the client (import, type declaration, `defineService`) but not re-exported from `index.ts`, so it is missing from the package's public API surface. All other services in the codebase are re-exported — please add a re-export block for `EverythingService` (and any newly exported types like `EverythingFile`) to `index.ts` following the same pattern.</violation>
</file>
<file name="python/src/basecamp/client.py">
<violation number="1" location="python/src/basecamp/client.py:351">
P1: The new `account.everything` accessor exposes overdue methods with the wrong response contract: `get_everything_overdue_cards` and `get_everything_overdue_todos` call `_request` and are typed as `dict[str, Any]`, but these routes return bare arrays. A valid overdue response therefore violates the SDK method contract and can break callers expecting the documented list result; the generated service should use the bare-array response handling and list return type for both sync and async methods.</violation>
</file>
<file name="typescript/src/generated/services/everything.ts">
<violation number="1" location="typescript/src/generated/services/everything.ts:182">
P2: `everythingFiles` is paginated at runtime, but the declared return type is a plain array response alias. Using `ListResult<...>` in the signature preserves typed access to pagination metadata and matches the method’s actual return contract.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| def everything(self): | ||
| from basecamp.generated.services.everything import EverythingService | ||
|
|
||
| return self._service("everything", lambda: EverythingService(self)) |
There was a problem hiding this comment.
P1: The new account.everything accessor exposes overdue methods with the wrong response contract: get_everything_overdue_cards and get_everything_overdue_todos call _request and are typed as dict[str, Any], but these routes return bare arrays. A valid overdue response therefore violates the SDK method contract and can break callers expecting the documented list result; the generated service should use the bare-array response handling and list return type for both sync and async methods.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At python/src/basecamp/client.py, line 351:
<comment>The new `account.everything` accessor exposes overdue methods with the wrong response contract: `get_everything_overdue_cards` and `get_everything_overdue_todos` call `_request` and are typed as `dict[str, Any]`, but these routes return bare arrays. A valid overdue response therefore violates the SDK method contract and can break callers expecting the documented list result; the generated service should use the bare-array response handling and list return type for both sync and async methods.</comment>
<file context>
@@ -344,6 +344,12 @@ def timeline(self):
+ def everything(self):
+ from basecamp.generated.services.everything import EverythingService
+
+ return self._service("everything", lambda: EverythingService(self))
+
@property
</file context>
| // Messages returns every message across all accessible projects, newest-first. | ||
| // Pass a positive page to return only that page; page 0 follows the Link header | ||
| // across all pages. | ||
| func (s *EverythingService) Messages(ctx context.Context, page int32) (result *RecordingsPage, err error) { |
There was a problem hiding this comment.
P2: Passing a positive page returns the server's first page, not the requested page, across every paginated Everything method. Add page to the initial request query (for example via a request editor) or document/remove this parameter rather than promising a page-specific result.
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 169:
<comment>Passing a positive page returns the server's first page, not the requested page, across every paginated Everything method. Add `page` to the initial request query (for example via a request editor) or document/remove this parameter rather than promising a page-specific result.</comment>
<file context>
@@ -0,0 +1,437 @@
+// Messages returns every message across all accessible projects, newest-first.
+// Pass a positive page to return only that page; page 0 follows the Link header
+// across all pages.
+func (s *EverythingService) Messages(ctx context.Context, page int32) (result *RecordingsPage, err error) {
+ op := OperationInfo{Service: "Everything", Operation: "Messages", ResourceType: "recording", IsMutation: false}
+ ctx, done, err := s.begin(ctx, op)
</file context>
| defineService("tools", () => new ToolsService(client, hooks, fetchPage, maxPages)); | ||
| defineService("timesheets", () => new TimesheetsService(client, hooks, fetchPage, maxPages)); | ||
| defineService("timeline", () => new TimelineService(client, hooks, fetchPage, maxPages)); | ||
| defineService("everything", () => new EverythingService(client, hooks, fetchPage, maxPages)); |
There was a problem hiding this comment.
P2: EverythingService is wired into the client (import, type declaration, defineService) but not re-exported from index.ts, so it is missing from the package's public API surface. All other services in the codebase are re-exported — please add a re-export block for EverythingService (and any newly exported types like EverythingFile) to index.ts following the same pattern.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At typescript/src/client.ts, line 411:
<comment>EverythingService is wired into the client (import, type declaration, `defineService`) but not re-exported from `index.ts`, so it is missing from the package's public API surface. All other services in the codebase are re-exported — please add a re-export block for `EverythingService` (and any newly exported types like `EverythingFile`) to `index.ts` following the same pattern.</comment>
<file context>
@@ -405,6 +408,7 @@ export function createBasecampClient(options: BasecampClientOptions): BasecampCl
defineService("tools", () => new ToolsService(client, hooks, fetchPage, maxPages));
defineService("timesheets", () => new TimesheetsService(client, hooks, fetchPage, maxPages));
defineService("timeline", () => new TimelineService(client, hooks, fetchPage, maxPages));
+ defineService("everything", () => new EverythingService(client, hooks, fetchPage, maxPages));
defineService("clientVisibility", () => new ClientVisibilityService(client, hooks, fetchPage, maxPages));
defineService("boosts", () => new BoostsService(client, hooks, fetchPage, maxPages));
</file context>
| * const result = await client.everything.everythingFiles(); | ||
| * ``` | ||
| */ | ||
| async everythingFiles(options?: EverythingFilesEverythingOptions): Promise<components["schemas"]["GetEverythingFilesResponseContent"]> { |
There was a problem hiding this comment.
P2: everythingFiles is paginated at runtime, but the declared return type is a plain array response alias. Using ListResult<...> in the signature preserves typed access to pagination metadata and matches the method’s actual return contract.
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 182:
<comment>`everythingFiles` is paginated at runtime, but the declared return type is a plain array response alias. Using `ListResult<...>` in the signature preserves typed access to pagination metadata and matches the method’s actual return contract.</comment>
<file context>
@@ -0,0 +1,273 @@
+ * const result = await client.everything.everythingFiles();
+ * ```
+ */
+ async everythingFiles(options?: EverythingFilesEverythingOptions): Promise<components["schemas"]["GetEverythingFilesResponseContent"]> {
+ return this.requestPaginated(
+ {
</file context>
| type EverythingFile struct { | ||
| ID int64 `json:"id,omitempty"` | ||
| Status string `json:"status,omitempty"` | ||
| VisibleToClients bool `json:"visible_to_clients,omitempty"` |
There was a problem hiding this comment.
P3: False API values are lost when callers marshal EverythingFile. Keep JSON tags on these response booleans without omitempty so false is represented.
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 62:
<comment>False API values are lost when callers marshal `EverythingFile`. Keep JSON tags on these response booleans without `omitempty` so `false` is represented.</comment>
<file context>
@@ -0,0 +1,437 @@
+type EverythingFile struct {
+ ID int64 `json:"id,omitempty"`
+ Status string `json:"status,omitempty"`
+ VisibleToClients bool `json:"visible_to_clients,omitempty"`
+ CreatedAt time.Time `json:"created_at,omitempty"`
+ UpdatedAt time.Time `json:"updated_at,omitempty"`
</file context>
| ID int64 `json:"id,omitempty"` | ||
| Status string `json:"status,omitempty"` | ||
| VisibleToClients bool `json:"visible_to_clients,omitempty"` | ||
| CreatedAt time.Time `json:"created_at,omitempty"` |
There was a problem hiding this comment.
P3: Attachment variants with no timestamps serialize zero-time sentinels instead of preserving field absence. Use *time.Time for optional timestamps and populate them only when the generated value is present/non-zero.
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 63:
<comment>Attachment variants with no timestamps serialize zero-time sentinels instead of preserving field absence. Use `*time.Time` for optional timestamps and populate them only when the generated value is present/non-zero.</comment>
<file context>
@@ -0,0 +1,437 @@
+ ID int64 `json:"id,omitempty"`
+ Status string `json:"status,omitempty"`
+ VisibleToClients bool `json:"visible_to_clients,omitempty"`
+ CreatedAt time.Time `json:"created_at,omitempty"`
+ UpdatedAt time.Time `json:"updated_at,omitempty"`
+ Title string `json:"title,omitempty"`
</file context>
38e8903 to
6947813
Compare
Closes #434 (partially — flat family only). Part of the post-#401 BC3 follow-up absorption program (PR-5, the LARGE one, two-phase).
Summary
BC5's account-wide recording listings (documented by bc3 #11627) had no SDK surface. This adds a new
EverythingServicewith the flat family (8 ops), mirroring the flat-aggregate pattern ofGetMyAssignments. The bucket-grouped family (9 sub-routes) lands in PR-5b; the registry entry stayspartial-coverageuntil then.Absorbed
GetEverythingMessages/Comments/Checkins/Forwards(element = the genericRecordingprojection the wire returns, embeddingbucket),GetEverythingBoosts(Boost),GetEverythingFiles.GetEverythingOverdueTodos(Todo),GetEverythingOverdueCards(Card) — bare arrays viasmithy-bare-arrays, tested with no Link-following./files.jsonheterogeneous (Upload + Document + attachment-envelope) → optional-field supersetEverythingFilewithkind+ repeatablepeople_ids[]filters.Runtime decode proof (all six SDKs)
A non-empty test decoding all three file variants in one array — Go, TS, Ruby, Python, Kotlin, Swift. Kotlin needed
EverythingFileadded to the generatorTYPE_ALIASES(else it fell back toListResult<JsonElement>); it now returnsListResult<EverythingFile>. Go tests also cover multi-page Link-following, unpaginated-with-Link-header-ignored, and thekind/people_ids[]filters.Wiring
Service auto-derives from the
Everythingtag; client wiring added where hand-written (Go accessor, TSdefineService, Ruby method, Python sync+async properties; Kotlin/Swift auto-wired).Verification
make generate && make check— clean (all six SDK suites, conformance, wrapper/Kotlin drift, 24 api-gap entries).everything-aggregates.md→partial-coverage. Conformancepaths.json/dispatch + per-group canary entries tracked as follow-ups landing with PR-5b.Summary by cubic
Adds a new
EverythingServicethat exposes account‑wide “everything” listings (flat family, 8 ops) across all SDKs. Partially addresses #434 and aligns with bc3 #11627; bucket‑grouped routes will ship in PR‑5b.New Features
EverythingServicewith 8 ops:GetEverythingMessages,GetEverythingComments,GetEverythingCheckins,GetEverythingForwards,GetEverythingBoosts,GetEverythingFiles,GetEverythingOverdueTodos,GetEverythingOverdueCards./files.jsonheterogeneous feed modeled asEverythingFilewithkindand repeatablepeople_ids[]filters; Go uses nullableFlexIntfor width/height.Migration
accountClient.Everything(), TypeScriptclient.everything, Pythonclient.everything, Rubyclient.everything, KotlinaccountClient.everything, SwiftaccountClient.everything.Written for commit 62dad6f. Summary will update on new commits.