Skip to content

Commit 559b17d

Browse files
committed
docs: add adoption strategy, ecosystem workstreams, spec producer issue template
- Add adoption strategy section to README outlining priority order - Add ecosystem workstreams table to state-of-the-union.md covering SDK generators, parsers, validators, spec producers, and doc renderers - Update recommendation section with spec producer guidance - Clarify AJV nested-workspace-resources behavior description - Add GitHub issue template for spec producer tracking - Minor .gitignore whitespace fix
1 parent 42ff887 commit 559b17d

5 files changed

Lines changed: 72 additions & 6 deletions

File tree

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
name: Spec producer tracking
3+
about: Track a tool that emits OpenAPI specs from source code
4+
title: "Track spec producer: <tool>"
5+
labels: ["area:producer"]
6+
assignees: ""
7+
---
8+
9+
## Tool
10+
11+
- Name:
12+
- Repository:
13+
- Language/runtime:
14+
- Upstream issue:
15+
- Upstream PR:
16+
17+
## Current Behavior
18+
19+
- Emits `$dynamicRef` / `$dynamicAnchor`: yes/no/partial
20+
- Emits by default:
21+
- Has opt-in flag:
22+
- Has duplicated-schema fallback:
23+
- OpenAPI versions supported:
24+
25+
## Desired Behavior
26+
27+
- [ ] Keeps duplicated schema output as the default while downstream support is incomplete
28+
- [ ] Adds explicit opt-in `$dynamicRef` emission
29+
- [ ] Documents downstream SDK generator compatibility caveats
30+
- [ ] Can emit generic pagination or envelope patterns where applicable
31+
- [ ] Can emit recursive dynamic reference patterns where applicable
32+
33+
## Evidence
34+
35+
Paste generated OpenAPI excerpts or links to relevant docs/issues.
36+
37+
## Next Action
38+
39+
Open upstream issue, prepare PR, wait on SDK generator support, or verify generated output against this repo's fixtures.

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ node_modules/
44
openapitools.json
55
generated/
66
logs/
7-
all-results/
8-
7+
all-results/
8+
99
# Covers JetBrains IDEs: IntelliJ, GoLand, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
1010
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
1111

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ OpenAPI 3.1.x allows JSON Schema 2020-12 schema objects, and OpenAPI 3.2 explici
1010

1111
Generator and typecheck failures in this repo are **report-only** because those failures are the compatibility data. Fixture validity and generated spec freshness are the CI gates.
1212

13+
## Adoption Strategy
14+
15+
This project currently tests SDK generators and type emitters, but `$dynamicRef` adoption requires work across the OpenAPI ecosystem: SDK generators, parsers/bundlers, runtime validators, spec producers, and documentation renderers.
16+
17+
SDK generators are the first priority because they are where users see broken output directly. Spec producers such as `@nx/swagger` should start adding `$dynamicRef` emission support, but behind explicit opt-in flags until downstream SDK generator support is reliable.
18+
19+
See [State of the Union](state-of-the-union.md) for the detailed strategy.
20+
1321
## Quickstart
1422

1523
Install pinned local dependencies:

fixtures/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,13 +96,13 @@ Validators: AJV 2020 and Hyperjump 2020-12.
9696
| `paginated-response.yaml` | Valid user/group pages fail; invalid item cases fail | Valid user/group pages pass; invalid item cases fail | Valid user/group pages pass; invalid item cases fail | AJV PR #2615 fixes this |
9797
| `api-envelope.yaml` | Valid wrapped-user page fails; invalid item cases fail | Not tested | Not tested | Expected same gap as pagination fixtures; AJV PR #2615 should fix this |
9898
| `recursive-category-tree.yaml` | Valid localized category tree passes; child missing localized fields fails | Pass | Not tested | Runtime check passes |
99-
| `nested-workspace-resources.yaml` | Valid nested workspace passes; AJV accepts invalid nested folder data (missing `permissions` field) | Fails: "resolves to more than one schema" for multiple same-name `$dynamicAnchor` in the same document (`FolderTemplate.$defs.folderType` and `WorkspaceFolder.$defs.folderType` share an anchor name) — this is an AJV limitation, not a fixture bug | Not tested | AJV does not correctly resolve the multi-parameter generic template pattern; the fixture is semantically sound |
99+
| `nested-workspace-resources.yaml` | Valid nested workspace passes; invalid nested folder missing permissions is accepted as a known gap because AJV resolves the generic `$dynamicRef` slot to the `not: {}` fallback | Fails: "resolves to more than one schema" for same-name `$dynamicAnchor`s in the generic binding path — this is an AJV limitation, not a fixture bug | Not tested | AJV does not correctly resolve the multi-parameter generic template pattern; the fixture is semantically sound |
100100
| `non-identifier-schema-key.yaml` | Valid localized category tree passes; child missing localized fields fails | Not tested | Valid localized category tree passes; child missing localized fields fails | Runtime check passes; generator matrix tests identifier normalization |
101101
| `spec-semantics/ambiguous-sibling-anchors.yaml` | Not tested | Not tested | Not tested | OpenAPI-valid research fixture for static-scan limitations |
102102
| `spec-semantics/dynamicref-core-semantics.yaml` | `$ref` to `$dynamicAnchor` passes; several `$dynamicRef` core cases are known gaps, including non-fragment URI refs | Not tested | Core cases, non-fragment URI refs, allOf order, and multi-parameter generic cases pass | Semantics fixture tier; AJV gaps are documented by case output |
103103
| `spec-semantics/external-dynamic-ref.yaml` | Not tested | Not tested | Valid external node passes; invalid external node fails | External resource semantics fixture for parser/bundler research |
104104

