Skip to content

feat(cli): pass OpenRPC paramStructure through IR to FDR - #18469

Open
willkendall01 wants to merge 3 commits into
mainfrom
devin/1792701082-openrpc-param-structure
Open

willkendall01 wants to merge 3 commits into
mainfrom
devin/1792701082-openrpc-param-structure

Conversation

@willkendall01

@willkendall01 willkendall01 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Description

Linear ticket: Refs none

OpenRPC methods with paramStructure: by-name show up in docs with a positional params array, both in Try it and in the snippets. Servers that only accept named params reject that request. The importer ignored paramStructure, and the IR and FDR OpenRPC protocol had nowhere to store it. This PR carries the field through to the FDR register payload. The renderer change is in fern-api/fern-platform#15897.

Changes Made

  • IR 67.36.0 (minor, additive): HttpEndpointSource.openrpc changes from {} to OpenRpcSourceInfo { paramStructure: optional<OpenRpcParamStructure> } (BY_NAME / BY_POSITION / EITHER). Wire format is unchanged when the field is absent. The IR changelog is updated.
  • packages/ir-sdk/src/sdk: generated types updated by hand to match the TS generator's output. pnpm ir:generate couldn't pull fernapi/fern-typescript-sdk:3.69.0 here because Docker Hub returned 429.
  • openrpc-to-ir MethodConverter: maps method.paramStructure into the source and ignores unknown values instead of failing the import. For by-name methods, example request bodies are now objects keyed by param name. Before this they were arrays, which rendered as {"0": ..., "1": ...} once the renderer sent by-name params as an object. Other methods keep array examples.
  • register convertPackage: emits { type: "openrpc", methodName, paramStructure: "by-name" | "by-position" | "either" | undefined }.
  • Unreleased CLI changelog entry (feat).

Until the fdr-sdk catalog pin includes fern-platform#15897, FDR's zod schema strips the new field. So it has no effect until the platform change is deployed, and existing OpenRPC sites stay positional either way.

Testing

  • Unit tests added/updated: new openrpc-param-structure fixture and test in v3-importer-tests. They check the IR source (BY_NAME / BY_POSITION / unset), the example bodies (named object vs array) and the FDR protocol output.
  • @fern-api/register, @fern-api/ir-migrations, @fern-api/v3-importer-tests and openrpc-to-ir tests and compile pass.
  • Manual testing: local docs preview with this CLI plus fern-platform#15897. Try it sent a named params object to Postman Echo, and a method without paramStructure stayed positional. Screenshots are in a comment on fern-platform#15897.

Link to Devin session: https://app.devin.ai/sessions/93b3ae4a969442b29452f9f42d9fe342
Open in Devin Desktop: https://app.devin.ai/desktop/session/93b3ae4a969442b29452f9f42d9fe342?variant=devin
Requested by: @willkendall01


Devin Review

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

Copy link
Copy Markdown
Contributor

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

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

AI Review Summary

Adds OpenRPC paramStructure to the IR (v67.36.0) and threads it through to the FDR register payload, with a new importer fixture/test. The IR definition and hand-written generated SDK changes look consistent; main concerns are the missing IR migration for older IR versions and a changelog date that's in the future.

  • 🟡 1 warning(s)
  • 🔵 2 suggestion(s)

Review Scope

  • Mode: Full pull request
  • Range: Full pull request through e61cd9a89a8327566a13868e3f32d34c673eb14f
  • Current range coverage: Complete
  • Cumulative pull request coverage: Complete

This review is complete for the current scope. Addressing all critical and warning findings above satisfies the review; suggestions are optional. Request another review only if subsequent changes introduce new behavior or materially expand the pull request's scope.

proto: ProtoSourceInfo
openapi: {}
openrpc: {}
openrpc: OpenRpcSourceInfo

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.

🟡 warning

