Skip to content

docs: API compatibility — staged rollouts for mobile-visible schema changes - #2460

Open
vecchp wants to merge 1 commit into
mainfrom
docs/api-compatibility
Open

vecchp wants to merge 1 commit into
mainfrom
docs/api-compatibility

Conversation

@vecchp

@vecchp vecchp commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Docs-only. Codifies the rollout discipline the mobile compat audit produced (teams #2450/#2458, tasks #2457/#2459): released mobile binaries + instant backend deploys mean contract moves must be staged tolerant → release → strict, never in one step.

  • New apps/betterangels-backend/docs/api-compatibility.md: the asymmetry, the four rules (no one-step required fields, no fallback removal before adoption, additive changes are safe, semantic tightening needs its backfills), the three-deployment recipe with the DO-NOT-LAND checklist convention, and worked examples from the two live cutovers.
  • Pointer row added to graphql_errors.md's Related files (denial shapes stay there; this doc is about when contracts move).

Summary by Sourcery

Document the tolerant → release → strict rollout process for safely evolving API contracts used by released mobile clients.

New Features:

  • Document staged API rollout guidance for mobile-visible GraphQL schema changes, including compatibility rules, deployment sequencing, and real-world cutover examples.

Enhancements:

  • Clarify how released mobile clients constrain backend contract changes and distinguish rollout timing from authorization error-shape behavior.

Documentation:

  • Link the new API compatibility guidance from the GraphQL errors documentation.

…hanges

Codifies the tolerant → release → strict discipline from the mobile compat
audit: required-field additions and fallback removals get three deployments
(tolerant backend, client release, strict flip), additive changes stay
deploy-safe, and semantic tightening needs its backfills live first.  Worked
examples: teams header retirement (#2450/#2458), tasks payload org
(#2457/#2459).  Pointer added from graphql_errors.md's Related files.
@sourcery-ai

sourcery-ai Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds documentation for safely rolling out mobile-visible GraphQL schema changes across independently timed backend and app releases, centered on a tolerant → release → strict deployment sequence, and links that guidance from the GraphQL error reference.

Sequence diagram for staged mobile API contract rollout

sequenceDiagram
    participant Backend
    participant MobileApp
    participant Users

    Note over Backend,MobileApp: Step 1: tolerant backend
    Backend->>Backend: Accept new and legacy inputs
    Users->>MobileApp: Open released app
    MobileApp->>Backend: Send legacy input
    Backend-->>MobileApp: Preserve legacy behavior

    Note over Backend,MobileApp: Step 2: client release
    MobileApp->>Backend: Send new input
    Backend-->>MobileApp: Execute new path

    Note over Backend,MobileApp: Step 3: strict flip after adoption
    Backend->>Backend: Require new input or remove fallback
    MobileApp->>Backend: Send new input
    Backend-->>MobileApp: Execute strict contract
Loading

File-Level Changes

Change Details Files
Document staged compatibility practices for GraphQL contract changes affecting released mobile clients.
  • Explain backend/mobile deployment asymmetry, including EAS Update limitations.
  • Define rules for required inputs, removals, additive changes, and semantic enforcement changes.
  • Specify the tolerant → client release → strict three-deployment sequence, including adoption gates and DO NOT LAND checklist guidance.
  • Capture representative team-header and task-payload rollout examples.
apps/betterangels-backend/docs/api-compatibility.md
Cross-reference the new rollout guidance from the existing GraphQL error documentation.
  • Add the compatibility guide to the Related files table while preserving graphql_errors.md as the source for denial-response shapes.
apps/betterangels-backend/docs/graphql_errors.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="apps/betterangels-backend/docs/api-compatibility.md" line_range="18" />
<code_context>
+   - Old client → new backend: `Field 'organizationId' of required type 'ID!' was not provided`.
+   - So neither side can ship first alone — a **tolerant middle phase is mandatory** (below).
+2. **Never remove a field, mutation, or fallback** until clients using it are gone. Check usage first: `git grep <symbol> origin/main -- libs/expo`.
+3. **Additive changes are deploy-safe**: new fields, new *optional* inputs/arguments, new queries/mutations, and server-side directive swaps (`@hasPerm` etc. — clients never send directives). No staging needed.
+4. **Semantic tightening needs its data story**: if enforcement starts denying callers who previously succeeded, the conversion (grant/role backfills — e.g. the `post_migrate` grant backfills in `accounts/apps.py`) must be live **before** the enforcement ships.
+
</code_context>
<issue_to_address>
**issue:** The claim that new optional inputs/arguments and new queries/mutations are deploy-safe with no staging is false for clients that start using them before the backend is deployed: an old backend rejects the unknown input field or operation during GraphQL validation, so the mobile request fails.

**Triggers:** When a mobile client release reaches users before the backend containing the new optional input, argument, query, or mutation is live.

**Suggested fix:** Limit the no-staging rule to additive backend output fields, or state that the backend must be deployed before clients begin sending or calling newly added inputs, arguments, queries, or mutations.

```suggestion
3. **Additive backend output fields are deploy-safe**: server-side directive swaps (`@hasPerm` etc. — clients never send directives). For new *optional* inputs/arguments and new queries/mutations, deploy the backend before clients begin sending or calling them; no staging needed.
```
</issue_to_address>

### Comment 2
<location path="apps/betterangels-backend/docs/api-compatibility.md" line_range="40" />
<code_context>
+## Examples
+
+- **Teams — header retirement (DEV-2566).** `TeamFilter.organizationId` already existed and the backend already prefers the filter, falling back to the `X-Organization-ID` header — so the FE change alone was safe to ship **first** (#2458). The header/middleware retirement (#2450) and the interceptor removal (#2452) wait for the FE build's adoption.
+- **Tasks — payload org (RFC 0003 slice 1, DEV-2561).** `createTask` grew `organizationId`. Tolerant backend + mobile wiring (#2457, with `task_create_legacy` preserving the pre-cutover path), strict flip (#2459) gated on the app build being live.
+
+## What non-holders see
</code_context>
<issue_to_address>
**issue:** The worked Tasks example refers to a `task_create_legacy` compatibility path that does not exist anywhere in the repository, so readers cannot locate or verify the purported tolerant backend implementation and may copy an invalid symbol into rollout plans.

**Triggers:** When an engineer follows the Tasks example to inspect the tolerant implementation.

**Suggested fix:** Replace `task_create_legacy` with the actual implementation or link the specific PR/branch where that symbol exists; otherwise describe the legacy path without presenting it as a repository symbol.

```suggestion
- **Tasks — payload org (RFC 0003 slice 1, DEV-2561).** `createTask` grew `organizationId`. Tolerant backend + mobile wiring (#2457, with the legacy behavior preserved for pre-cutover clients), strict flip (#2459) gated on the app build being live.
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨

- Old client → new backend: `Field 'organizationId' of required type 'ID!' was not provided`.
- So neither side can ship first alone — a **tolerant middle phase is mandatory** (below).
2. **Never remove a field, mutation, or fallback** until clients using it are gone. Check usage first: `git grep <symbol> origin/main -- libs/expo`.
3. **Additive changes are deploy-safe**: new fields, new *optional* inputs/arguments, new queries/mutations, and server-side directive swaps (`@hasPerm` etc. — clients never send directives). No staging needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: The claim that new optional inputs/arguments and new queries/mutations are deploy-safe with no staging is false for clients that start using them before the backend is deployed: an old backend rejects the unknown input field or operation during GraphQL validation, so the mobile request fails.

Triggers: When a mobile client release reaches users before the backend containing the new optional input, argument, query, or mutation is live.

Suggested fix: Limit the no-staging rule to additive backend output fields, or state that the backend must be deployed before clients begin sending or calling newly added inputs, arguments, queries, or mutations.

Suggested change
3. **Additive changes are deploy-safe**: new fields, new *optional* inputs/arguments, new queries/mutations, and server-side directive swaps (`@hasPerm` etc. — clients never send directives). No staging needed.
3. **Additive backend output fields are deploy-safe**: server-side directive swaps (`@hasPerm` etc. — clients never send directives). For new *optional* inputs/arguments and new queries/mutations, deploy the backend before clients begin sending or calling them; no staging needed.

## Examples

- **Teams — header retirement (DEV-2566).** `TeamFilter.organizationId` already existed and the backend already prefers the filter, falling back to the `X-Organization-ID` header — so the FE change alone was safe to ship **first** (#2458). The header/middleware retirement (#2450) and the interceptor removal (#2452) wait for the FE build's adoption.
- **Tasks — payload org (RFC 0003 slice 1, DEV-2561).** `createTask` grew `organizationId`. Tolerant backend + mobile wiring (#2457, with `task_create_legacy` preserving the pre-cutover path), strict flip (#2459) gated on the app build being live.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: The worked Tasks example refers to a task_create_legacy compatibility path that does not exist anywhere in the repository, so readers cannot locate or verify the purported tolerant backend implementation and may copy an invalid symbol into rollout plans.

Triggers: When an engineer follows the Tasks example to inspect the tolerant implementation.

Suggested fix: Replace task_create_legacy with the actual implementation or link the specific PR/branch where that symbol exists; otherwise describe the legacy path without presenting it as a repository symbol.

Suggested change
- **Tasks — payload org (RFC 0003 slice 1, DEV-2561).** `createTask` grew `organizationId`. Tolerant backend + mobile wiring (#2457, with `task_create_legacy` preserving the pre-cutover path), strict flip (#2459) gated on the app build being live.
- **Tasks — payload org (RFC 0003 slice 1, DEV-2561).** `createTask` grew `organizationId`. Tolerant backend + mobile wiring (#2457, with the legacy behavior preserved for pre-cutover clients), strict flip (#2459) gated on the app build being live.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants