Skip to content

feat: support path-scoped overrides for duplicate operationId command conflicts #82

Description

@samzong

Problem

Lathe currently rejects duplicate generated command paths, which is the right failure mode for a CLI, but the user cannot recover when the upstream OpenAPI document has duplicate operationId values that point to different REST endpoints.

A real downstream upgrade hit this with lathe v0.4.4 while regenerating DaoCloud/daocloud-skills:

error: command path "gatewayservice create-service" conflicts between "GatewayService_CreateService" and "GatewayService_CreateService"

The two operations are distinct REST endpoints:

POST /apis/sesame.skoala.io/v1alpha1/workspaces/{workspaceId}/clusters/{clusterName}/namespaces/{namespaceName}/gateways/{gatewayName}/services
POST /apis/sesame.skoala.io/v1alpha2/workspaces/{workspaceId}/clusters/{clusterName}/namespaces/{namespaceName}/gateways/{gatewayName}/services

Both declare the same OpenAPI operationId:

GatewayService_CreateService

From a REST perspective the endpoints are distinct because method + path are different. From an OpenAPI quality perspective the duplicate operationId is bad, but downstream consumers still need a deterministic way to generate a usable CLI without editing generated code or hiding business commands.

Proposal

Add an operation-scoped recovery path for command path conflicts caused by duplicate generated command identity.

Minimum useful behavior:

  1. Improve the conflict error so it prints enough identity for both operations:
    • HTTP method
    • path template
    • operationId
    • generated group/use
  2. Add overlay targeting by method + path, or an equivalent stable operation selector, so downstreams can rename only one conflicting operation.

Example shape:

commands:
  - match:
      method: POST
      path: /apis/sesame.skoala.io/v1alpha2/workspaces/{workspaceId}/clusters/{clusterName}/namespaces/{namespaceName}/gateways/{gatewayName}/services
    use: create-service-v1alpha2

The exact YAML shape is flexible. The important part is that overlays must be able to target one operation even when operationId and generated use collide.

Alternatives considered

  • Fix the upstream OpenAPI spec by making operationId globally unique. Correct, but not always available to the CLI consumer and not a good blocker for downstream adoption.
  • Use the current commands.<use>.use overlay. This does not work here because both generated commands have the same use, so the overlay would apply to both and the conflict remains.
  • Use ignore: true. This changes the business command surface by hiding one or both operations, which is not acceptable for a dependency-only Lathe upgrade.
  • Auto-suffix all conflicts with path version. Possibly useful later, but explicit overlay targeting is the smaller and more controllable primitive.

Affected surface

  • Swagger/OpenAPI/proto parsing
  • Normalization/codegen

Compatibility notes

This should be opt-in for command shape changes. Existing overlays should continue to work. The error message improvement is backward-compatible. If a catalog schema change is needed to expose the selector/debug identity, bump the catalog schema intentionally.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions