Skip to content

Commit 04e54b8

Browse files
committed
Expand spec to 102 operations, regenerate all 5 SDKs
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.
1 parent 852db62 commit 04e54b8

129 files changed

Lines changed: 20823 additions & 3486 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/release-kotlin.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
steps:
2323
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2424

25-
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
25+
- uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
2626
with:
2727
distribution: corretto
2828
java-version: '17'

.github/workflows/release-typescript.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
steps:
2323
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2424

25-
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
25+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
2626
with:
2727
node-version: '20'
2828
registry-url: 'https://registry.npmjs.org'

.github/workflows/security.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ jobs:
3131
runs-on: ubuntu-latest
3232
steps:
3333
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
34-
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
34+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
3535
with:
3636
node-version: '22'
3737
- name: Install
@@ -68,7 +68,7 @@ jobs:
6868
ignore-unfixed: true
6969
format: sarif
7070
output: trivy-go.sarif
71-
- uses: github/codeql-action/upload-sarif@820e3160e279568db735cee8ed8f8e77a6da7818 # v3
71+
- uses: github/codeql-action/upload-sarif@9792ccaef0455e446c567163589397e8c3ac2e0d # v3
7272
if: always()
7373
with:
7474
sarif_file: trivy-go.sarif
@@ -88,7 +88,7 @@ jobs:
8888
ignore-unfixed: true
8989
format: sarif
9090
output: trivy-typescript.sarif
91-
- uses: github/codeql-action/upload-sarif@820e3160e279568db735cee8ed8f8e77a6da7818 # v3
91+
- uses: github/codeql-action/upload-sarif@9792ccaef0455e446c567163589397e8c3ac2e0d # v3
9292
if: always()
9393
with:
9494
sarif_file: trivy-typescript.sarif
@@ -108,7 +108,7 @@ jobs:
108108
ignore-unfixed: true
109109
format: sarif
110110
output: trivy-ruby.sarif
111-
- uses: github/codeql-action/upload-sarif@820e3160e279568db735cee8ed8f8e77a6da7818 # v3
111+
- uses: github/codeql-action/upload-sarif@9792ccaef0455e446c567163589397e8c3ac2e0d # v3
112112
if: always()
113113
with:
114114
sarif_file: trivy-ruby.sarif

.github/workflows/smithy-verify.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ jobs:
1010
steps:
1111
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
1212

13-
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
13+
- uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
1414
with:
1515
distribution: corretto
1616
java-version: '17'

.github/workflows/test.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ jobs:
5555
needs: smithy
5656
steps:
5757
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
58-
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
58+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
5959
with:
6060
node-version: '22'
6161
- name: Install
@@ -134,7 +134,7 @@ jobs:
134134
needs: smithy
135135
steps:
136136
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
137-
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
137+
- uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
138138
with:
139139
distribution: corretto
140140
java-version: '17'
@@ -169,7 +169,7 @@ jobs:
169169
runs-on: ubuntu-latest
170170
steps:
171171
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
172-
- uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
172+
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
173173
with:
174174
node-version: '22'
175175
- run: cd typescript && npm ci && npm run build
@@ -195,7 +195,7 @@ jobs:
195195
runs-on: ubuntu-latest
196196
steps:
197197
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
198-
- uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
198+
- uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4
199199
with:
200200
distribution: corretto
201201
java-version: '17'

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ repos:
1414
hooks:
1515
- id: golangci-lint
1616
entry: bash -c 'cd go && golangci-lint run'
17+
pass_filenames: false

