Skip to content

Add UpdateBoost - #1016

Merged
robzolkos merged 3 commits into
mainfrom
boost-update
Oct 19, 2026
Merged

robzolkos merged 3 commits into
mainfrom
boost-update

Conversation

@robzolkos

@robzolkos robzolkos commented Oct 19, 2026 •

Copy link
Copy Markdown
Collaborator

Stacked on #1015 (base is circles-service, rebased onto its head 124fe18f); retarget to main once it merges.

The operation

UpdateBoost models PUT /boosts/{boostId} (bc3 #13945), which replaces a boost's content and answers 200 with the boost (same shape as Get a boost).

  • Only the boost's creator may update it. Anyone else, admins included, gets 403, as does any caller when comments are closed on the boosted recording.
  • 404 for a boost on a deleted recording or in another account.
  • 422, bodiless, for missing, blank or invalid content. It is modeled as BareValidationError, the way CreatePing's is.
  • Flat route only. The legacy bucket-scoped boost routes get no update.
  • A naturally idempotent PUT: it retries on 429 and 503 and is flagged @basecampIdempotent(natural: true).
  • content is capped at 16 in the spec (@length(max: 16), maxLength: 16 in openapi.json), matching CreateRecordingBoostInput and CreateEventBoostInput and the web's limit. It is a separate commit. No SDK enforces maxLength on a request client side, create included, so no runtime behavior changes; the server owns the rule and answers a bodiless 422.

It sits on the existing Boosts service in all seven SDKs. Go: func (s *BoostsService) Update(ctx context.Context, boostID int64, content string) (*Boost, error). Go rejects empty content with a usage error before the request, as CreateRecording does.

The repin

spec/api-provenance.json moves from b1f18fd182 to 4958288166 (bc3 master after #13945, same day, so the API version is unchanged). make bc3-routes regenerates spec/bc3-routes.json, 416 to 417 routes. The only new route is PUT /boosts/:id, which this PR models, so no api-gap is registered and the allowlist needs no change. The range triage is in spec/api-gaps/README.md, including that the same docs reword CreateBoost (the 191-character limit and "too long" 422 are gone from the text).

Tests

  • Unit tests in every SDK for success (path, method, content-only body), 403, 404 and 422: Go, TypeScript, Ruby, Python, Rust (tests/boosts.rs), Kotlin (BoostsServiceTest), Swift (BoostsServiceTests).
  • A conformance/tests/boosts_write.json fixture (flat path, wire body, 403, 404, bodiless 422) with an UpdateBoost dispatch case in all seven runners.
  • Gates: operation counts (283), the idempotency parity script (98/234), Rust route-table counts, Go grouped-client inventory, and the SPEC fixture-category rows.

make check ends "All checks passed" locally on Linux. Swift's own build and the Swift conformance runner are macOS-only here and skipped, so the Swift test and runner dispatch rest on CI.


Summary by cubic

Adds UpdateBoost to all seven SDKs, modeling PUT /boosts/{boostId}, which replaces a boost's content and answers 200 with the updated boost.

Behavior

  • Only the boost's creator may update; others get 403 and a bodiless 422 covers missing, blank, or invalid content.
  • A naturally idempotent PUT retries on 429 and 503; Go rejects empty content before sending the request.
  • Flat route only; bucket-scoped boost routes get no update.

Spec and tests

  • Caps content at 16 characters in the spec (@length(max: 16), maxLength: 16 in openapi.json), matching CreateRecordingBoostInput, CreateEventBoostInput, and the web limit. No SDK enforces maxLength client side; the server owns the rule and answers a bodiless 422.
  • Repins the bc3 provenance to 4958288166 with no API version change; the only new route is PUT /boosts/:id.
  • Adds a boosts_write.json conformance fixture with dispatch cases in all seven runners, plus per-SDK unit tests and updated operation-count, idempotency-parity, and route-table gates.
  • TypeScript exports UpdateBoostRequest; the api-gaps note now names the same 16-character cap.

Written for commit 80875fb. Summary will update on new commits.

View guided diff Turn on auto-fix

@github-actions github-actions Bot added typescript Pull requests that update TypeScript code ruby Pull requests that update the Ruby SDK go kotlin swift spec Changes to the Smithy spec or OpenAPI conformance Conformance test suite python Pull requests that update the Python SDK rust Rust SDK labels Oct 19, 2026
@robzolkos robzolkos added the breaking Breaking change to public API label Oct 19, 2026
@robzolkos
robzolkos requested a balanced review from Copilot October 19, 2026 22:22
@robzolkos
robzolkos marked this pull request as ready for review October 19, 2026 22:23

Copilot AI 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.

🔵 Needs a closer look

The new TypeScript request type is missing from the package’s public exports.

No open issues 🎉

What changed in this PR

Adds UpdateBoost to the existing Boosts service across all seven SDKs through the Smithy-to-generated-client pipeline.

Changes:

  • Models the flat PUT endpoint, request constraint, response, and retry behavior.
  • Adds SDK tests and shared conformance coverage.
  • Advances upstream provenance and updates operation inventories.

[!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
typescript/​tests/​services/​boosts.test.ts Tests update requests and errors.
typescript/​src/​generated/​services/​boosts.ts Adds update method and request type.
typescript/​src/​generated/​schema.d.ts Adds operation types.
typescript/​src/​generated/​person-id-sites.ts Registers booster normalization.
typescript/​src/​generated/​path-mapping.ts Maps the update route.
typescript/​src/​generated/​openapi-stripped.json Adds account-relative operation schema.
typescript/​src/​generated/​metadata.ts Adds retry metadata.
swift/​Tests/​BasecampTests/​BoostsServiceTests.swift Tests requests and mapped errors.
swift/​Sources/​Basecamp/​Generated/​Services/​BoostsService.swift Adds update method.
swift/​Sources/​Basecamp/​Generated/​Models/​UpdateBoostRequest.swift Adds request model.
swift/​Sources/​Basecamp/​Generated/​Metadata.swift Adds retry and idempotency metadata.
spec/​overlays/​tags.smithy Assigns operation to Boosts.
spec/​doc-constants.json Updates provenance citation rationale.
spec/​bc3-routes.json Records upstream update route.
spec/​basecamp.smithy Defines operation and input constraint.
spec/​api-provenance.json Advances upstream baseline.
spec/​api-gaps/​README.md Records upstream range triage.
SPEC.md Updates counts and fixture documentation.
SECURITY.md Updates retry operation counts.
scripts/​check-idempotency-parity Updates expected counts.
rust/​basecamp-sdk/​tests/​guarantees.rs Updates inventory assertions.
rust/​basecamp-sdk/​tests/​boosts.rs Tests update requests and errors.
rust/​basecamp-sdk/​src/​generated/​types.rs Adds request and response types.
rust/​basecamp-sdk/​src/​generated/​services/​boosts.rs Adds update method.
rust/​basecamp-sdk/​src/​generated/​routes.rs Adds update route.
rust/​basecamp-sdk/​src/​generated/​mod.rs Updates operation count.
rust/​basecamp-sdk/​src/​generated/​metadata.rs Adds operation metadata.
ruby/​test/​basecamp/​services/​boosts_service_test.rb Tests update requests and errors.
ruby/​lib/​basecamp/​generated/​types.rb Refreshes generation timestamp only.
ruby/​lib/​basecamp/​generated/​services/​boosts_service.rb Adds update method.
ruby/​lib/​basecamp/​generated/​metadata.json Adds retries and booster normalization.
python/​tests/​services/​test_boosts_service.py Tests synchronous and asynchronous updates.
python/​src/​basecamp/​generated/​types.py Adds request type.
python/​src/​basecamp/​generated/​services/​boosts.py Adds synchronous and asynchronous methods.
python/​src/​basecamp/​generated/​services/​_person_id_sites.py Registers booster normalization.
python/​src/​basecamp/​generated/​metadata.json Adds operation metadata.
openapi.json Adds endpoint and schemas.
kotlin/​sdk/​src/​commonTest/​kotlin/​com/​basecamp/​sdk/​BoostsServiceTest.kt Tests requests and mapped errors.
kotlin/​sdk/​src/​commonMain/​kotlin/​com/​basecamp/​sdk/​generated/​services/​Types.kt Adds request body type.
kotlin/​sdk/​src/​commonMain/​kotlin/​com/​basecamp/​sdk/​generated/​services/​boosts.kt Adds update method.
kotlin/​sdk/​src/​commonMain/​kotlin/​com/​basecamp/​sdk/​generated/​Metadata.kt Adds operation metadata.
kotlin/​conformance/​src/​main/​kotlin/​com/​basecamp/​sdk/​conformance/​Main.kt Dispatches update conformance cases.
go/​pkg/​generated/​client.gen.go Adds generated request and response handling.
go/​pkg/​basecamp/​url-routes.json Maps update operation.
go/​pkg/​basecamp/​catalog/​catalog.json Adds operation catalog entry.
go/​pkg/​basecamp/​boosts.go Adds public update wrapper.
go/​pkg/​basecamp/​boosts_test.go Tests validation, requests, and errors.
go/​pkg/​basecamp/​api-provenance.json Synchronizes upstream baseline.
go/​grouped-client-inventory.yml Registers operation inventory entry.
COORDINATION.md Updates documented provenance pin.
conformance/​tests/​boosts_write.json Adds four shared update cases.
conformance/​runner/​typescript/​runner.test.ts Dispatches update cases.
conformance/​runner/​swift/​Sources/​ConformanceRunner/​Dispatch.swift Dispatches update cases.
conformance/​runner/​rust/​src/​operations.rs Dispatches update cases.
conformance/​runner/​ruby/​runner.rb Dispatches update cases.
conformance/​runner/​python/​runner.py Dispatches update cases.
conformance/​runner/​go/​main.go Dispatches update cases.
behavior-model.json Declares update retry behavior.
AGENTS.md Updates documented operation counts.

Review effort: Balanced

@robzolkos
robzolkos requested a balanced review from Copilot October 19, 2026 22:53
Base automatically changed from circles-service to main October 19, 2026 22:54
BC3 #13945 (4958288166) adds PUT /boosts/:id.json, replacing a boost's
content. Only the boost's creator may update it: anyone else, admins
included, gets 403, as does any caller when comments are closed on the
boosted recording. A deleted recording or another account answers 404,
and missing, blank or invalid content answers a bodiless 422. The flat
route is the only one; the legacy bucket-scoped boost routes get no
update.

This models UpdateBoost on the Boosts service in all seven SDKs (Go:
BoostsService.Update(ctx, boostID, content)). It is a naturally
idempotent PUT, so it retries on 429 and 503. Its 422 is a
BareValidationError, the way CreatePing's is. No SDK enforces a length client side; the 16 character cap the web
uses is declared in the spec by the next commit.

Repin the provenance from b1f18fd182 to 4958288166 (same day, so the API
version does not move) and regenerate spec/bc3-routes.json, 416 -> 417
routes. The range adds that one route and nothing else, so no api-gap is
registered; spec/api-gaps/README.md records the triage, including the
CreateBoost wording change in the same docs.

Tests: per-SDK unit tests for success, 403, 404 and 422, a boosts_write
conformance fixture (path, wire body, 403, 404, 422) with a dispatch case
in every runner, and the idempotency, route-count and operation-count
gates.
CreateRecordingBoostInput and CreateEventBoostInput declare
@Length(max: 16) on content, and the web composer holds boosts to the
same 16. UpdateBoostInput left it open, so the spec described an update
that accepts what a create refuses.

The limit lands in openapi.json as maxLength 16 and in the Go catalog.
No SDK enforces maxLength on a request client side, create included, so
no runtime, test or fixture changes; the server owns the rule and
answers a bodiless 422.
TypeScript callers could reach client.boosts.update but not import its
request type, which index.ts exports for both create inputs. The api-gaps
note still said UpdateBoost has no length limit after the spec gave it the
same @Length(max: 16) as create.

Copilot AI 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.

🔵 Needs a closer look

The seven-SDK integration needs final human review with confirmed macOS Swift build and conformance results.

No open issues 🎉

Review effort: Balanced

@robzolkos

Copy link
Copy Markdown
Collaborator Author

Convergence note before merge.

@robzolkos
robzolkos merged commit cd34d82 into main Oct 19, 2026
56 checks passed
@robzolkos
robzolkos deleted the boost-update branch October 19, 2026 23:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking Breaking change to public API conformance Conformance test suite go kotlin python Pull requests that update the Python SDK ruby Pull requests that update the Ruby SDK rust Rust SDK spec Changes to the Smithy spec or OpenAPI swift typescript Pull requests that update TypeScript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants