Skip to content

fix(gauges): absorb five spec drifts from the contract bc3 serves - #853

Merged
jeremy merged 6 commits into
mainfrom
fix/gauges-spec-drift
Sep 11, 2026
Merged

jeremy merged 6 commits into
mainfrom
fix/gauges-spec-drift

Conversation

@jeremy

@jeremy jeremy commented Sep 9, 2026

Copy link
Copy Markdown
Member

Summary

Five drifts between the gauges spec and the contract bc3 serves at the pinned revision, all read off the jbuilder/controller source and doc/api/sections/gauges.md, fixed in the spec (and the one Go hand-written wrapper) and regenerated into all six SDKs:

  1. GaugeNeedle.comment_count_needle.json.jbuilder emits the singular key unconditionally, next to the envelope's plural comments_count. Modeled @required, with the same doc note SearchResult.comment_count carries. Go GaugeNeedle.CommentCount, Swift commentCount; the dict-shaped SDKs already passed it through. spec/fixtures/gauges/needle_get.json now carries it and the manifest's KNOWN INCOMPLETE note is gone.
  2. UpdateGaugeNeedleInput.gauge_needle is @required, and so is its descriptionneedle_params opens with params.require(:gauge_needle), which rejects a missing wrapper and an empty one alike, and description is the only member the update accepts (needle_params.except(:color, :position)). So the wrapper-less and empty-wrapper bodies every SDK permitted were a 400, never a no-op. Matches CreateGaugeNeedle. Go's wrapper keeps Description *string and refuses nil before the wire as a usage error.
  3. notify doc string — names everyone, default, custom, which is exactly what Subscribers#find_subscribers accepts; the previous working_on was invented and silently notified nobody. Surfaced in generated docs in all six SDKs.
  4. Gauge.previous_needle_position is nullable — JSON null for a gauge's first needle (gauges.md shows it). nullable: true layered in enhance-openapi-go-types.sh like the other nullable-when-present members; Go's wrapper field becomes *int32 so the null is distinguishable from a genuine move from 0. A second fixture, gauges/get_first_needle.json, pins the null against the schema.
  5. ToggleGauge declares NotFoundErrorProjectScoped raises RecordNotFound for an unknown project, as ListGaugeNeedles on the same label already declared.

The three "noted, not proposed" items in the issue (.json suffix asymmetry, maxPageSize: 50, comma-joined bucket_ids) are left as they are.

Red-proof, from the literal wire bodies

  • Go: TestGaugeNeedle_DecodesTheSingularCommentCount (comment_count: 5 next to comments_count: 2 — the field did not exist before) and TestGauge_PreviousNeedlePositionNullIsNotZero (null → nil, wire 0 → non-nil 0; the value type decoded both to 0).
  • Swift: GaugeNeedle is typed, so the test fixture gained comment_count and the decode test asserts commentCount — before the spec change the field was discarded.
  • Kotlin: the "omits the wrapper when no attributes are given" test is replaced by one pinning that the wrapper always goes on the wire, since bc3 requires it.
  • Fixtures: make check-fixture-coverage validates needle_get.json against the now-required member and get_first_needle.json's null against the now-nullable one.

Breaking

Labelled breaking; the # Unreleased section in MIGRATING.md covers both:

  • gauge_needle and its description become required on UpdateGaugeNeedle in TypeScript, Python, Ruby, Kotlin and Swift (a call that omitted them stops compiling or raises before the wire — it always got a 400; an explicit None/nil in Python/Ruby still compacts to an empty body and gets the 400).
  • GaugeNeedle.comment_count is required, so Swift's public initializer and the TypeScript/Python model types gain a required member.
  • Go Gauge.PreviousNeedlePosition is *int32 (apidiff flags the type change).

Fixes #731

Copilot AI balanced review requested due to automatic review settings September 9, 2026 23:49
@jeremy jeremy added bug Something isn't working breaking Breaking change to public API labels Sep 9, 2026
@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 python Pull requests that update the Python SDK labels Sep 9, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 9, 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-09-10T23:37:41.401933Z c459cdb New commits
ℹ️ 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.

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.

🟡 Changes recommended

The empty update payload remains invalid, TypeScript validation lacks coverage, and migration guidance misstates breaking and nil behavior.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Aligns the Gauges specification and all six SDKs with bc3’s served contract.

Changes:

  • Models comment_count, nullable previous positions, and ToggleGauge 404s.
  • Requires the gauge-needle update wrapper and corrects notification documentation.
  • Regenerates SDK artifacts, fixtures, tests, and migration guidance.

