Expand spec to 102 operations, regenerate all 5 SDKs#9
Conversation
There was a problem hiding this comment.
Pull request overview
Expands the Fizzy OpenAPI/Smithy surface area to 102 operations and regenerates all 5 SDKs, including behavior-model–driven retry semantics and updated conformance infrastructure.
Changes:
- Added many new operations and removed/renamed pre-1.0 summary types, regenerating Go/TypeScript/Ruby/Swift/Kotlin SDK outputs.
- Introduced/standardized per-operation retry behavior (including idempotent POST retry) driven by
behavior-model.json. - Expanded conformance fixtures/runners and refreshed CI/Make targets to enforce drift/freshness and security checks.
Reviewed changes
Copilot reviewed 74 out of 270 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| ruby/scripts/generate-services.rb | Updates Ruby service generation (tag-less service derivation + behavior-model retry flags). |
| ruby/lib/fizzy/http.rb | Adds retry override plumbing + tightens pagination origin error message + localhost HTTP exception. |
| ruby/lib/fizzy/errors.rb | Ensures JSON dependency is available for error parsing/handling. |
| ruby/lib/fizzy/client.rb | Plumbs retry override through client verbs; adds miscellaneous service accessor. |
| ruby/.rubocop.yml | Disables Rails-specific Minitest cop for this non-Rails gem. |
| rubric-audit.json | Updates rubric audit date and operation/test counts for 102 ops. |
| kotlin/sdk/src/commonTest/kotlin/com/basecamp/fizzy/FizzyTest.kt | Adds Kotlin SDK tests for exception defaults, pagination SSRF guard, retry-after parsing, etc. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/fizzy/services/BaseService.kt | Adds root-scoped URL helpers + PATCH support; improves cross-origin pagination handling. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/fizzy/http/FizzyHttpClient.kt | Expands retryable status codes/methods and updates retry policy docs. |
| kotlin/sdk/src/commonMain/kotlin/com/basecamp/fizzy/FizzyHooks.kt | Broadens hook IDs to support non-Long identifiers. |
| kotlin/generator/src/main/kotlin/com/basecamp/fizzy/generator/ServiceEmitter.kt | Fixes PATCH emission and supports root-scoped operations. |
| kotlin/generator/src/main/kotlin/com/basecamp/fizzy/generator/OperationParser.kt | Adds isAccountScoped + derives service names when tags are absent. |
| kotlin/generator/src/main/kotlin/com/basecamp/fizzy/generator/MetadataEmitter.kt | Makes behavior-model retry parsing more tolerant of missing fields. |
| kotlin/generator/src/main/kotlin/com/basecamp/fizzy/generator/Config.kt | Adds operationId-based service name derivation for untagged operations. |
| go/pkg/fizzy/webhooks_service.go | New generated Go Webhooks service methods. |
| go/pkg/fizzy/users_service.go | New generated Go Users service methods. |
| go/pkg/fizzy/url-routes.json | Regenerated URL routes to cover new endpoints/params. |
| go/pkg/fizzy/uploads_service.go | New generated Go Uploads service methods. |
| go/pkg/fizzy/tags_service.go | New generated Go Tags service methods. |
| go/pkg/fizzy/steps_service.go | New generated Go Steps service methods. |
| go/pkg/fizzy/sessions_service.go | New generated Go Sessions service methods. |
| go/pkg/fizzy/search_service.go | New generated Go Search service method. |
| go/pkg/fizzy/reactions_service.go | New generated Go Reactions service methods. |
| go/pkg/fizzy/pins_service.go | New generated Go Pins service method. |
| go/pkg/fizzy/operations_registry.go | Adds operationId→service method registry for drift checking. |
| go/pkg/fizzy/notifications_service.go | New generated Go Notifications service methods. |
| go/pkg/fizzy/identity_service.go | New generated Go Identity service method. |
| go/pkg/fizzy/http.go | Adds WithNoRetry / WithIdempotent context controls and updates retry docs. |
| go/pkg/fizzy/devices_service.go | New generated Go Devices service methods. |
| go/pkg/fizzy/comments_service.go | New generated Go Comments service methods. |
| go/pkg/fizzy/columns_service.go | New generated Go Columns service methods. |
| go/pkg/fizzy/client.go | Removes old generated OpenAPI client usage; adds PATCH; adds new services + retry/error mapping tweaks. |
| go/pkg/fizzy/cards_service.go | New generated Go Cards service methods. |
| go/pkg/fizzy/boards_service.go | New generated Go Boards service methods. |
| go/pkg/fizzy/api-provenance.json | Updates provenance fields (but appears to diverge from spec provenance file copy). |
| go/pkg/fizzy/account_service.go | New generated Go Account service methods. |
| go/pkg/fizzy/access_tokens_service.go | New generated Go AccessTokens service methods. |
| go/oapi-codegen.yaml | Switches Go codegen to types-only output. |
| go/go.mod | Adds tooling and indirect deps needed for generation/diffing. |
| go/cmd/generate-services/main_test.go | Adds tests for Go service generator typed returns and helpers. |
| go.work | Adds workspace config with Go version pin. |
| conformance/tests/status-codes.json | Adds new status-code fixtures for new operations. |
| conformance/tests/request-shapes.json | Adds request-shape fixtures for new operations/fields. |
| conformance/tests/integer-precision.json | Adds fixtures for large integer/string ID handling. |
| conformance/tests/idempotency.json | Adds idempotent POST retry fixtures; updates PATCH/DELETE paths. |
| conformance/schema.json | Extends conformance schema with new overrides and assertion types. |
| conformance/runner/typescript/vitest.config.ts | Adds Vitest timeout config for TS runner. |
| conformance/runner/typescript/tsconfig.json | Adds TS runner tsconfig. |
| conformance/runner/typescript/runner.test.ts | Adds TS conformance runner using MSW + operation dispatcher. |
| conformance/runner/typescript/package.json | Adds TS conformance runner package manifest. |
| conformance/runner/ruby/runner.rb | Adds Ruby conformance runner using WebMock + operation dispatcher. |
| conformance/runner/ruby/Gemfile | Adds Gemfile for Ruby conformance runner. |
| conformance/runner/go/go.mod | Adds Go module for Go conformance runner. |
| behavior-model.json | Expands operations and retry-on codes (adds 500) + idempotent markers. |
| SECURITY.md | Documents cross-SDK security properties and retry/SSRF guarantees. |
| RAILS-API-COMMUNIQUE.md | Documents required Rails JSON endpoints and response shape expectations. |
| Makefile | Adds drift/freshness/provenance checks, splits check targets, and updates release/audit logic. |
| .pre-commit-config.yaml | Adds pre-commit hooks including golangci-lint. |
| .github/workflows/test.yml | Adds permissions, drift/freshness checks, splits conformance jobs, adds lint jobs, updates node versions. |
| .github/workflows/smithy-verify.yml | Adds additional freshness checks and fixes $GITHUB_PATH/$GITHUB_OUTPUT quoting. |
| .github/workflows/security.yml | Adds permissions, pins tool versions, adds Trivy/gosec jobs, updates node versions. |
| .github/workflows/release-typescript.yml | Fixes $GITHUB_OUTPUT quoting. |
| .github/workflows/release-swift.yml | Fixes $GITHUB_OUTPUT quoting. |
| .github/workflows/release-ruby.yml | Uses find to select gem artifact deterministically. |
| .github/workflows/release-go.yml | Fixes $GITHUB_OUTPUT quoting. |
| .github/workflows/release-github.yml | Fixes $GITHUB_OUTPUT quoting. |
| .github/workflows/dependabot-auto-merge.yml | Adds auto-merge workflow for Dependabot PRs. |
| .github/release.yml | Adds release-note category configuration. |
| .github/prompts/spec-impact.prompt.yml | Adds PR prompt to detect spec pipeline impact. |
| .github/actionlint.yaml | Adds actionlint config stub. |
Files not reviewed (1)
- conformance/runner/typescript/package-lock.json: Language not supported
Comments suppressed due to low confidence (1)
.github/workflows/test.yml:1
go-version: '1.26'is likely not a valid Go release (as of the latest stable versions prior to Aug 2025). If this version doesn’t exist inactions/setup-go, CI will fail to install Go. Use an existing Go version (or a semver range supported by the action), and ensurego.work/ modulegodirectives match.
name: Test
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
15 issues found across 270 files
Note: This PR contains a large number of files. cubic only reviews up to 75 files per PR, so some files may not have been reviewed.
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="rubric-audit.json">
<violation number="1" location="rubric-audit.json:20">
P2: Criterion 1A.6 still references "All 70 operations" while 4B.5 now references 102. Update 1A.6's note to match the current operation count so the audit document is internally consistent.</violation>
</file>
<file name="go/cmd/generate-services/main.go">
<violation number="1" location="go/cmd/generate-services/main.go:749">
P1: String query parameter values are not URL-encoded. The generated code uses `fmt.Sprintf` with `%s` to interpolate string values directly into the URL. For `SearchCards`' `q` parameter, search terms containing spaces, `&`, `=`, or other reserved characters will produce a malformed URL. The generator should emit `url.QueryEscape(*value)` for string-typed query params (and add `"net/url"` to the import block).</violation>
</file>
<file name="scripts/check-rb-service-drift.sh">
<violation number="1" location="scripts/check-rb-service-drift.sh:23">
P2: `grep` returns exit code 1 when there are no matches. Under `set -euo pipefail`, this silently kills the script before it can report the drift. Prefix with `{ grep ... || true; }` so that zero matches produce empty output instead of aborting.</violation>
</file>
<file name="kotlin/conformance/src/main/kotlin/com/basecamp/fizzy/conformance/Main.kt">
<violation number="1" location="kotlin/conformance/src/main/kotlin/com/basecamp/fizzy/conformance/Main.kt:105">
P2: `skipped` is declared and printed in the summary but never incremented. Unsupported assertion types hit the `ASSERT SKIP` print path yet return `true`, so they count as passes and the summary always reports `0 skipped`.</violation>
</file>
<file name=".pre-commit-config.yaml">
<violation number="1" location=".pre-commit-config.yaml:16">
P3: Add `pass_filenames: false` — the `bash -c` entry ignores staged filenames, so pre-commit appends them for nothing. Making this explicit avoids confusion and a (minor) wasted argument-list construction on each commit.</violation>
</file>
<file name="go/pkg/fizzy/access_tokens_service.go">
<violation number="1" location="go/pkg/fizzy/access_tokens_service.go:11">
P3: Generator bug: `accesstoken` should be `access token` (two words). The resource name from `access_tokens` is concatenated instead of being split on underscore. Same issue on lines 24 and 29. Since this is generated code, the fix belongs in `go/cmd/generate-services/`.
(Based on your team's feedback about deriving doc comment subjects from the service resource and fixing the generator rather than generated code.) [FEEDBACK_USED]</violation>
</file>
<file name="conformance/runner/go/main.go">
<violation number="1" location="conformance/runner/go/main.go:145">
P3: Both `loadNoRetryOps` and `loadIdempotentPostOps` duplicate ~40 lines of identical file-reading and JSON-parsing logic, and `main()` calls them with the same paths — reading each file twice. Consider extracting a shared helper that parses both files once and returns both maps.</violation>
<violation number="2" location="conformance/runner/go/main.go:255">
P2: The `skipped` counter is declared but never incremented, so the summary always reports `0 skipped`. Meanwhile, unsupported assertion types in `checkAssertion` return `true` and are silently counted as passes. The Ruby runner handles this correctly by tracking per-test skip state — the Go runner should do the same so unknown assertion types don't inflate the pass count.</violation>
</file>
<file name="kotlin/sdk/src/commonMain/kotlin/com/basecamp/fizzy/services/BaseService.kt">
<violation number="1" location="kotlin/sdk/src/commonMain/kotlin/com/basecamp/fizzy/services/BaseService.kt:244">
P2: Cross-origin pagination link should silently break instead of throwing. Replace the throw with `break` so pagination stops quietly and `ListMeta.truncated` indicates incomplete results.
(Based on your team's feedback about silently stopping pagination on cross-origin links.) [FEEDBACK_USED]</violation>
</file>
<file name="kotlin/sdk/src/commonMain/kotlin/com/basecamp/fizzy/http/FizzyHttpClient.kt">
<violation number="1" location="kotlin/sdk/src/commonMain/kotlin/com/basecamp/fizzy/http/FizzyHttpClient.kt:201">
P3: Stale inline comment at line ~97 still lists `(GET, PUT, DELETE, HEAD)` — it should include PATCH to match the updated `IDEMPOTENT_METHODS` set and the updated KDoc above `requestWithRetry`.</violation>
</file>
<file name="scripts/check-ts-service-drift.sh">
<violation number="1" location="scripts/check-ts-service-drift.sh:23">
P2: With `set -euo pipefail`, `grep` returning no matches (exit 1) will crash the script instead of reporting drift. Wrap the `grep` so a no-match exit code doesn't propagate.</violation>
</file>
<file name="go/pkg/fizzy/boards_service.go">
<violation number="1" location="go/pkg/fizzy/boards_service.go:58">
P3: Generator bug: `"closeds"` is not a word. The `generateDocComment` function naively pluralises the method-name remainder, which breaks for adjective suffixes. This method returns `[]generated.Card`, so the comment should say something like "returns closed cards for a board." Fix in `go/cmd/generate-services/main.go`.</violation>
</file>
<file name="go/pkg/fizzy/notifications_service.go">
<violation number="1" location="go/pkg/fizzy/notifications_service.go:17">
P2: Generator produces ungrammatical doc comment `returns a settings` — "settings" is uncountable, so the article is wrong. Same issue on `UpdateSettings` (line 73). The root cause is in `go/cmd/generate-services/main.go` around line 694: when the derived resource is already plural/uncountable (like "settings"), the generator should omit the article (e.g. `returns notification settings`) or singularize correctly.
(Based on your team's feedback about fixing the generator rather than generated code.) [FEEDBACK_USED]</violation>
</file>
<file name="kotlin/sdk/src/commonMain/kotlin/com/basecamp/fizzy/FizzyHooks.kt">
<violation number="1" location="kotlin/sdk/src/commonMain/kotlin/com/basecamp/fizzy/FizzyHooks.kt:45">
P2: `Any?` is unnecessarily broad — every call site passes `String?`. Use `String?` to preserve type safety and give hook consumers a clear contract without needing casts.</violation>
</file>
<file name="RAILS-API-COMMUNIQUE.md">
<violation number="1" location="RAILS-API-COMMUNIQUE.md:135">
P2: Three operations listed here (`UnpublishBoard`, `MarkCardUnread`, `ReopenCard`) are DELETE, not POST, per the OpenAPI spec. Calling them "POST operations" is inaccurate and could mislead Rails implementers about the expected HTTP method. Consider rewording to "The SDK retries these operations…" and noting which are POST (idempotent-tagged) vs DELETE (retried by default).</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 23df158741
ℹ️ 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".
There was a problem hiding this comment.
1 issue found across 16 files (changes from recent commits).
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/fizzy/http.go">
<violation number="1" location="go/pkg/fizzy/http.go:24">
P3: The `MaxRetries` field comment now says "retryable requests," but the `WithMaxRetries` function doc on line 61 still says "idempotent requests." Update it to match.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
Add 32 new operations covering access tokens, account settings, board entropy/involvement, join codes, notification settings, push subscriptions, search, steps index, and user role management. Consolidate summary types (UserSummary→User, BoardSummary→Board, ColumnSummary→Column, Pin→Card) across all SDKs — breaking for pre-1.0 consumers that reference the removed types. Go SDK gains typed return values and idempotent POST retry via WithIdempotent(ctx). Ruby gains retryable: true kwarg. Both propagated through generator from behavior-model.json. Generator improvements: URL-encode string query params, CamelCase word splitting in doc comments, smart pluralization, uncountable noun handling. Conformance runner skipped counters now tracked. Conformance suite expanded to 111 tests across 9 fixture files. All 4 runners (Go, TS, Ruby, Kotlin) passing.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 46 out of 129 changed files in this pull request and generated 2 comments.
Files not reviewed (2)
- conformance/runner/typescript/package-lock.json: Language not supported
- typescript/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
32 new generated service methods (thin wrappers over client HTTP methods) expanded the statement count without adding per-method tests. The underlying HTTP plumbing is well-tested; the generated wrappers are validated by conformance tests, not unit tests.
Go URLRoute struct now matches the actual JSON schema (pattern/ operations/params wrapper). URLRouteByOperation searches the operations map correctly. Remove PublishCard and DeactivateWebhook from the idempotent retry list in RAILS-API-COMMUNIQUE.md — neither is marked idempotent in behavior-model.json.
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
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="RAILS-API-COMMUNIQUE.md">
<violation number="1" location="RAILS-API-COMMUNIQUE.md:145">
P2: `DeactivateWebhook` is listed in the non-retry list but doesn't exist as an operation in the behavior model or anywhere in the codebase. If this operation was removed from the spec, drop it from this list to avoid confusing Rails developers about what endpoints the SDK actually calls.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 47 out of 130 changed files in this pull request and generated 1 comment.
Files not reviewed (2)
- conformance/runner/typescript/package-lock.json: Language not supported
- typescript/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
* Add permissions block to release-swift workflow Declare explicit `contents: read` permissions to enforce least-privilege and resolve code scanning alert #53. * Add permissions block to smithy-verify workflow Declare explicit `contents: read` permissions to enforce least-privilege and resolve code scanning alert #55. * Add permissions block to smoke workflow Declare explicit `contents: read` permissions to enforce least-privilege and resolve code scanning alert #59.
File was dropped during branch re-squash. Restored from prior commit and removed DeactivateWebhook from non-retry list — the operation doesn't exist in the spec.
Summary
UserSummary→User,BoardSummary→Board,ColumnSummary→Column,Pin→CardResponseContentschemas to*generated.Typeor[]generated.TypeWithIdempotent(ctx)in Go,retryable: truekwarg in Ruby — driven frombehavior-model.jsonBreaking changes
Pre-1.0 SDK — no public consumers. These would be semver-major post-1.0:
UserSummarydeletedUserinsteadBoardSummarydeletedBoardinsteadColumnSummarydeletedColumninsteadPin/PinListdeletedListPinsreturnsCard/CardListTag.name→Tag.titleNotificationCard.board→NotificationCard.board_nameAccount,Tag,NotificationCardMerge order
Test plan
make checkpasses (Smithy, OpenAPI, behavior model, url-routes, provenance, rubric audit, all 5 SDK checks, all 4 conformance runners)api-breadthdeployed to staging