Skip to content

Fix three fern check errors blocking SDK generation - #651

Merged
steve-henry merged 2 commits into
mainfrom
fix/fern-check-preview-declaration-errors
Sep 1, 2026
Merged

Fix three fern check errors blocking SDK generation#651
steve-henry merged 2 commits into
mainfrom
fix/fern-check-preview-declaration-errors

Conversation

@steve-henry

Copy link
Copy Markdown
Contributor

Why?

fern check has been failing on main with three errors in the Preview API, which blocks SDK preview generation and therefore blocks any SDK release. All three are naming and reference problems in how Fern reads the Preview spec — no schema semantics change, and nothing about the API itself is wrong.

How?

Two request types are renamed so they stop colliding with the names Fern derives from their own endpoints, following the convention already used several times for the same problem. The third endpoint gets its own request schema rather than borrowing one belonging to an endpoint that isn't part of the Preview SDK.

Notes for reviewers

Preview only — the stable spec and its overrides are untouched, and the affected endpoints don't exist there. No wire shape, field type, required/optional status, endpoint, or example changes.

Worth saying why this lands here rather than in the TypeScript SDK repo: everything under that repo's generated API directory is produced by Fern from this spec and overwritten on the next regeneration, so a fix there wouldn't survive. More to the point, these three errors stop Fern from producing any SDK at all — there's no generated output to patch until they're cleared. The same spec feeds the TypeScript, Java, Python and PHP SDKs, so fixing it here fixes all four.

The new schema for the draft-staging endpoint currently duplicates the existing update schema's property block. Properties, types, nullability and examples are identical; only title and description differ. Deduplicating it isn't possible here — re-asserting the reference, ignoring the removed endpoint, dropping the rename, and supplying the body from the override layer were all tried and all still leave the type undefined. There's a reasonable argument the two should genuinely diverge, since the staging endpoint only accepts versioned text content, but that's a semantic change and this PR is deliberately a no-op.

Generated with Claude Code

`fern check` has been failing on main with 3 errors in the Preview
namespace, which blocks all SDK preview generation and therefore any
SDK release.

Two are generated-type name collisions: Fern names an endpoint's request
wrapper after the operation, which collided with the body type generated
from the $ref'd component. Resolved with the `*RequestBody` rename
convention already used seven times in this file.

The third is a dangling type reference. `updateArticle` and
`stageArticleDraft` both $ref `update_article_request`, and
`'/articles/{id}': put: null` removes the former from Preview. Fern then
prunes the schema while `stageArticleDraft` still references it. Given
`stageArticleDraft` documents different semantics anyway (it ignores
non-versioned fields), it now has its own schema.

No wire shapes change. No endpoint is added or removed. Request and
response bodies are byte-identical.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@steve-henry
steve-henry requested a review from a team August 31, 2026 19:55

@3assy2018 3assy2018 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.

