Fix three fern check errors blocking SDK generation - #651
Conversation
`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>
3assy2018
left a comment
There was a problem hiding this comment.
🔍 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.ymlnow maps bothupdate_article_requestand the newstage_article_draft_request_bodytox-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 readStageArticleDraftRequestBody? A greenfern checkanswers 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 "ThePUT /articles/{id}/draftendpoint ignores this field and always stages a draft" — andscheduled_publish_at/scheduled_unpublish_atexpress their 400 rules in terms ofstate: 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 siblingtitle/descriptionisn'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: trueon a request body means an entirely-null stage-draft call is valid. Plausible if it's faithful toupdate_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>
|
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 2. 3. 4. Top-level On the two you flagged as unverifiable: Worth knowing for the blast-radius note: preview generation can't currently be run at all, by CI or locally. |
3assy2018
left a comment
There was a problem hiding this comment.
🔍 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-namemapping — addressed (stale override removed, verified against a local checkout). - ✅
allOfcomposition question — addressed (tried it; breaksfern checkto 4 errors, 2 touching the stable spec — correctly left out). - ✅
nullable: truefaithfulness — addressed (confirmed identicalproperties, inherited fromupdate_article_request). - ⏳
statefield 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
geetikabagga
left a comment
There was a problem hiding this comment.
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}/draftis calledUpdateArticleRequestBodyacross TS/Java/Python/PHP. - It only passes today because
'/articles/{id}': put: null(lines 23-24, pre-existing and unrelated) prunesupdate_article_requestout of the Preview SDK, leaving one claimant. Remove thatnullsome 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.
Why?
fern checkhas 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