Skip to content

feat(cli): thread idempotency-key generation into the IR#17018

Merged
cadesark merged 5 commits into
mainfrom
devin/1783707282-ir-idempotency-cli
Jul 10, 2026
Merged

feat(cli): thread idempotency-key generation into the IR#17018
cadesark merged 5 commits into
mainfrom
devin/1783707282-ir-idempotency-cli

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Description

Promotes idempotency-key auto-generation from a per-generator config flag to a single canonical IR field, so every generator reads one source of truth instead of each defining/reinterpreting its own config key (autoGenerateIdempotencyKey vs auto_generate_idempotency_key vs kebab-case) and re-deriving its own POST/PUT method-gating.

This PR is IR + CLI only — it adds the field and the CLI plumbing that populates it. Generators consume the published @fern-fern/ir-sdk, so the follow-up generator PRs (which read sdkConfig.idempotencyKeyGeneration) land after this merges and the new IR (67.11.0) is published. The field is optional/additive → minor IR bump; no migration needed (the existing v67→v66 passthrough migration drops it naturally for older generators).

Changes Made

  • IR schema (ir-types-latest/definition/ir.yml): add SdkConfig.idempotencyKeyGeneration: optional<IdempotencyKeyGeneration>; new IdempotencyKeyGeneration { headerName: string; methods: list<HttpMethod> }. methods centralizes the eligible-method set (defaults to [POST, PUT]) so gating is identical across generators rather than hard-coded per language. Presence of the optional block encodes "enabled" (absent = disabled, the default). Regenerated TS types via pnpm ir:generate.
  • IR versioning: VERSION 67.10.2 → 67.11.0; hand-edited IR CHANGELOG.md entry.
  • CLI threading: new getIdempotencyKeyGenerationFromGeneratorConfig() in api-workspace-commons resolves the auto-generate-idempotency-key generator config (accepts true, or { header-name, methods }; defaults header Idempotency-Key, methods [POST, PUT]), modeled on the existing user-agent precedent. Added to CLI_ONLY_CONFIG_KEYS so it's stripped from the config forwarded to generators. Wired into all IR-construction call sites (generateIntermediateRepresentation, local + remote runners, GenerationRunner).
  • Construction-site fixups: AbstractSpecConverter and the ir-utils merge test set the new (optional) field.
  • CLI changelog: packages/cli/cli/changes/unreleased/add-idempotency-key-generation-ir.yml (feat).

Testing

  • pnpm turbo run compile green across affected packages (ir-generator, api-workspace-commons, local/remote runners, ir-utils, v3-importer-commons).
  • pnpm turbo run test green for @fern-api/ir-utils, @fern-api/ir-migrations, and @fern-api/register — updated additive snapshots only (idempotencyKeyGeneration passes through as null/undefined).
  • Generator behavior lands in follow-up PRs after IR publish.

Link to Devin session: https://app.devin.ai/sessions/c3ddfc2bb3b04f9a9e2977e756158dee
Requested by: @cadesark


Open in Devin Review

…otencyKeyGeneration)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

@nitpickybot nitpickybot Bot 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.

AI Review Summary

Clean additive IR change threading idempotency-key generation from generator config into the IR. The plumbing is consistent with the existing user-agent precedent. One correctness concern: an empty-string custom header-name falls through to a valid string and would silently produce an empty header, and the changelog date is in the future (2026).

  • 🔵 2 suggestion(s)

}
if (typeof value === "object" && value !== null) {
const headerName = (value as { "header-name"?: unknown })["header-name"];
return { headerName: typeof headerName === "string" ? headerName : DEFAULT_IDEMPOTENCY_KEY_HEADER };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 suggestion

An empty-string header-name passes the typeof === "string" check and produces { headerName: "" }, yielding an empty wire header downstream. Consider treating blank strings as "use default":

Suggested change
return { headerName: typeof headerName === "string" ? headerName : DEFAULT_IDEMPOTENCY_KEY_HEADER };
return { headerName: typeof headerName === "string" && headerName.trim() !== "" ? headerName : DEFAULT_IDEMPOTENCY_KEY_HEADER };

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [v67.11.0] - 2026-07-08

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 suggestion

Date is 2026-07-08 (and the entry below is 2026-07-07). Either the whole changelog is time-traveling or this is a typo — worth confirming it matches the surrounding convention before merge.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@cadesark cadesark self-assigned this Jul 10, 2026
cade and others added 2 commits July 10, 2026 18:59
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ion field

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@github-actions

Copy link
Copy Markdown
Contributor

Docs Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-07-10T05:18:08Z).

Fixture main PR Delta
docs 241.5s (n=5) 231.3s (35 versions) -10.2s (-4.2%)

Docs generation runs fern generate --docs --preview end-to-end against the benchmark fixture with 35 API versions (each version: markdown processing + OpenAPI-to-IR + FDR upload).
Delta is computed against the nightly baseline on main.
Baseline from nightly run(s) on main (latest: 2026-07-10T05:18:08Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-07-10 19:44 UTC

@github-actions

Copy link
Copy Markdown
Contributor

SDK Generation Benchmark Results

Comparing PR branch against median of 5 nightly run(s) on main (latest: 2026-07-10T05:18:08Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
csharp-sdk square 72s (n=5) 113s (n=5) 66s -6s (-8.3%)
go-sdk square 135s (n=5) 285s (n=5) 131s -4s (-3.0%)
java-sdk square 218s (n=5) 272s (n=5) 188s -30s (-13.8%)
php-sdk square 62s (n=5) 84s (n=5) 59s -3s (-4.8%)
python-sdk square 146s (n=5) 237s (n=5) 129s -17s (-11.6%)
ruby-sdk-v2 square 92s (n=5) 124s (n=5) 88s -4s (-4.3%)
rust-sdk square 175s (n=5) 165s (n=5) 207s +32s (+18.3%)
swift-sdk square 61s (n=5) 437s (n=5) 50s -11s (-18.0%)
ts-sdk square 127s (n=5) 128s (n=5) 128s +1s (+0.8%)

main (generator): generator-only time via --skip-scripts (includes Docker image build, container startup, IR parsing, and code generation — this is the same Docker-based flow customers use via fern generate). main (E2E): full customer-observable time including build/test scripts (nightly baseline, informational). Delta is computed against generator-only baseline.
⚠️ = generation exited with a non-zero exit code (timing may not reflect a successful run).
Baseline from nightly runs on main (latest: 2026-07-10T05:18:08Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-07-10 19:45 UTC

@cadesark cadesark merged commit 25b3810 into main Jul 10, 2026
219 checks passed
@cadesark cadesark deleted the devin/1783707282-ir-idempotency-cli branch July 10, 2026 19:57
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