Skip to content

feat: add Spectral lint rules enforcing API design guidelines#317

Open
pengying wants to merge 1 commit intomainfrom
pengying/spectral-lint-rules
Open

feat: add Spectral lint rules enforcing API design guidelines#317
pengying wants to merge 1 commit intomainfrom
pengying/spectral-lint-rules

Conversation

@pengying
Copy link
Copy Markdown
Contributor

@pengying pengying commented Apr 2, 2026

Add Spectral OpenAPI linter with rules matching openapi/README.md:

  • field-names-camelCase: schema properties must be camelCase (error)
  • enum-values-upper-snake-case: enum values must be UPPER_SNAKE_CASE (error)
  • query/path-params-camelCase: parameter names must be camelCase (error)
  • paths-kebab-case: path segments must be kebab-case (error)
  • no-inline-request/response-schema: must use $ref not inline (error)
  • oneOf-must-have-discriminator: oneOf needs discriminator (warn)
  • pagination-envelope-has-data/hasMore: list responses need envelope (warn)
  • delete-returns-204: DELETE should return 204 (warn)
  • schema-properties-have-descriptions: properties need descriptions (warn)
  • schema-properties-have-examples: properties should have examples (info)

Also adds "Avoid Inline Schemas" section to openapi/README.md.

Co-Authored-By: Claude Opus 4.6 (1M context) noreply@anthropic.com

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 2, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
grid-flow-builder Ready Ready Preview, Comment Apr 2, 2026 3:27pm

Request Review

Copy link
Copy Markdown
Contributor Author

pengying commented Apr 2, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 2, 2026

Greptile Summary

This PR introduces a Spectral OpenAPI linter configuration (.spectral.yaml) with 10+ rules covering naming conventions, discriminator requirements, inline schema avoidance, pagination envelope validation, HTTP status codes, and documentation completeness. It also adds a new "Avoid Inline Schemas" section to openapi/README.md and wires up a make lint-spectral Make target.

The intent is solid and the rule coverage maps well to the design guidelines — however several of the rule implementations have correctness gaps (covered in prior review threads: resolved: false needed for inline-schema rules, no-op JSONPath on pagination-envelope-has-hasMore, false positives on non-list GETs, missed property-level enums). The most pressing new finding is that lint-spectral is never called by make lint, so the CI pipeline defined in .github/workflows/lint.yml will not enforce any of these rules until the lint target is updated.

Key findings:

  • CI integration gap: make lintnpm run lint → only Redocly; Spectral rules are never executed in CI (P1)
  • Multiple rule correctness issues flagged in prior threads remain unaddressed (P1): no-inline-*-schema always fires due to $ref resolution, pagination-envelope-has-hasMore filter is a no-op, enum-values-upper-snake-case misses property-level enums, path-level parameters skipped
  • .spectral.yaml is not in the CI paths trigger, so rule-only changes won't re-run the lint workflow

Confidence Score: 3/5

  • Not safe to merge — Spectral rules won't be enforced in CI, and several rule implementations have known correctness issues still unaddressed from prior review rounds.
  • Score of 3 reflects a new P1 CI integration gap (Spectral never called from make lint) combined with multiple unresolved P1 issues from prior review threads (resolved: false, no-op JSONPath, false positives on pagination rules). The PR's primary purpose — automated enforcement of API design guidelines — is not achieved until both the rule correctness issues and the CI wiring are fixed.
  • .spectral.yaml (multiple rule correctness issues) and Makefile (Spectral not included in the lint target that CI runs)

Important Files Changed

Filename Overview
.spectral.yaml New Spectral ruleset with several correctness issues: no-inline-*-schema rules need resolved: false to work correctly, pagination-envelope-has-hasMore JSONPath filter is a no-op, pagination-envelope-has-data will false-positive on non-list GETs, and enum-values-upper-snake-case misses property-level enums — most flagged in previous review threads.
Makefile Adds lint-spectral Make target but does not wire it into the primary lint target, leaving Spectral out of CI enforcement.
package.json Adds @stoplight/spectral-cli as a devDependency; no lint:spectral npm script added, which is consistent with the direct npx invocation in the Makefile.
openapi/README.md Adds "Avoid Inline Schemas" section documenting the $ref-only pattern; documentation is clear and accurate.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    PR[Pull Request / Push] --> CI[".github/workflows/lint.yml\nruns: make lint"]
    CI --> MAKELINT["make lint\n→ npm run lint"]
    MAKELINT --> REDOCLY["npm run lint:openapi\n(Redocly bundle + lint)"]
    REDOCLY --> PASS["✅ CI passes"]

    MAKELINT -.->|"NOT called\n(gap introduced by this PR)"| SPECTRAL

    SPECTRAL["make lint-spectral\n→ npx spectral lint openapi.yaml"]
    SPECTRAL --> RULES

    subgraph RULES["Spectral Rules (.spectral.yaml)"]
        R1["Naming: camelCase fields,\nparams, paths-kebab-case"]
        R2["Enums: UPPER_SNAKE_CASE"]
        R3["No inline request/response schemas\n⚠️ needs resolved: false"]
        R4["oneOf must have discriminator"]
        R5["Pagination envelope:\ndata + hasMore\n⚠️ hasMore filter is a no-op"]
        R6["DELETE returns 204"]
        R7["Properties need descriptions\n+ examples"]
    end

    SPECTRAL -.->|"must be run\nmanually"| DEV["👤 Developer only"]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: Makefile