RAILS-API-COMMUNIQUE.md

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
# Fizzy SDK → Rails API Surface Communique
2+
3+
The SDK spec has been expanded from 70 to 102 operations with full conformance coverage across Go, TypeScript, Ruby, Swift, and Kotlin. This document captures what the Rails app needs to match, verified against the Rails source.
4+
5+
---
6+
7+
## Response shape changes already aligned with Rails
8+
9+
These shape changes were made to match what Rails actually returns. No Rails changes needed.
10+
11+
### UserSummary eliminated — full User everywhere
12+
13+
The SDK now expects the full `_user.json.jbuilder` shape (`{id, name, role, active, email_address, avatar_url, created_at, url}`) in all embedded positions: `Board.creator`, `Card.creator`, `Card.assignees[]`, `Comment.creator`, `Reaction.reacter`, `Notification.creator`. Rails already renders the full partial everywhere — **no change needed**.
14+
15+
Note: `email_address` comes from `user.identity&.email_address` — system users with no identity will have `null`. The SDK marks this field optional.
16+
17+
### BoardSummary and ColumnSummary eliminated
18+
19+
`Card.board` and `Card.column` now expect full Board/Column shapes. Rails card partial already renders `json.partial! "boards/board"` and `json.partial! "columns/column"`**no change needed**.
20+
21+
### Column.color is Object {name, value}
22+
23+
Rails `_column.json.jbuilder` serializes `color` via `json.(column, :color)` which implicitly serializes the `Color = Struct.new(:name, :value)` as `{"name": "Blue", "value": "var(--color-card-default)"}`**already correct**.
24+
25+
### Tag.name → Tag.title
26+
27+
Rails `_tag.json.jbuilder` already returns `title` (not `name`), plus `created_at` and `url`. **Already aligned**.
28+
29+
Note: `url` is a cards index URL filtered to that tag (`cards_url(tag_ids: [tag])`), not a tag show URL.
30+
31+
### Account: slug, created_at added
32+
33+
Rails `_account.json.jbuilder` already returns `{id, name, slug, created_at}`. The `user` field is added at the identity level (`my/identities/show.json.jbuilder`), not in the account partial itself. **Already aligned**.
34+
35+
### ListPins returns Card[]
36+
37+
Rails `my/pins/index.json.jbuilder` already returns `json.array! @pins { json.partial! "cards/card", card: pin.card }` — flat card array. **Already aligned**.
38+
39+
### All IDs are strings
40+
41+
Rails returns string IDs via `to_param`**no change needed**.
42+
43+
---
44+
45+
## Shape discrepancies requiring Rails attention
46+
47+
### Card.has_more_assignees, comments_url, reactions_url
48+
49+
Rails card partial includes `has_more_assignees`, `comments_url`, and `reactions_url` fields. The SDK spec doesn't include these. Low priority but worth noting for completeness.
50+
51+
### Card.description_html
52+
53+
Rails card partial returns both `description` (plain text) and `description_html` (HTML). SDK spec only has `description`. Consider adding `description_html` to the spec.
54+
55+
### Steps index: no standalone endpoint
56+
57+
The SDK spec defines `ListSteps` as `GET /{acct}/cards/{number}/steps.json`. Rails has no `steps/index.json.jbuilder` — steps are embedded inline in `cards/show.json.jbuilder` only. Individual step CRUD does have JSON responses.
58+
59+
**Either:** (a) Add a steps index JSON endpoint to Rails, or (b) remove `ListSteps` from the SDK spec and document that steps come from the card show response.
60+
61+
---
62+
63+
## New endpoints: confirmed HTML/Turbo-only in Rails
64+
65+
All of these routes exist in Rails but serve **only HTML or Turbo Stream responses**. Each needs a `respond_to { |format| format.json { head :ok } }` (or appropriate JSON body) added.
66+
67+
### Void-response endpoints (just need `head :ok` / `head :no_content`)
68+
69+
| Operation | Controller | Method | Path |
70+
|-----------|-----------|--------|------|
71+
| PublishBoard | `Boards::PublicationsController#create` | POST | `/{acct}/boards/{id}/publication.json` |
72+
| UnpublishBoard | `Boards::PublicationsController#destroy` | DELETE | `/{acct}/boards/{id}/publication.json` |
73+
| UpdateBoardInvolvement | `Boards::InvolvementsController#update` | PATCH | `/{acct}/boards/{id}/involvement.json` |
74+
| UpdateBoardEntropy | `Boards::EntropiesController#update` | PATCH | `/{acct}/boards/{id}/entropy.json` |
75+
| UpdateAccountEntropy | `Account::EntropiesController#update` | PATCH | `/{acct}/account/entropy.json` |
76+
| MoveColumnLeft | `Columns::LeftPositionsController#create` | POST | `/{acct}/columns/{id}/left_position.json` |
77+
| MoveColumnRight | `Columns::RightPositionsController#create` | POST | `/{acct}/columns/{id}/right_position.json` |
78+
| MarkCardRead | `Cards::ReadingsController#create` | POST | `/{acct}/cards/{number}/reading.json` |
79+
| MarkCardUnread | `Cards::ReadingsController#destroy` | DELETE | `/{acct}/cards/{number}/reading.json` |
80+
| PublishCard | `Cards::PublishesController#create` | POST | `/{acct}/cards/{number}/publish.json` |
81+
| UpdateUserRole | `Users::RolesController#update` | PATCH | `/{acct}/users/{id}/role.json` |
82+
| DeleteUserAvatar | `Users::AvatarsController#destroy` | DELETE | `/{acct}/users/{id}/avatar` |
83+
| UpdateAccountSettings | `Account::SettingsController#update` | PATCH | `/{acct}/account/settings.json` |
84+
| UpdateNotificationSettings | `Notifications::SettingsController#update` | PATCH | `/{acct}/notifications/settings.json` |
85+
| ResetJoinCode | `Account::JoinCodesController#destroy` | DELETE | `/{acct}/account/join_code.json` |
86+
| UpdateJoinCode | `Account::JoinCodesController#update` | PATCH | `/{acct}/account/join_code.json` |
87+
| CreatePushSubscription | `Users::PushSubscriptionsController#create` | POST | `/{acct}/users/{id}/push_subscriptions.json` |
88+
| DeletePushSubscription | `Users::PushSubscriptionsController#destroy` | DELETE | `/{acct}/users/{id}/push_subscriptions/{subId}` |
89+
90+
### Endpoints needing JSON views (return data)
91+
92+
| Operation | Controller | Path | Expected response |
93+
|-----------|-----------|------|-------------------|
94+
| GetAccountSettings | `Account::SettingsController#show` | GET `/{acct}/account/settings.json` | `{name}` |
95+
| GetJoinCode | `Account::JoinCodesController#show` | GET `/{acct}/account/join_code.json` | `{code, url, usage_limit?}` |
96+
| GetNotificationSettings | `Notifications::SettingsController#show` | GET `/{acct}/notifications/settings.json` | `{bundle_email_frequency}` |
97+
| ListStreamCards | `Boards::Columns::StreamsController#show` | GET `/{acct}/boards/{id}/columns/stream.json` | `Card[]` (paginated) |
98+
| ListPostponedCards | `Boards::Columns::NotNowsController#show` | GET `/{acct}/boards/{id}/columns/not_now.json` | `Card[]` (paginated) |
99+
| ListClosedCards | `Boards::Columns::ClosedsController#show` | GET `/{acct}/boards/{id}/columns/closed.json` | `Card[]` (paginated) |
100+
| SearchCards | `SearchesController#show` | GET `/{acct}/search.json?q=...` | `Card[]` (paginated) |
101+
| CreateAccountExport | `Account::ExportsController#create` | POST `/{acct}/account/exports.json` | `{id, status, created_at, download_url?}` |
102+
| GetAccountExport | `Account::ExportsController#show` | GET `/{acct}/account/exports/{id}` | `{id, status, created_at, download_url?}` |
103+
104+
### Access tokens (partial JSON exists)
105+
106+
| Operation | Path | Notes |
107+
|-----------|------|-------|
108+
| ListAccessTokens | GET `/my/access_tokens.json` | **Needs JSON index view** — currently HTML only |
109+
| CreateAccessToken | POST `/my/access_tokens.json` | Has inline JSON (`{token, description, permission}`) — **needs `id` and `created_at` added** |
110+
| DeleteAccessToken | DELETE `/my/access_tokens/{id}` | Needs `format.json { head :no_content }` |
111+
112+
---
113+
114+
## Input field names (SDK sends these — Rails must `permit` them)
115+
116+
| Operation | Field SDK sends | Verify `params.permit` |
117+
|-----------|----------------|----------------------|
118+
| AssignCard | `assignee_id` | Was `user_id` in some references |
119+
| TagCard | `tag_title` | Was `name` in some references |
120+
| UpdateUserRole | `role` | String: "member" or "admin" |
121+
| UpdateBoardInvolvement | `involvement` | String |
122+
| UpdateBoardEntropy | `auto_postpone_period` | Integer |
123+
| UpdateAccountEntropy | `auto_postpone_period` | Integer |
124+
| UpdateAccountSettings | `name` | String |
125+
| UpdateNotificationSettings | `bundle_email_frequency` | String |
126+
| UpdateJoinCode | `usage_limit` | Integer |
127+
| CreatePushSubscription | `endpoint`, `p256dh_key`, `auth_key` | All strings |
128+
| CreateBoard/UpdateBoard | `public_description`, `auto_postpone_period` | New optional fields |
129+
| UpdateBoard | `user_ids` | Array of strings |
130+
131+
---
132+
133+
## Idempotency contract
134+
135+
The SDK retries these operations on 503/5xx (naturally idempotent — calling twice has the same effect). Rails should ensure they're truly safe to replay:
136+
137+
- `MarkCardRead` (POST) / `MarkCardUnread` (DELETE) — toggle read state
138+
- `MoveColumnLeft` / `MoveColumnRight` (POST) — positional, already-leftmost is a no-op
139+
- `PublishBoard` (POST) / `UnpublishBoard` (DELETE) — toggle publish state
140+
- `PublishCard` (POST) — publish draft, already-published is a no-op
141+
- `CloseCard`, `PostponeCard`, `GoldCard`, `PinCard`, `WatchCard`, `TriageCard` (POST)
142+
- `ReopenCard` (DELETE) — reopen a closed card
143+
- `ActivateWebhook`, `DeactivateWebhook` (POST)
144+
- `ReadNotification` (POST)
145+
146+
The SDK does **not** retry: `CreateCard`, `CreateBoard`, `CreateComment`, `CreateStep`, `CreateWebhook`, `AssignCard`, `TagCard`, `CreateSession`, `CreateAccessToken`, `CreatePushSubscription`, `CreateAccountExport`.
147+
148+
---
149+
150+
## Priority order
151+
152+
1. **Shape discrepancy decisions** — Card.tags (strings vs objects), ListSteps (standalone vs embedded)
153+
2. **Void-response JSON paths** — 18 controllers need `format.json { head :ok }`, low effort
154+
3. **Data-returning JSON views** — 9 endpoints need jbuilder templates
155+
4. **Access token JSON index** — new template needed

0 commit comments

Comments
 (0)