Skip to content

EndpointClientCoverageTests: a client wildcard silently covers literal endpoint routes #179

Description

@Sev7eNup

Found while closing #89.

EndpointClientCoverageTests exists to enforce the CLAUDE.md rule "Jeder neue API-Endpoint braucht beide Clients" at the level of endpoint existence. It did not catch #89 — the effective-sizing endpoint shipping without a CLI client — and it reported the surface as covered.

Cause

IsCovered treats a wildcard on either side as compatible:

if (e[i] != c[i] && e[i] != "*" && c[i] != "*") { allCompatible = false; break; }

Both sides normalize parameterized segments to *. The CLI's GetSettingsSectionAsync requests api/admin/settings/{section}api/admin/settings/*, which then matches the literal endpoint route api/admin/settings/effective-sizing. Every literal sub-route under a path where a client has a parameterized sibling is silently "covered".

This is not specific to admin-settings: it applies wherever a client has a by-id/by-name/by-section call next to literal sibling routes.

Measured blast radius

Tightening to "a client * only satisfies an endpoint *":

if (e[i] != c[i] && !(e[i] == "*" && c[i] == "*")) { allCompatible = false; break; }

surfaces 7 additional routes:

api/alerting/catalog
api/alerting/deliveries
api/alerting/preview-filter
api/alerting/preview-rule
api/workflows/*/move-folder
api/workflows/by-name/*
api/workflows/export

These are a mix: some are genuine gaps, but api/alerting/deliveries, api/workflows/by-name/* and api/workflows/export do have CLI call sites, so the strict rule also produces false positives that need per-route investigation (likely a normalization mismatch on the client-scan side rather than a real gap).

Deliberately left out of #89's PR — fixing it properly means auditing each of those 7 and either closing the gap or adding an honest known-gaps entry, which is well beyond that PR's scope.

Suggested work

  1. Tighten IsCovered so a client wildcard cannot satisfy an endpoint literal.
  2. Investigate why the three routes with real call sites do not match — probably the client URL normalization, not the matcher.
  3. Close or document the remainder.
  4. Add a test for the matcher itself: a client route api/x/* must not cover endpoint api/x/literal. Without it this regresses invisibly again.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions