Skip to content

feat(compilers/openapi): fill typed fields from vendor extensions - #355

Open
OmarAlJarrah wants to merge 1 commit into
mainfrom
feat/openapi-extension-sourced-fields
Open

feat(compilers/openapi): fill typed fields from vendor extensions#355
OmarAlJarrah wants to merge 1 commit into
mainfrom
feat/openapi-extension-sourced-fields

Conversation

@OmarAlJarrah

Copy link
Copy Markdown
Member

Summary

Several typed IR fields model information OpenAPI gives no keyword for, so the only way a document
can state it is a vendor extension — and nothing connected the two. x-deprecated-reason landed in
Unmodeled and ir.Deprecation.Message stayed empty at every one of the seven places the compiler
builds a Deprecation, with no diagnostic either way. Any emitter wanting the value had to reach
into Unmodeled with an ad-hoc x-* lookup, which is exactly what an emitter must not do.

The deliverable is the mechanism, not the two keys that demonstrate it.

The rule, recorded first. docs/ir-design.md §12 now states what promoting a vendor extension
into a typed field means: the mapping is injectable policy, default on and disableable; the
extension stays in Unmodeled with its vendor_extension reason, so a promotion is a second
reading and never a move; the node records the heuristic in its own Provenance.Inferred; and a
node with no Provenance is not promoted into, because a guess nobody can audit is worse than an
empty field. Reading an extension is a heuristic — the format assigns x-* no semantics at all —
so invariant 6 governs all of it.

The seam. Options.Promotions maps an extension key to a member of a closed ExtensionTarget
vocabulary. Adding a target later is a constant and an applier, not a change to the policy shape or
to any call site. The default mapping is deliberately small and obviously a default:
x-deprecated-reason, x-deprecated-since and x-sunset are conventions no specification defines,
and a caller may replace the mapping outright rather than extend it.

What it fills today: the three ir.Deprecation members, at every carrier that can record the
promotion — operation, response header, type, property and security scheme. Parameter is the one
carrier left out and the reason is in the code beside it: ir.Parameter has no Provenance, so
rule 3 cannot be satisfied there, and giving it one is a change to ir-design.md rather than to
this compiler. The other extension-sourced fields — Pagination.*, LongRunning, Idempotency,
ErrorCase.Retryable/Throttling, Enum.Flags, EnumMember.Name, Sensitive, Secret — are
follow-up targets for this vocabulary; ErrorCase.Retryable/Throttling additionally needs #275,
since response extensions are not read at all until it lands.

Merge ordering: #341 adds DecodeOptions to the compiler contract, and #345 and #352 also rewrite
unwitnessed.golden.txt. Whichever lands first, the others rebase; once #341 is in, Promotions
should gain textual option names there so the CLI's -opt path can reach it.

Test plan

  • New corpus row extension-promotion names all five carriers individually, so a construction site
    that stops promoting fails on its own row rather than being covered by a neighbour. It also pins
    the two refusals: an extension beside no deprecated: true annotates nothing, and a value that is
    not text fills no field and is reported.
  • unwitnessed.golden.txt loses four entries — Deprecation.Message, Deprecation.Since,
    Deprecation.RemovalVersion, and Provenance.Inferred, which no corpus spec witnessed at all
    before this.
  • Unit tests pin that the promotion leaves the entry it read, that the marker joins whatever
    heuristic was already recorded and is not repeated when a node is annotated twice, and that both
    the exported default mapping and a caller's own map are copied rather than shared.
  • Policy tests cover the off switch and a caller's mapping replacing the defaults rather than
    extending them.
  • Full gate: gofmt, vet, golangci-lint, build, and the 100% coverage gate.

Closes #252

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.

compilers/openapi: typed IR fields whose only source is a vendor extension have no route to fill them

1 participant