Line: 22-23

Comment:
**Spectral not wired into the main `lint` target**

The `lint` Make target calls `npm run lint`, which maps to only `lint:openapi` (Redocly). The new `lint-spectral` target is entirely separate, so CI (`.github/workflows/lint.yml` runs `make lint`) will never execute Spectral. This means the rules added in this PR are effectively advisory — a PR introducing a camelCase violation, missing discriminator, or inline schema will pass CI without complaint.

To enforce Spectral in CI, `lint-spectral` needs to be added as a dependency of `lint` (or chained in):

```suggestion
lint:
	npm run lint
	$(MAKE) lint-spectral
```

Alternatively, add a `lint:spectral` script to `package.json` and extend the `lint` script: `"lint": "npm run lint:openapi && npx spectral lint openapi.yaml --fail-severity=error"`.

Note also that `.spectral.yaml` is absent from the `paths` trigger in `.github/workflows/lint.yml`, so changes to the rule file alone won't re-run CI.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "feat: add Spectral lint rules enforcing ..." | Re-trigger Greptile

Add Spectral OpenAPI linter with rules matching openapi/README.md:

- field-names-camelCase: schema properties must be camelCase (error)
- enum-values-upper-snake-case: enum values must be UPPER_SNAKE_CASE (error)
- query/path-params-camelCase: parameter names must be camelCase (error)
- paths-kebab-case: path segments must be kebab-case (error)
- no-inline-request/response-schema: must use $ref not inline (error)
- oneOf-must-have-discriminator: oneOf needs discriminator (warn)
- pagination-envelope-has-data/hasMore: list responses need envelope (warn)
- delete-returns-204: DELETE should return 204 (warn)
- schema-properties-have-descriptions: properties need descriptions (warn)
- schema-properties-have-examples: properties should have examples (info)

Spectral is not yet wired into `make lint` — run `make lint-spectral`
to check. Will be added to CI after existing violations are fixed.

Also adds "Avoid Inline Schemas" section to openapi/README.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment on lines 22 to 23
lint:
npm run lint
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Spectral not wired into the main lint target

The lint Make target calls npm run lint, which maps to only lint:openapi (Redocly). The new lint-spectral target is entirely separate, so CI (.github/workflows/lint.yml runs make lint) will never execute Spectral. This means the rules added in this PR are effectively advisory — a PR introducing a camelCase violation, missing discriminator, or inline schema will pass CI without complaint.

To enforce Spectral in CI, lint-spectral needs to be added as a dependency of lint (or chained in):

Suggested change
lint:
npm run lint
lint:
npm run lint
$(MAKE) lint-spectral

Alternatively, add a lint:spectral script to package.json and extend the lint script: "lint": "npm run lint:openapi && npx spectral lint openapi.yaml --fail-severity=error".

Note also that .spectral.yaml is absent from the paths trigger in .github/workflows/lint.yml, so changes to the rule file alone won't re-run CI.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Makefile
Line: 22-23

Comment:
**Spectral not wired into the main `lint` target**

The `lint` Make target calls `npm run lint`, which maps to only `lint:openapi` (Redocly). The new `lint-spectral` target is entirely separate, so CI (`.github/workflows/lint.yml` runs `make lint`) will never execute Spectral. This means the rules added in this PR are effectively advisory — a PR introducing a camelCase violation, missing discriminator, or inline schema will pass CI without complaint.

To enforce Spectral in CI, `lint-spectral` needs to be added as a dependency of `lint` (or chained in):

```suggestion
lint:
	npm run lint
	$(MAKE) lint-spectral
```

Alternatively, add a `lint:spectral` script to `package.json` and extend the `lint` script: `"lint": "npm run lint:openapi && npx spectral lint openapi.yaml --fail-severity=error"`.

Note also that `.spectral.yaml` is absent from the `paths` trigger in `.github/workflows/lint.yml`, so changes to the rule file alone won't re-run CI.

How can I resolve this? If you propose a fix, please make it concise.

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