Openapi v3 parity - #5496
Draft
sethboyles wants to merge 20 commits into
Draft
Openapi v3 parity#5496sethboyles wants to merge 20 commits into
sethboyles wants to merge 20 commits into
Conversation
sethboyles
marked this pull request as draft
September 30, 2026 21:52
The 42 tag descriptions were one-line summaries written for the spec, and
several were inaccurate ("Service plans are plans for a service."). Replace
them with the prose the v3 reference docs use for each resource, and add
tags for the four resources that the v3 docs document separately but the
spec had folded into their parents: App Features, Space Features, Service
Plan Visibility and Route Policies.
Language derived from (40 of 42 are byte-identical to their source):
docs/v3/source/includes/resources/*/_header.md
docs/v3/source/includes/resources/*/_header.md.erb
Resource-level reference material folded into the matching tag, so it is
rendered once rather than repeated on every operation:
docs/v3/source/includes/resources/app_features/_supported_features.md.erb
docs/v3/source/includes/resources/app_features/_service_binding_files.md.erb
docs/v3/source/includes/resources/feature_flags/_flags.md.erb
docs/v3/source/includes/resources/roles/_valid_roles.md.erb
docs/v3/source/includes/resources/service_brokers/_jobs.md.erb
docs/v3/source/includes/resources/service_offerings/_visibility.md.erb
docs/v3/source/includes/resources/service_plan_visibility/_visibility_types.md.erb
docs/v3/source/includes/resources/audit_events/_header.md.erb (event type list)
Two places deviate from verbatim, both deliberate:
- Feature Flags: _flags.md.erb holds the table as an ERB loop, so it is
rendered here as a plain markdown table. The hash_based_routing row is
new -- the flag is in FeatureFlag::DEFAULT_FLAGS (app/models/runtime/
feature_flag.rb) but is missing from _flags.md.erb.
- Service Offerings: _visibility.md.erb is appended after the header prose.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
info.description was a short stub with two typos. The v3 reference docs carry ~80KB of conceptual documentation that the spec had no equivalent for at all, and existing parameter descriptions already link into it (for example "[relational operators](#relational-operators)" in components/parameters/CreatedAts.yaml). Port it verbatim so those anchors resolve and the concepts are documented. Language derived from, in this order: docs/v3/source/includes/introduction/_introduction.md docs/v3/source/includes/concepts/_*.md.erb (19 files) docs/v3/source/includes/upgrade_guide/**/*.md (38 files) The result is byte-for-byte reproducible from those files; the only text that is not from the v3 docs is the leading note that this spec is experimental. Mechanical conversions applied to make Slate markup render as plain markdown: <aside class="notice|warning"> -> > **Note:|Warning:** blockquote fenced single-line captions -> bold caption <h3 id="...">Title</h3> -> ### Title HTML comments -> removed Renders as three top-level sections (Introduction, Concepts, Upgrade Guide) with 26 subsections. ai-assisted=yes Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
RelationshipToOne declared `data` as `$ref: Relationship.yaml` with a sibling `type: [object, "null"]`. Under JSON Schema 2020-12 both apply, so the $ref's `type: object` won and a legitimate `data: null` response -- an organization role has no space, for example -- failed validation. `redocly lint` flagged this on the role examples. Replaced with an explicit anyOf of the $ref and `null`. That is equivalent to oneOf here, since an object and null never overlap, and it lets generators such as GraphQL Mesh keep producing the existing Relationship type. IncludedResources had `additionalProperties: false` but was missing three keys the API really does return, so responses using them could not validate: route_policies (RouteShowMessage/RoutesListMessage accept include=route_policies), service_plans and service_brokers (emitted by the service offering and service plan `fields` decorators). Note that docs/v3/source/includes/concepts/_includes.md.erb omits route_policies from its table of resources with includes, so this follows app/messages/routes_list_message.rb rather than the docs. ai-assisted=yes Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds the permitted-roles list to all 18 operations, the query parameters
and filter wording the v3 docs document, per-field descriptions on the app
object (state values, both relationships, metadata, links) and the app
feature, ssh_enabled, env, environment variables and permissions objects,
and response bodies plus examples for the app feature endpoints, which had
none.
Language derived from:
docs/v3/source/includes/resources/apps/
docs/v3/source/includes/resources/app_features/
docs/v3/source/includes/api_resources/_apps.erb
docs/v3/source/includes/api_resources/_app_features.erb
docs/v3/source/includes/api_resources/_app_ssh_enabled.erb
Also fixes, following the implementation rather than the spec:
- AppFeatureList used `$ref: '#/components/schemas/...'` pointers, which do
not resolve in the split layout; now relative file refs.
- AppUpdateRequestBody accepted environment_variables; AppUpdateMessage
does not.
- CF-FeatureDisabled moved from 422 to 403, per the v3 docs.
- The stop example reported state STARTED.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- `App.relationships` stays a `$ref` to Relationships.yaml, with the
relationship keys listed in its description. Typing it turns an open
object into a fixed type and changes how the shared RelationshipToOne
types get named.
- The object-valued `default` on `environment_variables` is described in
text instead; object defaults on request properties cannot be
represented as GraphQL default values and break schema printing.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties are stated in the property descriptions rather
than the schema; CC already rejects invalid requests with a 422.
Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Bodies that already list their properties get no extra
`type: object`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 13 operations and the embed, label_selector,
created_ats, updated_ats, guids and types parameters the v3 docs document.
The process stats object grew from 10 loosely typed fields to all 22
documented ones, and readiness health checks now have their own schema
rather than aliasing the health check schema, since their defaults and
wording differ.
Language derived from:
docs/v3/source/includes/resources/processes/
_object, _health_check_object, _readiness_health_check_object,
_process_instance_object, _stats_object and the endpoint files
docs/v3/source/includes/api_resources/_processes.erb
Also fixes:
- ProcessList used `allOf: [Pagination, ...]`, which flattened the
pagination fields to the top level instead of nesting them under
`pagination`.
- The process_instances description claimed the response contains index,
state and uptime; ProcessInstancesPresenter returns `since`.
Note: PATCH /v3/apps/{guid}/processes/{type} is kept because it is real
(config/routes.rb), even though the Definition block in
docs/v3/source/includes/resources/processes/_update.md.erb omits it.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- ProcessList keeps `resources` in the second `allOf` entry, now next to
a proper `pagination` property. Dropping the `allOf` renames every
type generated under `resources`.
- `data.timeout` on the readiness health check is kept as a deprecated
property rather than removed, since existing clients select it; it is
never returned.
- The ProcessScaleRequestBody schema has a `title`, so generators keep
the name they derived when the body was defined inline.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Bodies that already list their properties get no extra
`type: object`. Adding these to the schema would change existing
requests and generated input types.
- `since` stays a `number`, which already covers the integer values
returned.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 15 operations, route options (hash-based
routing) to the object and to the create and update bodies, and every
documented destination field. Destinations now use a request-shaped schema
for writes so the read-only fields are not accepted on input.
Language derived from:
docs/v3/source/includes/resources/routes/
_object, _destination_object, _route_options_object and the endpoint files
docs/v3/source/includes/api_resources/_routes.erb
Also fixes, following the implementation:
- The `protocols` list filter did not exist in RoutesListMessage and would
have been rejected; page/per_page on the destinations list are rejected
by NoAdditionalParamsValidator.
- RouteDestinationList declared a `pagination` block that
RouteDestinationsPresenter never emits, and the destination links were
self/route rather than destinations/route.
- Transfer route ownership is documented as 204 in _transfer_route_ownership
.md.erb but the controller renders 200 with {"status":"ok"} (see
spec/request/routes_spec.rb).
- The v3 hash_balance example value is rejected by RouteOptionsMessage.
- Removes a duplicate /v3/spaces/{guid}/routes block; the registry points
that path at paths/Spaces.yaml.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- `Route.relationships` stays a `$ref` to Relationships.yaml, with the
relationship keys listed in its description. Typing it turns an open
object into a fixed type and changes how the shared RelationshipToOne
types get named.
- In RouteDestinationRequest, `app.guid` and `protocol` stay plain
strings, with the UUID format and the valid protocols in their
descriptions, so clients that pass strings keep working.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties and length and range limits are stated in the
property descriptions rather than the schema; CC already rejects
invalid requests with a 422. Request bodies are not marked `required`,
since CC treats a missing body as `{}`. Adding these to the schema
would change existing requests and generated input types.
- Response values that were previously undeclared stay listed in the
description rather than becoming a new `enum`.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 17 operations, including the per-role
qualifiers on the security group endpoints and the note that a Space
Manager cannot change `suspended`. Adds the `suspended` field, the full
user and security group filter sets, and descriptions for every
relationship and link.
Language derived from:
docs/v3/source/includes/resources/spaces/
docs/v3/source/includes/resources/space_features/
docs/v3/source/includes/resources/manifests/_apply.md
docs/v3/source/includes/resources/manifests/_create_diff.md
docs/v3/source/includes/api_resources/_spaces.erb
docs/v3/source/includes/api_resources/_space_features.erb
Also fixes, following the implementation:
- The features list returned the single-feature schema instead of a list,
and its example invented a diego_docker space feature.
- manifest_diff was modelled as 201/202 with a Location header; it returns
201 with a {"diff": [...]} body.
- The usage summary link is `space`; the v3 example says `organization`,
but SpaceUsageSummaryPresenter emits `space`.
Deletes the unreferenced components/requestBodies/SpaceCreate.yaml;
SpaceCreateRequestBody.yaml is the one the paths use.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties are stated in the property descriptions rather
than the schema; CC already rejects invalid requests with a 422.
Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Bodies that already list their properties get no extra
`type: object`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 12 operations and models the managed and
user-provided variants properly: create is a discriminated oneOf on `type`
with per-type required fields, update is an anyOf, and the three `fields`
parameters are now deepObject with the allowed keys enumerated rather than
bare objects. Adds last_operation, maintenance_info and
broker_provided_metadata as described sub-schemas.
Language derived from:
docs/v3/source/includes/resources/service_instances/
docs/v3/source/includes/api_resources/_service_instances.erb
Also fixes: syslog_drain_url and route_service_url were on the managed
instance schema, but ServiceInstancePresenter#hash_additions_managed does
not emit them and the v3 object table lists them as user-provided only.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- The service instance create and update bodies also declare the merged
set of fields directly, next to the existing `oneOf`/`anyOf`, so
generators that cannot express unions of input objects still get every
field. `syslog_drain_url` and `route_service_url` stay plain strings.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties are stated in the property descriptions rather
than the schema; CC already rejects invalid requests with a 422.
Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 13 operations, restores the multi-paragraph
prose on create, delete and parameters, and replaces the bare `type:
object` responses on the details and parameters endpoints with real
schemas. Adds the `strategy` field to credential binding creates and the
missing `parameters` links.
Language derived from:
docs/v3/source/includes/resources/service_credential_bindings/
docs/v3/source/includes/resources/service_route_bindings/
docs/v3/source/includes/api_resources/_service_credential_bindings.erb
docs/v3/source/includes/api_resources/_service_route_bindings.erb
The details response shape follows
app/presenters/v3/service_credential_binding_details_presenter.rb.
Also fixes, following the implementation:
- The credential binding `type` filter is a single value with an inclusion
check in ServiceCredentialBindingListMessage, not a list.
- A 201 create only happens for user-provided instances, which cannot have
key bindings, so it is narrowed to the app binding schema.
- Route binding last_operation is emitted by the presenter but undocumented
in v3; it is included and marked nullable.
- The example GUIDs in both _service_*_bindings.erb files are malformed
(non-hex characters) and the route binding relationship GUIDs are swapped
relative to their own links; repaired here.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- ServiceCredentialBindingDetails stays an open object with its keys
documented in the description; the content is broker-defined and
clients read it as free-form JSON.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Bodies that already list their properties get no extra
`type: object`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… the v3 docs
The service offering and service plan schemas were near-empty stubs whose
only fields (service_broker_guid, service_offering_name) do not exist in
the API. Both are rewritten from the v3 object tables: available, free,
tags, requires, shareable, documentation_url, costs, maintenance_info,
broker_catalog with its features block, schemas, visibility_type and the
relationships. Adds permitted roles to all 17 operations, the
broker_catalog_ids filter, and deepObject `fields` parameters.
Language derived from:
docs/v3/source/includes/resources/service_brokers/
docs/v3/source/includes/resources/service_offerings/
docs/v3/source/includes/resources/service_plans/
docs/v3/source/includes/resources/service_plan_visibility/
docs/v3/source/includes/api_resources/_service_brokers.erb
docs/v3/source/includes/api_resources/_service_offerings.erb
docs/v3/source/includes/api_resources/_service_plans.erb
docs/v3/source/includes/api_resources/_service_plan_visibility.erb
Broker authentication is extracted to its own write-only schema, shared by
the create and update bodies, and is required on create per
ServiceBrokerCreateMessage. The four visibility operations move to the new
Service Plan Visibility tag. The plan `links.space` entry is confirmed
against app/presenters/v3/service_plan_presenter.rb.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Input enums and formats are stated in the property descriptions rather
than the schema; CC already rejects invalid requests with a 422.
Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Bodies that already list their properties get no extra
`type: object`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 13 operations, the copy endpoints, the
relationships.app field that was missing from the droplet schema entirely,
and per-field descriptions for state, checksum, buildpacks, image, error,
execution_metadata, process_types and the bits/docker data blocks.
Language derived from:
docs/v3/source/includes/resources/droplets/
docs/v3/source/includes/resources/packages/
docs/v3/source/includes/api_resources/_droplets.erb
docs/v3/source/includes/api_resources/_packages.erb
Copying is modelled as an optional source_guid query parameter on the
existing POST operations rather than as separate paths. The spec
previously carried a `/v3/packages?source_guid={source_guid}` path key,
which is not valid OpenAPI -- a path template cannot contain a query
string -- and it was never registered, so the endpoint was invisible.
Also fixes, following the implementation:
- Droplet upload declared a `resources` part and a JSON variant;
DropletUploadMessage accepts only bits.
- Droplet upload returns 202 only, package upload 200 only (the
controllers' render calls), not both.
- Droplet delete's 202 carried a Job body; the controller does head
:accepted.
- DropletCreateMessage does not accept metadata.
- Package download now documents its 200 (streamed from a local blobstore)
alongside the 302 (redirect to a remote one), per
BlobDispatcher#send_or_redirect -- so the operation-2xx-response entry in
.redocly.lint-ignore.yaml is no longer needed and is removed.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- `Package.relationships` stays a `$ref` to Relationships.yaml, with the
relationship keys listed in its description. Typing it turns an open
object into a fixed type and changes how the shared RelationshipToOne
types get named.
- The object-valued `default` on `process_types` and `data` is described
in text instead; object defaults on request properties cannot be
represented as GraphQL default values and break schema printing.
- The PackageUpdateRequestBody schema has a `title`, so generators keep
the name they derived when the body was defined inline.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties are stated in the property descriptions rather
than the schema; CC already rejects invalid requests with a 422.
Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 8 operations, including the Build State Updater
component role note, the staging_memory_in_mb, staging_disk_in_mb and
staging_log_rate_limit_bytes_per_second create fields, the buildpack
lifecycle filter, and v3's defaults for buildpack create (stack, position,
lifecycle, enabled, locked).
Language derived from:
docs/v3/source/includes/resources/builds/
docs/v3/source/includes/resources/buildpacks/
docs/v3/source/includes/api_resources/_builds.erb
docs/v3/source/includes/api_resources/_buildpacks.erb
Also fixes, following the implementation:
- PATCH /v3/apps/{guid}/builds does not exist; config/routes.rb has only
GET on that path. Operation removed.
- Buildpack upload returns 202 only and accepts only a `bits` part
(BuildpackUploadMessage); the invented 200 and `resources` part are gone.
- Build had a `checksum` property the presenter never emits, and BuildUpdate
had staging_* fields BuildUpdateMessage rejects.
- POST /v3/builds now references BuildCreateRequestBody, which existed but
was orphaned while the operation duplicated it inline.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- `Build.relationships` stays a `$ref` to Relationships.yaml, with the
relationship keys listed in its description. Typing it turns an open
object into a fixed type and changes how the shared RelationshipToOne
types get named.
- The BuildCreateRequestBody schema has a `title`, so generators keep
the name they derived when the body was defined inline.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties and input enums and formats are stated in the
property descriptions rather than the schema; CC already rejects
invalid requests with a 422. Adding these to the schema would change
existing requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Deployments gain permitted roles on all 6 operations plus the fields the v3
object table documents and the spec lacked: status.details.error, the
canary step counters, and descriptions and enums for status.value,
status.reason, strategy and all six options. Revisions gain the processes
and sidecars snapshots and `deployable`.
Language derived from:
docs/v3/source/includes/resources/deployments/
docs/v3/source/includes/resources/revisions/
docs/v3/source/includes/api_resources/_deployments.erb
docs/v3/source/includes/api_resources/_revisions.erb
Also fixes, following the implementation:
- Cancel and continue return no body (the controllers call head :ok); the
spec claimed a Deployment body.
- The revision `droplet` field is a bare {guid} object, not a relationship.
- Revision had an `enabled` property that does not exist.
- last_healthy_at is surfaced by the presenter as
status.details.last_successful_healthcheck.
Note: docs/v3/source/includes/resources/deployments/_cancel.md.erb and
_continue.md.erb contain no prose, so the preconditions described on those
two operations are written from DeploymentCancel/DeploymentContinue
(cancelable? and continuable?) and docs/v3/zero_downtime_deployments.md
rather than copied from the endpoint docs.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- `Deployment.relationships` stays a `$ref` to Relationships.yaml, with
the relationship keys listed in its description. Typing it turns an
open object into a fixed type and changes how the shared
RelationshipToOne types get named.
- `enabled` on the revision is kept as a deprecated property (never
returned; use `deployable`) rather than removed, since existing
clients select it.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties and length and range limits are stated in the
property descriptions rather than the schema; CC already rejects
invalid requests with a 422. Adding these to the schema would change
existing requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 12 operations, including the user_org_creation
flag caveat on create and the per-role notes on the quota list. Every leaf
of the nested apps, services, routes and domains quota objects now carries
its v3 description and the `null means unlimited` semantics, and the usage
summary and default domain/isolation segment endpoints have modelled
response shapes instead of bare objects.
Language derived from:
docs/v3/source/includes/resources/organizations/
docs/v3/source/includes/resources/organization_quotas/
docs/v3/source/includes/api_resources/_organizations.erb
docs/v3/source/includes/api_resources/_organization_quotas.erb
The usage summary leaves follow
app/presenters/v3/organization_usage_summary_presenter.rb, since v3
documents no field table for them.
Also fixes, following the implementation:
- OrganizationQuota had `metadata` and a links.organizations entry that
OrganizationQuotaPresenter does not emit and the update message rejects.
- OrganizationQuotaList used `allOf: [Pagination, ...]`, flattening the
pagination fields to the top level.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- OrganizationQuotaList keeps `resources` in the second `allOf` entry,
now next to a proper `pagination` property. Dropping the `allOf`
renames every type generated under `resources`.
- Applying a quota to organizations keeps using RelationshipToMany,
which already describes a list of guids under `data`.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties are stated in the property descriptions rather
than the schema; CC already rejects invalid requests with a 422.
Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 16 operations. Role creation now models both
documented shapes -- by user guid, and by username plus origin -- with a
oneOf over the organization and space relationships. User creation is a
strict oneOf (UAA guid, or username plus origin). Space quota nested
objects get every documented leaf, its default, and the `null means
unlimited` semantics.
Language derived from:
docs/v3/source/includes/resources/roles/
docs/v3/source/includes/resources/users/
docs/v3/source/includes/resources/space_quotas/
docs/v3/source/includes/api_resources/_roles.erb
docs/v3/source/includes/api_resources/_users.erb
docs/v3/source/includes/api_resources/_space_quotas.erb
The valid role types are enumerated from
docs/v3/source/includes/resources/roles/_valid_roles.md.erb, whose table is
in the Roles tag description rather than repeated here.
Also fixes, following the implementation:
- label_selector was offered on the roles and space quota lists; neither
list message supports it.
- SpaceQuota carried `metadata`, but SpaceQuotaUpdateMessage is not a
MetadataBaseMessage.
- The user update body exposed username, presentation_name, origin and
links; UserUpdateMessage allows only metadata.
- Role examples contained a `user_group` relationship RolePresenter never
emits.
- The v3 space quota list example says relationships.organizations; the
presenter emits `organization`.
- Wires up schemas/UserCreate.yaml and schemas/SpaceQuotaUpdate.yaml, both
of which existed but were orphaned.
- Removes a path with a trailing slash
(/v3/space_quotas/{guid}/relationships/spaces/{space_guid}/) that matched
no route and was unregistered.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- The SpaceQuotaUpdate schema has a `title`, so generators keep the name
they derived when the body was defined inline.
- UserCreate declares the merged fields next to its `oneOf`, with a
`title`, so generators that cannot express unions of input objects
still get every field.
- Applying a quota to spaces keeps using RelationshipToMany, which
already describes a list of guids under `data`.
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties are stated in the property descriptions rather
than the schema; CC already rejects invalid requests with a 422.
Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The security group rule object is extracted into its own schema with every
documented field, including `log`, which was missing everywhere, and the
protocol enum, the destination notes about comma-delimited lists and
icmpv6, and the -1..255 range on type and code. Stacks gain `state` and
`state_reason`. Permitted roles added to all 15 operations, and the
multi-paragraph prose on update, bind and unbind is restored rather than
flattened to one line.
Language derived from:
docs/v3/source/includes/resources/security_groups/
docs/v3/source/includes/resources/stacks/
docs/v3/source/includes/api_resources/_security_groups.erb
docs/v3/source/includes/api_resources/_stacks.erb
docs/v3/source/includes/api_resources/examples/*security_group*.json
Also fixes, following the implementation:
- PATCH and DELETE on /v3/spaces/{guid}/staging_security_groups do not
exist; config/routes.rb has GET only. Those operations are removed, along
with two duplicate /v3/spaces/... path items whose registry entries point
at paths/Spaces.yaml. This also resolves the duplicate updateSecurityGroup
and deleteSecurityGroup operationIds.
- running_spaces and staging_spaces were top-level properties; they are
to-many relationships.
- Security groups have no metadata support (no label model, and
SecurityGroupPresenter emits none), so the metadata property is removed
from all three security group schemas.
- SecurityGroup.links only ever contains self.
- The guids and names filters were described as case-insensitive; both the
docs and the code say case-sensitive.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties, length and range limits and input enums and
formats are stated in the property descriptions rather than the
schema; CC already rejects invalid requests with a 422. Request bodies
are not marked `required`, since CC treats a missing body as `{}`.
Bodies that already list their properties get no extra `type: object`.
Adding these to the schema would change existing requests and
generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 12 operations and the documented task and
sidecar body fields. GET /v3/apps/{guid}/manifest now declares that it
returns YAML and references a Manifest schema carrying the manifest field
reference, which the spec had nowhere.
Language derived from:
docs/v3/source/includes/resources/tasks/
docs/v3/source/includes/resources/sidecars/
docs/v3/source/includes/resources/manifests/_object.md.erb (field reference)
docs/v3/source/includes/api_resources/_tasks.erb
docs/v3/source/includes/api_resources/_sidecars.erb
Also fixes, following config/routes.rb:
- The cancel endpoints are POST /v3/tasks/{guid}/actions/cancel and
PUT /v3/tasks/{guid}/cancel; the spec had PUT on the actions path. The
PUT form is marked deprecated, as the v3 docs label it.
- Removes the two dead /v3/spaces/{guid}/... manifest path items from
paths/Manifests.yaml; the registry points both at paths/Spaces.yaml,
where they are defined.
Note: the task object table in
docs/v3/source/includes/resources/tasks/_object.md.erb names the field
log_rate_limit_per_second, but TaskPresenter emits
log_rate_limit_in_bytes_per_second; the spec follows the presenter.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- Query parameters keep their existing order, and `order_by` stays a
plain string with the valid values in its description. Generators key
argument handling off both.
- Required properties are stated in the property descriptions rather
than the schema; CC already rejects invalid requests with a 422.
Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Bodies that already list their properties get no extra
`type: object`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to every operation in these four resources, the job
state and operation wording with its POLLING note, the resource match
`mode` property and required fields, and the link lists both root endpoints
actually return -- the /v3 root was missing eight of them
(app_usage_events, audit_events, buildpacks, environment_variable_groups,
organization_quotas, resource_matches, service_usage_events, space_quotas).
Language derived from:
docs/v3/source/includes/resources/jobs/
docs/v3/source/includes/resources/resource_matches/
docs/v3/source/includes/resources/admin/
docs/v3/source/includes/resources/root/
docs/v3/source/includes/api_resources/_jobs.erb
docs/v3/source/includes/api_resources/_resource_matches.erb
docs/v3/source/includes/api_resources/_root.erb
Also fixes:
- JobList used `$ref: '#/components/schemas/...'` pointers, which do not
resolve in the split layout; now relative file refs.
- Both root endpoints get `security: []`, since the v3 docs state they
require no authentication and the spec applies OAuth globally.
To keep code generated from the spec stable (GraphQL Mesh, for example,
derives type, field and argument names from its structure), this also:
- Request bodies are not marked `required`, since CC treats a missing
body as `{}`. Adding these to the schema would change existing
requests and generated input types.
ai-assisted=yes
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Adds permitted roles to all 7 operations, completes the audit event `types` enum (26 values were missing, including the buildpack, organization_quota, route_policy, space_quota and stack lifecycles), spells out the [gt]/[gte]/[lt]/[lte] timestamp operator syntax, and fills in the service usage event object, which previously had only `links`. Language derived from: docs/v3/source/includes/resources/audit_events/ docs/v3/source/includes/resources/app_usage_events/ docs/v3/source/includes/resources/service_usage_events/ docs/v3/source/includes/api_resources/_audit_events.erb docs/v3/source/includes/api_resources/_app_usage_events.erb docs/v3/source/includes/api_resources/_service_usage_events.erb The audit event type list itself lives in the Audit Events tag description rather than being repeated in the schema. Also fixes: - Both usage event list examples contained leaked ERB in their pagination hrefs (`https://api.example.org<%= path %>?...`). - The app usage event schema had no links object at all. - The purge endpoints return 200 only; both controllers render :ok. - updated_ats is documented for the usage event lists but DisallowUpdatedAtsParamValidator rejects it, so it is not offered. To keep code generated from the spec stable (GraphQL Mesh, for example, derives type, field and argument names from its structure), this also: - Query parameters keep their existing order, and `order_by` stays a plain string with the valid values in its description. Generators key argument handling off both. ai-assisted=yes Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ith v3 Adds permitted roles to the six authenticated operations, the missing osbapi_version and rate_limits fields on /v3/info, and real schemas for both info endpoints in place of inline stubs. The environment variable group `name` path parameter had no description at all and is now documented and enumerated as running or staging. Language derived from: docs/v3/source/includes/resources/feature_flags/ docs/v3/source/includes/resources/environment_variable_groups/ docs/v3/source/includes/resources/info/ docs/v3/source/includes/api_resources/_feature_flags.erb docs/v3/source/includes/api_resources/_environment_variable_groups.erb docs/v3/source/includes/api_resources/_info.erb The info fields follow app/presenters/v3/info_presenter.rb. The flag list itself is in the Feature Flags tag description. /v3/info states "no authentication required" rather than a roles list, matching the v3 docs, and declares a 429: unauthenticated requests are rate limited (middleware/rate_limiter.rb, middleware/base_rate_limiter.rb). Also fixes, following the implementation: - The hash_based_routing flag is accepted by the name parameter; it exists in FeatureFlag::DEFAULT_FLAGS but not in the v3 flag table. - EnvironmentVariableGroup.name was nullable; the presenter always returns running or staging. - Response code sets trimmed to what these endpoints can actually return (/v3/info takes no auth, parameters or body, yet declared 400/403/404/ 409/422/502). To keep code generated from the spec stable (GraphQL Mesh, for example, derives type, field and argument names from its structure), this also: - Query parameters keep their existing order, and `order_by` stays a plain string with the valid values in its description. Generators key argument handling off both. - Response values that were previously undeclared stay listed in the description rather than becoming a new `enum`. ai-assisted=yes Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
sethboyles
force-pushed
the
openapi-v3-parity-graphql-compatible
branch
from
September 30, 2026 22:47
946356b to
efba23e
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PATCH /v3/apps/{guid}/builds,PUT /v3/tasks/{guid}/actions/cancel(2)config/routes.rb. Task cancel isPOST /v3/tasks/{guid}/actions/cancel, plus the legacyPUT /v3/tasks/{guid}/cancel, both still documented.POST /v3/buildpacks/{guid}/upload200,POST /v3/droplets/{guid}/upload200,POST /v3/packages/{guid}/upload202,POST /v3/spaces/{guid}/manifest_diff202,PATCH /v3/routes/{guid}/relationships/space204 (5)202with aLocationheader. Package upload returns200,manifest_diffreturns201, and route transfer returns200. The statuses that remain are the ones the controllers render.POST /v3/deployments/{guid}/actions/canceland/continue200application/json,DELETE /v3/droplets/{guid}202application/json,GET /v3/droplets/{guid}/download200text/html(4)head :ok(no body), and droplet delete withhead :acceptedplusLocation. Download sends the blob or redirects to the blobstore; it never returns HTML.application/jsonrequest bodies from bits uploadsPOST /v3/droplets/{guid}/upload,POST /v3/packages/{guid}/upload(2)bits, and for packages alsoresources), per the v3 docs. A JSON body isn't accepted.PATCH /v3/builds/{guid}state: STAGING(1)BuildUpdateMessageonly acceptsBuildModel::FINAL_STATES(STAGED,FAILED);STAGINGgets a 422.STAGINGis still listed as a response state.datais not nullablePATCH /v3/routes/{guid}/relationships/space(1)RouteTransferOwnerMessagevalidatesdatawithpresence: true, allow_nil: false, sonullgets a 422.GET /v3/processes/{guid}/process_instancesstate: STOPPING(1)InstancesStatsReporterreports stopping instances asSTOPPINGwhenapp_instance_stopping_stateis enabled (it is by default), and the v3 docs list it. The previous enum was incomplete, so clients could already receive a value outside it.dataGET/PATCH /v3/apps/{guid}/relationships/current_droplet,GET/PATCH /v3/spaces/{guid}/relationships/isolation_segment(8),GET/PATCH /v3/organizations/{guid}/relationships/default_isolation_segment(2)RelationshipToOne.datawastype: [object, "null"]next to a$reftoRelationship(type: object). In OpenAPI 3.1 both apply, sodata: null(e.g. a space with no isolation segment) failed validation. It's nowanyOf: [Relationship, null], which accepts the same values the schema was meant to. oasdiff reports the newanyOf(and the movedtype) as breaking even though the accepted values are unchanged. The org default-isolation-segment schema has the samenullmember underoneOf, already the case before this PR.