[!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 summaries
File Description
spec/basecamp.smithy Updates the canonical Gauges contract.
openapi.json Regenerates the OpenAPI model.
scripts/enhance-openapi-go-types.sh Marks previous needle position nullable.
spec/fixtures/manifest.yaml Registers the first-needle fixture.
spec/fixtures/gauges/needle_get.json Adds singular comment count.
spec/fixtures/gauges/get_first_needle.json Covers a null previous position.
typescript/src/generated/services/gauges.ts Requires and validates the update wrapper.
typescript/src/generated/schema.d.ts Regenerates Gauge types and responses.
typescript/src/generated/openapi-stripped.json Synchronizes generated OpenAPI input.
typescript/src/generated/metadata.ts Refreshes generation metadata.
swift/Sources/Basecamp/Generated/Models/UpdateGaugeNeedleRequest.swift Makes the payload non-optional.
swift/Sources/Basecamp/Generated/Models/GaugeNeedle.swift Adds required commentCount.
swift/Tests/BasecampTests/GaugesServiceTests.swift Tests singular comment-count decoding.
ruby/lib/basecamp/generated/services/gauges_service.rb Requires the update keyword.
ruby/lib/basecamp/generated/types.rb Adds the comment-count model field.
ruby/lib/basecamp/generated/metadata.json Refreshes generation metadata.
python/src/basecamp/generated/services/gauges.py Requires the update argument.
python/src/basecamp/generated/types.py Updates Gauge typing.
kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/services/Types.kt Makes the update payload non-nullable.
kotlin/sdk/src/commonMain/kotlin/com/basecamp/sdk/generated/services/gauges.kt Always serializes the wrapper.
kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/GaugesServiceTest.kt Updates wrapper serialization coverage.
go/pkg/generated/client.gen.go Regenerates Gauge models and 404 handling.
go/pkg/basecamp/gauges.go Preserves null positions and comment counts.
go/pkg/basecamp/gauges_test.go Tests both corrected decode behaviors.
MIGRATING.md Documents consumer-facing changes.
Review details
  • Files reviewed: 11/25 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread kotlin/sdk/src/commonTest/kotlin/com/basecamp/sdk/GaugesServiceTest.kt Outdated
Comment thread MIGRATING.md Outdated
Comment thread MIGRATING.md Outdated

@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: a61be65d24

ℹ️ 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 MIGRATING.md Outdated
Comment thread MIGRATING.md Outdated
@jeremy

jeremy commented Sep 10, 2026

Copy link
Copy Markdown
Member Author

Converged: CI green on 591cc24 (46 checks), the first review round's five threads all fixed and answered (description required on the update payload at the spec layer, migration text corrected on explicit nil and on the comment_count break), and no review activity since. Labelled breaking; MIGRATING.md carries the Unreleased section. Ready for a human look and merge.

GaugeNeedle models the singular comment_count bc3 emits unconditionally;
UpdateGaugeNeedle requires its gauge_needle wrapper, as bc3 does; the
notify doc names the values Subscribers#find_subscribers accepts; Gauge's
previous_needle_position is nullable, and Go's wrapper takes a pointer so
the first needle's null is not a move from 0; ToggleGauge declares
NotFoundError. Regenerated into all six SDKs.

Fixes #731
…migration note

The Rust SDK landed on main while this branch was open, and it is generated
from the same openapi.json: gauge_needle and its description become required
members, comment_count arrives on GaugeNeedle, and the one generated-call
test that answered a needle now carries it.
@jeremy
jeremy force-pushed the fix/gauges-spec-drift branch from bb4d1ff to 84161f7 Compare September 10, 2026 21:38

@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: 84161f7642

ℹ️ 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 go/pkg/basecamp/gauges.go
Comment thread MIGRATING.md Outdated
Comment thread spec/basecamp.smithy
Comment thread MIGRATING.md Outdated
…st type, and carry comment_count in every inline needle stub

SPEC's upload paragraph cited the gauge-needle as the precedent where a
nil *string leaves the field alone, which UpdateNeedle now refuses as a
usage error: the description is the payload's only member and bc3
requires it, so there is no third state to express. The migration note
named a Rust type that does not exist — the generated service takes
UpdateGaugeNeedleRequestContent — and left out that Python's Gauge
TypedDict now types previous_needle_position NotRequired[Optional[int]].
The Go and Python needle stubs that omitted comment_count decoded to a
zero the contract no longer allows; they carry the required key now, as
the Kotlin and Swift stubs and the shared fixture already did.
* origin/main:
  fix(kotlin): project the transport error before it becomes the network message (#872)
  deps(rust): bump toml in /rust in the cargo-dependencies group (#863)
  deps(actions): bump the actions group across 1 directory with 2 updates (#865)
  Compile the CodeQL Kotlin build with the newest Kotlin CodeQL supports (#875)
@jeremy
jeremy merged commit c0703b8 into main Sep 11, 2026
55 checks passed
@jeremy
jeremy deleted the fix/gauges-spec-drift branch September 11, 2026 22:20
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 bug Something isn't working 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.

Gauges: five spec drifts from the contract bc3 actually serves

2 participants