Changing openrpc: {} to openrpc: OpenRpcSourceInfo makes the union variant carry a payload. Older IR versions' schemas still expect {}, so unless packages/ir-migrations has a migration (or the existing identity migrations drop unknown fields safely), generators pinned to IR ≤67.35 could receive the extra paramStructure key. Worth confirming an ir-migrations entry was added for 67.36.0 — the PR description mentions the migrations package only as "tests pass".

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.

No migration is needed. This is a minor, additive IR bump (67.35 → 67.36), and per CLAUDE.md / packages/ir-sdk/CLAUDE.md migrations are only required for major bumps. Older IR 67.x consumers get an extra optional key on source.openrpc, and generators parse IR with unrecognizedObjectKeys: "passthrough" (generators/base/src/AbstractGeneratorCli.ts, utils/parseIR.ts), so it's ignored. v67-to-v66 also serializes with passthrough. The ir-migrations tests pass on this branch.

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.36.0] - 2026-10-22

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.

🔵 suggestion

2026-10-22 is a year ahead of the preceding entry's convention (and presumably today). Looks like a typo — the previous entry is v67.35.0 - 2026-10-21, so it may be consistent, but double-check the year before merging.

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.

The date is correct. Today is 2026-10-22, and the entry follows v67.35.0 - 2026-10-21.

const endpoints = endpointsByName(ir);
expect(endpoints["plants.water"]?.source).toMatchObject({ type: "openrpc", paramStructure: "BY_NAME" });
expect(endpoints["plants.prune"]?.source).toMatchObject({ type: "openrpc", paramStructure: "BY_POSITION" });
expect(endpoints["plants.list"]?.source).toMatchObject({ type: "openrpc", paramStructure: undefined });

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.

🔵 suggestion

toMatchObject({ ..., paramStructure: undefined }) passes even if paramStructure is a non-undefined value in some Vitest versions? No — it does assert undefined, but it also passes when the key is absent. That's fine here; however consider toEqual for the whole source object so a regression that adds a stray field is caught. Optional.

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.

I'm leaving this as is. The FDR protocol assertions further down already use toEqual on the full object, so a stray field would show up there. The IR check only cares about paramStructure, and the v3-sdks/baseline-sdks snapshots for this fixture cover the full source shape.

@devin-ai-integration devin-ai-integration 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.

✅ Devin resolved the finding on e61cd9a

Fixed by Devin (1)

  • Invalid parameter structure aborts OpenRPC import

View all findings in Devin Review

Devin Review

willkendall01 and others added 2 commits October 22, 2026 20:44
…ling import

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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-10-22T04:06:10Z).

Fixture main PR Delta
docs 155.4s (n=5) 170.2s (35 versions) +14.8s (+9.5%)

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-10-22T04:06:10Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-10-22 21:29 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-10-22T04:06:10Z).

Full benchmark table (click to expand)
Generator Spec main (generator) main (E2E) PR (generator) Delta
csharp-sdk square 73s (n=5) 110s (n=5) 56s -17s (-23.3%)
go-sdk square 124s (n=5) 227s (n=5) 133s +9s (+7.3%)
java-sdk square 173s (n=5) 305s (n=5) 241s +68s (+39.3%)
php-sdk square 57s (n=5) N/A 40s -17s (-29.8%)
python-sdk square 115s (n=5) 179s (n=5) 132s +17s (+14.8%)
ruby-sdk-v2 square 76s (n=5) 109s (n=5) 77s +1s (+1.3%)
rust-sdk square 174s (n=5) 193s (n=5) 212s +38s (+21.8%)
swift-sdk square 59s (n=5) 292s (n=5) 42s -17s (-28.8%)
ts-sdk square 137s (n=5) 143s (n=5) 125s -12s (-8.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-10-22T04:06:10Z). Trigger benchmark-baseline to refresh.
Last updated: 2026-10-22 21:32 UTC

This branch has not been deployed

No deployments
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.

1 participant