Skip to content

feat(cli): define x-xgen-long-running-operation - #1425

Closed
julius-jogela wants to merge 2 commits into
mainfrom
feat/x-xgen-long-running-operation
Closed

feat(cli): define x-xgen-long-running-operation#1425
julius-jogela wants to merge 2 commits into
mainfrom
feat/x-xgen-long-running-operation

Conversation

@julius-jogela

@julius-jogela julius-jogela commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

Summary

Draft. Introduces the x-xgen-long-running-operation vendor extension and tags it at
merge time.

Behavior:

  • non-202 operation → no extension
  • standard 202x-xgen-long-running-operation: true
  • legacy 202x-xgen-long-running-operation: { legacy: true }

17 operations return 202 but predate IPA-132 and do not follow the long-running
operation contract (no Location header, no /operations polling endpoint). Rather than
leaving them untagged, they are published under the same extension with a legacy marker
so downstream tooling can tell the two groups apart:

# IPA-132 compliant
x-xgen-long-running-operation: true

# legacy pre-IPA-132 202 operation
x-xgen-long-running-operation:
  legacy: true

How legacy operations are identified

A hardcoded denylist of the 17 operationIds in merge.go. I looked for a native signal
in the raw spec first and there isn't one:

  • No response anywhere in the spec declares a Location header. The only response
    header names present are RateLimit-Limit and RateLimit-Remaining (542 responses
    each), so Location presence can't distinguish legacy from future-compliant operations.
  • No path contains an /operations segment.
  • The 202 response schemas have nothing in common — 11 of 17 are null, the rest point
    at 6 unrelated schemas.
  • Content-type version dates look promising but would misclassify any legacy operation
    that later gains a new version.

The cleaner long-term design is a marker in the upstream service specs
(x-xgen-legacy-long-running-operation), letting merge derive the value instead of
hardcoding it. That can't be done from this repo, which only holds generated output — the
source specs come from S3. The denylist decision is isolated in
longRunningOperationExtensionValue() so switching to an upstream marker later touches
one function.

Deliberately not using x-xgen-IPA-exception: it is scoped to validation-rule
exceptions and is stripped from the released spec by ExtensionFilter, so the semantics
would silently disappear.

What's here

  • tools/cli/internal/cli/merge/merge.go — tag 202 operations during merge; emit
    { legacy: true } for denylisted operation IDs
  • tools/cli/internal/cli/merge/merge_test.go — tests asserting the exact emitted shape

Verified published shape

Ran the built binary over the committed raw spec, then through foascli filter --env prod:

merged     {'{"legacy": true}': 17, 'true': 1}
filtered   {'{"legacy": true}': 17, 'true': 1}

The object-valued extension survives filtering intact, in both JSON and YAML. The single
true is a synthetic probe operation, not a real one — all 17 real 202 operations in
the spec today are legacy, and none is IPA-132 compliant
, so true will not appear in
the published spec until a service ships a compliant LRO.

Risk worth discussing

{ legacy: true } is truthy in JavaScript, Python and Go map-presence checks. A
consumer writing if (op['x-xgen-long-running-operation']) will read legacy operations as
compliant and poll them per a contract they don't implement. Since the spec currently
contains 17 legacy and 0 compliant operations, a naive consumer would be wrong every time.

Options if that matters: document that the value is true | { legacy: true } before any
consumer is written, or emit { legacy: false } for compliant operations so the value
type is uniform and presence can never be mistaken for compliance.

Nothing consumes this extension in the repo yet, so there is no in-repo backward-
compatibility risk.

Testing

go test ./internal/cli/merge/ — asserts exact shapes for non-202 (absent), standard
202 (true), 201+202 (true), and legacy 202 ({legacy: true}).

Tag every operation that returns HTTP 202 with
x-xgen-long-running-operation: true during the merge step.

17 operations return 202 but predate IPA-132 and do not follow the
long-running operation contract, so they are excluded via a hardcoded
denylist of operation IDs. That list is a draft idea for filtering out
legacy operations, not a final design.
Legacy pre-IPA-132 operations were left untagged. Publish them under the
same extension with a legacy marker instead, so downstream tooling can
tell them apart from IPA-132 compliant operations:

  standard 202 -> x-xgen-long-running-operation: true
  legacy 202   -> x-xgen-long-running-operation: {"legacy": true}

The legacy operations are still identified by the hardcoded denylist of
operation IDs.
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