Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions .claude/skills/upstream-sync.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
---
description: Sync the Fizzy SDK spec and generated SDKs to upstream Fizzy API changes
user_invocable: true
---

# Fizzy SDK Upstream Sync Workflow

Sync this repo to upstream Fizzy API changes.

## Purpose

This repo does **not** bump a third-party SDK dependency.
Instead, the upstream sync workflow is:

1. review upstream Fizzy API changes
2. update the Smithy spec in `spec/`
3. regenerate derived artifacts and per-language SDK code
4. add/update tests
5. update provenance
6. run full checks

## Hard Rules

- **Never hand-write API methods.** All operations must come from the Smithy spec.
- **Never construct URL paths manually.** Use the generated route table.
- **Never edit `openapi.json` directly.** It is derived from Smithy.
- **Every new operation needs tests.** Add unit tests per language plus conformance tests.
- **Run `make check` before finishing.**

## Canonical Upstream Sources

When syncing, treat these upstream Fizzy sources as the references:

- `docs/api/README.md`
- `docs/api/sections/`
- `config/routes.rb`
- `app/controllers/`
- `app/views/`
- `app/models/`

If docs and behavior disagree, verify against routes/controllers/views/models and then update Smithy to match actual behavior.

## Steps

1. **Read the current baseline**
- Read `spec/api-provenance.json`
- Read `spec/README.md`
- Read `AGENTS.md`

2. **Check what changed upstream**
- Run `make sync-status`
- If needed, inspect the changed upstream files in the Fizzy app repo at the recorded revision vs `main`
- Focus only on API-relevant changes in the canonical sources listed above

3. **Update the Smithy spec**
- Edit `spec/fizzy.smithy`
- Edit `spec/fizzy-traits.smithy` if new traits or modeling support are required
- Keep changes additive and shape-accurate
- Do not patch generated SDK code by hand to compensate for missing Smithy changes

4. **Regenerate derived artifacts**
- Run `make smithy-build`
- Run `make url-routes`

5. **Regenerate SDKs**
Run the generators needed for the impacted languages. For a normal API sync, run all of them:

- `make go-generate-services`
- `make ts-generate`
- `make ts-generate-services`
- `make rb-generate`
- `make rb-generate-services`
- `make swift-generate`
- `make kt-generate-services`

6. **Add or update tests**
- Add unit tests for each affected language
- Add/update conformance tests for behavioral changes
- If a new operation was added, make sure tests cover request/response behavior and any special semantics

7. **Update provenance**
- Update `spec/api-provenance.json` with the new upstream revision/date
- Keep the tracked `paths` aligned with the canonical upstream sources
- Run `make provenance-sync`

8. **Run validation**
- Run `make check`
- Fix any drift, generation, or test failures before finishing

9. **Summarize the upstream sync**
Include:
- old vs new upstream revision
- which upstream API surfaces changed
- which Smithy operations/shapes changed
- which SDKs/tests were regenerated or updated

## Expected Outputs

A complete sync should typically leave changes in areas like:

- `spec/fizzy.smithy`
- `spec/fizzy-traits.smithy` (if needed)
- `openapi.json`
- `behavior-model.json`
- `url-routes.json`
- generated SDK service/type files in language directories
- tests
- `spec/api-provenance.json`
- `go/pkg/fizzy/api-provenance.json`

## Stop Conditions

Stop and call out the issue if:

- the upstream behavior is ambiguous across docs/routes/controllers/views/models
- a change would require hand-written API methods instead of Smithy-driven generation
- generated route data is missing and would force manual path building
- a new behavior cannot be covered by tests
58 changes: 41 additions & 17 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,32 @@ Smithy spec -> OpenAPI -> Behavior Model -> Per-language generators -> SDK code

## Development Workflow