105-
AJV PR [#2615](https://github.com/ajv-validator/ajv/pull/2615) fixes the generic pagination dynamic binding pattern. The nested workspace fixture exposes a separate AJV limitation: multiple schemas declaring the same `$dynamicAnchor` name in a single document causes an ambiguous reference error. This is a limitation of AJV PR #2615, not a bug in the fixture — `nested-workspace-resources.yaml` is semantically correct (both anchor declarations are scoped to different schemas in the `allOf` chain).
105+
AJV PR [#2615](https://github.com/ajv-validator/ajv/pull/2615) fixes the generic pagination dynamic binding pattern. The nested workspace fixture exposes a separate AJV limitation around same-name `$dynamicAnchor`s in a multi-parameter generic binding path. This is a limitation of AJV PR #2615, not a bug in the fixture — `nested-workspace-resources.yaml` is semantically correct because the declarations are scoped by the dynamic evaluation path.
106106

107107
## Fixture To Spec Path
108108

state-of-the-union.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ JSON Schema runtime validation:
5050
| Paginated response (inline) | Fails valid user/group pages | Passes valid/invalid user and group pages | Passes valid/invalid user and group pages | AJV PR #2615 fixes this |
5151
| API envelope | Not yet tested | Not yet tested | Not yet tested | Expected same gap as pagination fixtures |
5252
| Recursive category tree | Pass | Pass | Not tested | Pass |
53-
| Nested workspace resources | PASS (valid workspace); FAIL (invalid nested folder — AJV does not enforce constraints through `$dynamicRef` generic template binding, same gap as pagination fixtures) | Fails: "resolves to more than one schema" — AJV limitation when multiple schemas share a `$dynamicAnchor` name in the same document; fixture is semantically correct | Not tested | AJV does not resolve `$dynamicRef` generics pattern; fallback `not: {}` accepts invalid data |
53+
| Nested workspace resources | Valid workspace passes; invalid nested folder is accepted as a known gap because AJV resolves the generic `$dynamicRef` slot to the `not: {}` fallback | Fails: "resolves to more than one schema" — AJV limitation when same-name `$dynamicAnchor`s appear in the generic binding path; fixture is semantically correct | Not tested | AJV does not resolve the multi-parameter `$dynamicRef` generic template pattern |
5454
| Non-identifier schema key | Pass | Not tested | Pass | Pass |
5555
| Spec semantics fixtures | Mixed known gaps | Not tested | Pass where runtime assertions exist | Research tier; see `fixtures/README.md` |
5656

@@ -80,10 +80,26 @@ PaginatedUserResponse:
8080
8181
Hyperjump evaluates this as intended: user pages require `User[]`, group pages require `Group[]`, and invalid item shapes fail. AJV PR [#2615](https://github.com/ajv-validator/ajv/pull/2615) also now evaluates this correctly — valid user/group pages pass and invalid item shapes fail. This PR has not yet been merged.
8282

83-
The nested workspace fixture was restructured from sibling `$dynamicAnchor` declarations to a multi-parameter generic template pattern (`FolderTemplate` with `folderType` and `resourceType` slots). AJV now parses and partially validates the fixture but does not correctly enforce constraints through `$dynamicRef` generic template binding — the same gap that affects the pagination fixtures. The previous "ambiguous reference" error for same-name `$dynamicAnchor` declarations no longer applies to this fixture.
83+
The nested workspace fixture was restructured from sibling `$dynamicAnchor` declarations to a multi-parameter generic template pattern (`FolderTemplate` with `folderType` and `resourceType` slots). AJV now parses and partially validates the fixture but does not correctly enforce constraints through `$dynamicRef` generic template binding — the same gap that affects the pagination fixtures. AJV PR #2615 still exposes a separate same-name `$dynamicAnchor` limitation in this generic binding path; the fixture remains semantically correct.
8484

8585
This means the claim that `$dynamicRef` can model generic wrappers is supported by the OAI discussion and by Hyperjump, but tool support is mixed. Upstream generator issues should include the validator matrix rather than relying on one validator.
8686

87+
## Ecosystem Workstreams
88+
89+
`$dynamicRef` adoption depends on several OpenAPI tool categories, not just SDK generators.
90+
91+
| Category | Role | Examples | Recommended work |
92+
|---|---|---|---|
93+
| SDK generators / type emitters | Generate application-facing clients and types | OpenAPI Generator, Orval, openapi-typescript, @hey-api/openapi-ts, Kiota, NSwag | Highest priority: preserve dynamic scope and emit reusable parameterized types where supported |
94+
| Parsers / resolvers / bundlers | Resolve refs and prepare specs for consumers | Redocly bundle, swagger-cli bundle, parser libraries | Preserve `$dynamicRef` / `$dynamicAnchor` without changing dynamic scope |
95+
| Runtime validators | Validate data against schemas | AJV, Hyperjump | Close validator gaps and document disagreements |
96+
| Spec producers | Generate OpenAPI specs from source code | `@nx/swagger`, `@nestjs/swagger`, tsoa, FastAPI, springdoc-openapi, poem-openapi, swaggo/swag | Add opt-in `$dynamicRef` emission while keeping duplicated-schema output as the default |
97+
| Documentation renderers | Render OpenAPI docs | Swagger UI, Redoc, Stoplight Elements | Render valid specs containing `$dynamicRef` without crashing or hiding schemas |
98+
99+
SDK generators and type emitters are the first practical priority because broken generated types immediately affect application developers. A spec producer that emits `$dynamicRef` before downstream tools preserve the semantics can cause generation failures or degraded output such as `unknown`, `any`, `Object`, or duplicate non-generic wrappers.
100+
101+
Spec producers should still start implementing support now, but they should expose it as an explicit opt-in. Default output should remain compatibility-safe duplicated schemas until major SDK generators and parser/bundler stacks reliably preserve dynamic reference semantics.
102+
87103
## TypeScript SDK Matrix Snapshot (Initial 3-Generator Run)
88104

89105
This section is a compatibility snapshot from the initial focused run against Orval, OpenAPI Generator, and Swagger Codegen v3. The live CI matrix now covers additional TypeScript-oriented tools; use GitHub Actions artifacts and tracking issues for current per-tool status.
@@ -136,9 +152,12 @@ Orval PR [#3353](https://github.com/orval-labs/orval/pull/3353) adds opt-in dyna
136152
## Recommendation
137153

138154
- Use duplicated concrete wrappers or a hybrid compatibility strategy for production SDK pipelines today.
155+
- Prioritize SDK generators and type emitters first; they are the practical bottleneck for application adoption.
139156
- Use validator-backed recursive and complex nested fixtures for upstream `$dynamicRef` parser/codegen work.
140157
- Use the pagination/generic-wrapper fixture with the documented validator caveat: Hyperjump validates it; AJV currently does not.
141158
- **Generic fixtures must produce parameterized types (generics) when the target language supports them.** Concrete materialization of generic wrappers — duplicating the template structure for each item type — does not pass validation. The purpose of `$dynamicRef` for generics is type reuse; producing duplicates defeats that purpose. For languages without generics, concrete wrappers are acceptable as a documented fallback.
159+
- Spec producers such as `@nx/swagger` should add `$dynamicRef` emission behind explicit opt-in flags, not as default output, until downstream SDK generator support is reliable.
160+
- Track spec producer work separately from SDK generator work; this repo does not need producer CI automation yet.
142161
- Treat OAS `3.2.0` as experimental for generator compatibility until parser support improves.
143162
- OpenAPI Generator has the most severe gap: it cannot parse specs containing `$dynamicAnchor` at all. Start upstream work there.
144163

0 commit comments

Comments
 (0)