Skip to content

fix(compilers/openapi): warn on a malformed path key - #733

Open
fuad-daoud wants to merge 4 commits into
mainfrom
fix/malformed-path-key-warning
Open

fuad-daoud wants to merge 4 commits into
mainfrom
fix/malformed-path-key-warning

Conversation

@fuad-daoud

Copy link
Copy Markdown
Collaborator

Summary

A Paths Object key that is not a path lowered in silence. "a/b c?x" reached
the IR with uriTemplate: "a/b c?x", no stderr output and exit 0 — as did
widgets (no leading slash), /a b, /a?x=1 and /a/%zz. The key still
lowers exactly as written; what this adds is one warning per malformed key, so
the typo is visible without any lowering changing (GitHub #641).

What a key may not be, and why:

  • no leading / — the Paths Object Patterned Fields rule, stated in the
    same sentence at 3.0.3 §4.7.8.1, 3.1.0 §4.8.8.1 and 3.2.0 §4.8.1, so the
    check is not version-gated;
  • a ? — RFC 3986 §3.4 keeps the query out of the path, and OpenAPI states
    query data as Parameter Objects with in: query;
  • a character a URI path does not admit — RFC 3986 §3.3's pchar set plus
    / and OpenAPI's {} templating braces. Non-ASCII is admitted (the IR field
    is an RFC 6570 template, whose literals admit and pct-encode them), and % is
    admitted only as the start of a pct-encoded triplet.

The new openapi/invalid-path-key diagnostic is a warning, not an error:
the key does lower, so an error would be a refusal this compiler does not
perform, and harness.Check stops at the first error diagnostic, which would
hide every later finding in the same spec. It is sited at /paths/<key> by
ids.Ptr("paths", key), so the pointer is RFC 6901-escaped, and its message
names the key, every defect the key carries, and closes by saying the key is not
rewritten. One diagnostic per key, not per defect.

Deliberately out of scope, stated here and in the code:

No existing diagnostic changed code, severity, message or pointer, and nothing
is deleted.

Test plan

  • go test ./compilers/openapi/internal/operation -run TestPathKey -count=1 —
    TestPathKey_Defects (classifier table: every allowed and rejected class,
    %20/%2/%zz/trailing %, non-ASCII, ?, #, empty key),
    TestPathKeys_MalformedAreReported (one warning at /paths/<escaped>, the
    message naming each defect, URITemplate verbatim),
    TestPathKeys_ValidAreNotReported (overreach),
    TestPathKeys_MalformedUnderEveryVersion (3.0.3, 3.1.0, 3.2.0),
    TestPathKeys_FragmentIsSilentForNow,
    TestPathKeys_WebhookKeysAreNotPaths.
  • go test ./compilers/openapi/... -count=1 — green, no golden regenerated and
    none changed (git status --porcelain -- '*.golden.json' is empty; no
    committed paths key in the corpus is malformed).
  • make gate — exits 0, including the exact-100% coverage gate.
  • Manual probe: go run ./cmd/morphic compile on a spec keyed a/b c?x prints
    one warning and still emits "uriTemplate": "a/b c?x", exit 0.

The plan this implements is committed alongside the fix as
docs/plans/641-malformed-path-key-warning.md.

A Paths Object key that is not a path — one omitting the leading "/", one
carrying a "?", or one whose characters a URI path does not admit — lowered in
silence, so a typo reached uriTemplate, the name hint and the group name as
though it were a route. The key still lowers verbatim, field for field. What is
new is one warning per malformed key, at /paths/<key>, naming the key, every
defect it carries, and saying the key is not rewritten.

Warning rather than error, for the reason InvalidStatusKey is one: the key
lowers, so refusing would be a refusal this compiler does not perform, and
harness.Check stops at the first error diagnostic, which would hide every later
finding in the same spec.

The rule is not version-gated: 3.0.3 §4.7.8.1, 3.1.0 §4.8.8.1 and 3.2.0 §4.8.1
state the leading-slash requirement in the same sentence. A "#" fragment is
deliberately silent here — GitHub #602 will strip it, set SharedRoute, regroup
the operations and report it. Webhook keys are names rather than paths, and
Paths Object x-* extensions are not path items; both are left alone.
@fuad-daoud fuad-daoud self-assigned this Sep 30, 2026
fuad-daoud and others added 2 commits October 7, 2026 07:17
Resolve the conflicts with main and bring the doc comments this branch
adds under the 100-word cap main now enforces.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GCzyGPq9DQ7RLfagZm2JB5
Plans and agent working notes are not part of the repository; what a
reviewer needs is in the PR body, the commits and the linked issues.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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