1. Edit the Smithy spec in `spec/`
2. Run `make smithy-build` to regenerate OpenAPI
3. Run per-language generators: `make {lang}-generate-services`
4. Add/update tests
5. Run `make check`
6. Commit
1. Review upstream Fizzy API sources:
- [`docs/api/README.md`](https://github.com/basecamp/fizzy/blob/main/docs/api/README.md)
- [`docs/api/sections/`](https://github.com/basecamp/fizzy/tree/main/docs/api/sections)
- [`config/routes.rb`](https://github.com/basecamp/fizzy/blob/main/config/routes.rb)
- [`app/controllers/`](https://github.com/basecamp/fizzy/tree/main/app/controllers)
- [`app/views/`](https://github.com/basecamp/fizzy/tree/main/app/views)
- [`app/models/`](https://github.com/basecamp/fizzy/tree/main/app/models)
2. Edit the Smithy spec in `spec/`
3. Run `make smithy-build` to regenerate OpenAPI
4. Run per-language generators: `make {lang}-generate-services`
5. Add/update tests
6. Run `make check`
7. Commit

## Upstream Reference Sources

When syncing the SDK spec to upstream Fizzy changes, treat these as the primary references:

- **API docs** — [`docs/api/README.md`](https://github.com/basecamp/fizzy/blob/main/docs/api/README.md)
- **API section docs** — [`docs/api/sections/`](https://github.com/basecamp/fizzy/tree/main/docs/api/sections)
- **Routes** — [`config/routes.rb`](https://github.com/basecamp/fizzy/blob/main/config/routes.rb)
- **Controllers** — [`app/controllers/`](https://github.com/basecamp/fizzy/tree/main/app/controllers)
- **Views / JSON rendering** — [`app/views/`](https://github.com/basecamp/fizzy/tree/main/app/views)
- **Relevant models** — [`app/models/`](https://github.com/basecamp/fizzy/tree/main/app/models)

The SDK generation pipeline still starts from Smithy, but Smithy should be kept aligned with these upstream sources.

## Auth Model

Expand All @@ -37,24 +57,28 @@ Fizzy uses **two auth strategies** (no OAuth):
- **CookieAuth** — `Cookie: session_token=<value>` for session-based auth (mobile/web)
- **MagicLinkFlow** — orchestrates passwordless login: `CreateSession` → `RedeemMagicLink`

## Service Inventory
## API Surface Inventory

70 operations across 15 services:
111 operations across the current Smithy-defined API surface:

| Service | Operations |
| Area | Operations |
|---------|-----------|
| Identity | GetMyIdentity |
| Boards | ListBoards, CreateBoard, GetBoard, UpdateBoard, DeleteBoard |
| Columns | ListColumns, CreateColumn, GetColumn, UpdateColumn |
| Cards | ListCards, CreateCard, GetCard, UpdateCard, DeleteCard, CloseCard, ReopenCard, PostponeCard, TriageCard, UnTriageCard, GoldCard, UngoldCard, AssignCard, SelfAssignCard, TagCard, WatchCard, UnwatchCard, PinCard, UnpinCard, MoveCard, DeleteCardImage |
| Access Tokens | ListAccessTokens, CreateAccessToken, DeleteAccessToken |
| Account | GetAccountSettings, UpdateAccountSettings, GetJoinCode, UpdateJoinCode, ResetJoinCode, UpdateAccountEntropy, CreateAccountExport, GetAccountExport |
| Boards | ListBoards, CreateBoard, GetBoard, ListBoardAccesses, UpdateBoard, DeleteBoard, PublishBoard, UnpublishBoard, UpdateBoardInvolvement, UpdateBoardEntropy, ListStreamCards, ListPostponedCards, ListClosedCards |
| Columns | ListColumns, CreateColumn, GetColumn, UpdateColumn, DeleteColumn, MoveColumnLeft, MoveColumnRight |
| Cards | ListCards, ListColumnCards, CreateCard, GetCard, UpdateCard, DeleteCard, CloseCard, ReopenCard, PostponeCard, TriageCard, UnTriageCard, GoldCard, UngoldCard, AssignCard, SelfAssignCard, TagCard, WatchCard, UnwatchCard, PinCard, UnpinCard, MoveCard, DeleteCardImage, MarkCardRead, MarkCardUnread, PublishCard |
| Comments | ListComments, CreateComment, GetComment, UpdateComment, DeleteComment |
| Steps | CreateStep, GetStep, UpdateStep, DeleteStep |
| Steps | ListSteps, CreateStep, GetStep, UpdateStep, DeleteStep |
| Reactions | ListCardReactions, CreateCardReaction, DeleteCardReaction, ListCommentReactions, CreateCommentReaction, DeleteCommentReaction |
| Notifications | ListNotifications, ReadNotification, UnreadNotification, BulkReadNotifications, GetNotificationTray |
| Notifications | ListNotifications, ReadNotification, UnreadNotification, BulkReadNotifications, GetNotificationTray, GetNotificationSettings, UpdateNotificationSettings |
| Search | SearchCards |
| Activities | ListActivities |
| Tags | ListTags |
| Users | ListUsers, GetUser, UpdateUser, DeactivateUser |
| Users | ListUsers, GetUser, UpdateUser, DeactivateUser, RequestEmailAddressChange, ConfirmEmailAddressChange, CreateUserDataExport, GetUserDataExport, UpdateUserRole, DeleteUserAvatar, CreatePushSubscription, DeletePushSubscription |
| Pins | ListPins |
| Uploads | CreateDirectUpload |
| Webhooks | ListWebhooks, CreateWebhook, GetWebhook, UpdateWebhook, DeleteWebhook, ActivateWebhook |
| Sessions | CreateSession, RedeemMagicLink, DestroySession, CompleteSignup |
| Webhooks | ListWebhooks, CreateWebhook, GetWebhook, UpdateWebhook, DeleteWebhook, ActivateWebhook, ListWebhookDeliveries |
| Sessions | CreateSession, RedeemMagicLink, DestroySession, CompleteSignup, CompleteJoin |
| Devices | RegisterDevice, UnregisterDevice |
22 changes: 22 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,28 @@ Alternatively, prefix commands with `mise exec --`.
5. Add conformance tests if the operation has behavioral requirements
6. Run `make check`

## Syncing to Upstream Fizzy

The SDK generators read the Smithy spec, but the Smithy spec should be maintained against upstream Fizzy API sources:

- [`docs/api/README.md`](https://github.com/basecamp/fizzy/blob/main/docs/api/README.md)
- [`docs/api/sections/`](https://github.com/basecamp/fizzy/tree/main/docs/api/sections)
- [`config/routes.rb`](https://github.com/basecamp/fizzy/blob/main/config/routes.rb)
- [`app/controllers/`](https://github.com/basecamp/fizzy/tree/main/app/controllers)
- [`app/views/`](https://github.com/basecamp/fizzy/tree/main/app/views)
- [`app/models/`](https://github.com/basecamp/fizzy/tree/main/app/models)

Recommended sync workflow:

1. Review upstream docs and Rails changes
2. Update `spec/fizzy.smithy` / `spec/fizzy-traits.smithy`
3. Run `make smithy-build`
4. Run language generators
5. Update tests
6. Update `spec/api-provenance.json`
7. Run `make provenance-sync`
8. Run `make check`

## Release Process

Releases are managed via `make release VERSION=x.y.z`. See the Makefile for details.
14 changes: 8 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,16 @@ provenance-check:
@echo " Provenance is in sync"

sync-status:
@REV=$$(jq -r '.fizzy.revision' spec/api-provenance.json); \
if [ -z "$$REV" ] || [ "$$REV" = "null" ] || [ "$$REV" = "" ]; then \
echo "No revision recorded in api-provenance.json. Run provenance-sync after setting revision."; \
@REV=$$(jq -r '.fizzy.revision // empty' spec/api-provenance.json); \
if [ -z "$$REV" ]; then \
echo "==> fizzy: no baseline revision set"; \
exit 0; \
fi; \
echo "==> Checking for upstream changes since $$REV..."; \
gh api "repos/basecamp/fizzy/compare/$$REV...main" --jq '.ahead_by' 2>/dev/null | xargs -I{} echo " {} commits ahead" || \
echo " Could not query upstream (check gh auth)"
command -v gh > /dev/null 2>&1 || { echo "ERROR: gh CLI not found. Install: https://cli.github.com"; exit 1; }; \
gh auth status > /dev/null 2>&1 || { echo "ERROR: gh not authenticated. Run: gh auth login"; exit 1; }; \
echo "==> Upstream Fizzy API-related changes since $$(echo $$REV | cut -c1-7):"; \
gh api "repos/basecamp/fizzy/compare/$$REV...main" \
--jq '[.files[] | select((.filename == "docs/api/README.md") or (.filename | startswith("docs/api/sections/")) or (.filename == "config/routes.rb") or (.filename | startswith("app/controllers/")) or (.filename | startswith("app/views/")) or (.filename | startswith("app/models/")))] | if length == 0 then " (no API-doc/app-surface changes detected)" else .[] | " " + .status[:1] + " " + .filename end'

#---
# Go SDK (delegates to go/Makefile)
Expand Down
Loading
Loading