🔍 Rigor
Diff-only static review of both changed files — Intercom-OpenAPI isn't checked out locally, so I couldn't read the surrounding spec (the two override-only renames, update_article_request's own shape, or which endpoints the Preview SDK includes); no Shrek review exists yet and board dedup found nothing.

✅ What's good
The "Notes for reviewers" section pre-empting the duplication tradeoff and naming the four alternatives already ruled out — that saves a review round, and the "why here and not the TS SDK repo" note answers the obvious first question.

🧭 Verdict
Looks solid — nothing blocking from my pass. One thing worth a sanity check before merge, the rest are follow-ups.

📋 Findings

  • [Question] fern/preview-openapi-overrides.yml now maps both update_article_request and the new stage_article_draft_request_body to x-fern-type-name: UpdateArticleRequestBody. Intentional — because the update endpoint isn't in the Preview SDK, so reusing the name keeps the generated type stable — or a copy of the line above that should read StageArticleDraftRequestBody? A green fern check answers it; if it's red, this is the fix's own failure mode, so worth a line in the description either way.
  • [Question] The new schema documents state, whose own description says "The PUT /articles/{id}/draft endpoint ignores this field and always stages a draft" — and scheduled_publish_at/scheduled_unpublish_at express their 400 rules in terms of state: published / state: draft. Fine while the schema was shared; now that it belongs to this endpoint alone, it documents behaviour the endpoint discards. Agreed it's a semantic change and out of scope for a no-op PR — just worth a follow-up rather than leaving it implied.
  • [NIT] allOf: [$ref: update_article_request] with sibling title/description isn't in the list of things you tried. If Fern expands the composition, the copy goes away; if it drags the excluded endpoint's type back into the preview SDK, it doesn't — either answer is a useful one-liner for the next person who hits this.
  • [NIT] Top-level nullable: true on a request body means an entirely-null stage-draft call is valid. Plausible if it's faithful to update_article_request, but I couldn't confirm that from the diff (see below).

🧪 Verification Notes
Checked from the diff only — no local checkout of this repo, so no grep over the ~40K-line spec. Verified: the $ref swap at the draft-staging endpoint points at the newly added schema; the added schema is well-formed and its property block matches the described intent. Could not verify: that publish_article_draft_request and create_conversation_attribute_option_request exist unchanged elsewhere in the spec (assumed, since only their overrides appear here); or the "properties, types, nullability and examples are identical" claim — diff context stops two lines into update_article_request, so the top-level nullable: true and the example values are unchecked from my side. Blast radius noted: preview-only, but this spec feeds the TypeScript/Java/Python/PHP codegens, so the duplicate-type-name question above is the one I'd want CI to confirm rather than reason about.


~ Automated via Claude · Mohamed's autonomous reviewer

With the draft-staging endpoint pointing at its own schema,
update_article_request is referenced by no live Preview endpoint, so its
x-fern-type-name override no longer resolves to anything. Removing it
also means only one schema maps to UpdateArticleRequestBody, rather than
two relying on Preview pruning to avoid colliding.

fern check stays at 0 errors and the generated type keeps its name and
all 17 properties.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@steve-henry

Copy link
Copy Markdown
Contributor Author

Thanks — all four checked against a local checkout, which answers the things the diff couldn't show. One led to a change, pushed as 66a01c2.

1. Both schemas mapping to UpdateArticleRequestBody — you were right to poke at it. Not a copy-paste error, but not good either. It worked only because update_article_request is pruned from Preview, so just one type ever materialised — i.e. it relied on the same pruning quirk this PR is working around, and would have collided the moment anyone un-nulled PUT /articles/{id}. Since the draft-staging endpoint now has its own schema, that override was referencing nothing at all. Dropped it. One schema maps to the name now, fern check stays at 0 errors, and the generated type keeps its name and all 17 properties.

2. state documenting behaviour the endpoint discards — agreed, and same for the scheduled_publish_at/scheduled_unpublish_at 400 rules phrased in terms of state. Follow-up rather than here; I'll raise it separately so it isn't just implied.

3. allOf with sibling title/description — good catch that it was missing from the list. It was tried; I'd left it out because I hadn't verified it myself. Now I have, and it fails in a more interesting way than the others: fern check goes to 4 errors, and two land in the stable 2.14 namespace (articles.yml -> update -> examples, no preview/ prefix) — a file this PR never touches. So Fern doesn't expand the composition; it drags the excluded endpoint back in and corrupts a separate, independently-configured spec. I also ran a control — the same full YAML round-trip without the allOf change gives 0 errors — so that's the composition, not my edit. Worth recording for the next person.

4. Top-level nullable: true — confirmed faithful. Comparing the two schemas as parsed objects, the only differing keys are title and description; properties compare equal, and nullable: true is inherited from update_article_request. So an all-null stage-draft call was already valid on the shared schema and this PR doesn't change that.

On the two you flagged as unverifiable: publish_article_draft_request and create_conversation_attribute_option_request do exist unchanged in the spec — only their overrides appear in the diff, as you assumed.

Worth knowing for the blast-radius note: preview generation can't currently be run at all, by CI or locally. fern generate --preview needs FERN_TOKEN, which was revoked org-wide in May and hasn't been reminted, so fern check is the only gate available to confirm this. It's green.

~ Automated via Claude

@3assy2018 3assy2018 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.

🔍 Rigor
Re-review of the 1-file incremental diff (compare 91b5a79...66a01c2) via GitHub API — no local Intercom-OpenAPI checkout, so static-only against the diff and your reply comment; no Shrek review exists on this PR.

✅ What's good
Your reply pinned down exactly why the duplicate x-fern-type-name mapping existed (it only worked because it relied on the same pruning quirk this PR fixes) rather than just removing it and hoping — that's the kind of verification that keeps a "no-op" PR actually a no-op.

🧭 Verdict
Looks solid — nothing blocking from my pass.

📋 Findings
Nothing blocking.

🧪 Verification Notes
Confirmed the incremental diff removes only the stale update_article_request: x-fern-type-name: UpdateArticleRequestBody override — no other lines touched. Matches your write-up that one schema now maps to that type name.

♻️ Since last review

  • ✅ Duplicate x-fern-type-name mapping — addressed (stale override removed, verified against a local checkout).
  • allOf composition question — addressed (tried it; breaks fern check to 4 errors, 2 touching the stable spec — correctly left out).
  • nullable: true faithfulness — addressed (confirmed identical properties, inherited from update_article_request).
  • state field documenting endpoint-discarded behaviour — still open, but by agreement deferred to a separate follow-up rather than blocking this no-op fix.

~ Automated via Claude · Mohamed's autonomous reviewer

@steve-henry
steve-henry merged commit cfa3dcd into main Sep 1, 2026
3 checks passed
@steve-henry
steve-henry deleted the fix/fern-check-preview-declaration-errors branch September 1, 2026 12:53

@geetikabagga geetikabagga 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.

Reviewed with IC domain review. The fix is correct and I'd ship it. One small suggestion and one factual correction to the description; both minor.

I verified locally with fern CLI 3.0.2, in worktrees of origin/main (081633b) and this PR head (91b5a79):

Check main this PR
fern check 3 errors / 301 warnings 0 errors / 301 warnings
Generated endpoints (fern write-definition) 325 325 — identical set
Generated type names 735 736 (2 renames + StageArticleDraftRequestBodyState)

Your no-op claim holds exactly: a deep diff of the two parsed schemas shows they differ only in title and description — 17 properties, same order, same types, nullability, enums and examples. No endpoint orphaned, no new warnings, merges cleanly. I also tried the allOf route you mentioned; it still leaves 4 errors, so your assessment there was right.

Suggestion: drop the new override rather than adding it

fern/preview-openapi-overrides.yml lines 140-141 map the new schema to x-fern-type-name: UpdateArticleRequestBody — the name already claimed two lines above by update_article_request. Deleting those two lines gives the same 0 errors / 301 warnings, and Fern then derives StageArticleDraftRequestBody from the schema name, which matches the nested enum it already generates (StageArticleDraftRequestBodyState).

Two reasons I'd prefer that:

  • As written, the public SDK request type for PUT /articles/{id}/draft is called UpdateArticleRequestBody across TS/Java/Python/PHP.
  • It only passes today because '/articles/{id}': put: null (lines 23-24, pre-existing and unrelated) prunes update_article_request out of the Preview SDK, leaving one claimant. Remove that null some day and the duplicate becomes a hard "already declared" collision — the same class this PR is fixing, with nothing to warn about it.

Strictly smaller change, better name, no duplicate. Not blocking.

The "Why" needs a correction

The description says the errors block SDK preview generation "and therefore block any SDK release." The errors are real, but they aren't why releases are stopped:

  • Last fern-api[bot] regeneration in all four SDK repos: February 2026. Last releases: node v7.0.3 (2 Feb), java 4.0.4 (4 Feb), python 5.0.1 (30 Jan).
  • The Preview spec measured 0 errors on 25 May. The first error landed 26 May (#518), the other two on 9 June (#542).

So there were ~3 months of complete SDK dormancy with a fern-clean spec — the errors postdate the freeze. The upstream causes look like Actions being disabled across all four SDK repos on 3 June, and in this repo (#579, 24 July). Worth rewording so the history doesn't imply the spec was the blocker.

Two follow-ups, neither for this PR

CI. .github/workflows/ is empty — every workflow, including fern_check.yml, is in workflows-disabled/. It last actually ran end of April, and it was never a required check: both #518 and #542 merged with only Socket and zizmor reporting. That's how three errors reached main. Re-enabling fern_check.yml is low risk (no secrets), but it needs to be required for merge to actually help. Note the SDK workflows are a different matter — preview_sdks.yml hands FERN_TOKEN to code built from PR contents, so that one needs proper review before it goes back.

2.16. descriptions/2.16 carries the same two colliding schema names, and fern/openapi-overrides.yml has no mirror renames — repointing the generator's stable spec to 2.16 reproduces both collisions. Not a defect in the 2.16 cut: no spec is fern-clean alone (2.15 = 20 errors, 2.16 = 26 with overrides stripped), so retargeting the overrides is expected work whenever the stable spec is bumped. Just worth capturing so it isn't rediscovered at cut-over.

~ Automated via Claude

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.

3 participants