Update spectra to 0.14.1: nested doc annotations - #39
Merged
Merged
Conversation
spectra 0.14.0 fixes doc annotations being dropped when a type is inlined
into another schema. title, description, deprecated, examples and
examples_function set with the spectral/1 macro now reach struct and map
field values, list and non-empty list elements, union branches, optional
map values, and remote types from other modules. Previously only the type
schema generation was entered with kept them.
No wrapper API change was needed. Added:
- Tests covering each inlined position, alias merging (nearest use site
wins, other keys kept from both), and example validation at an inlined
position.
- A readable ArgumentError for {invalid_example, ...} in place of the raw
ErlangError. 0.14.0 validates examples at every position a type appears
in, not just at entry points, so this error is far more reachable.
- README section on annotation propagation, merging, the three positions
that do not carry an annotation, and the cost of examples_function being
called once per position.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XTMXez4gy2fHp6HgovtfGG
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
Two moderate test-coverage findings remain unresolved.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Updates Spectral to spectra 0.14.0, enabling nested annotation propagation and clearer invalid-example errors.
Changes:
- Bumps project and dependency versions.
- Adds nested annotation fixtures and tests.
- Improves invalid-example error handling.
- Documents annotation propagation and behavior.
File summaries
| File | Summary | Findings |
|---|---|---|
test/support/nested_doc_module.ex |
Adds nested annotation fixtures. | — |
test/support/nested_doc_bad_example_module.ex |
Adds invalid-example fixture. | — |
test/spectral_nested_doc_test.exs |
Tests nested annotation propagation and validation. | Moderate (2 votes): add examples_function call-count coverage.Moderate (1 vote): add nested OpenAPI rendering coverage. Nit (3 votes): fix grammar. |
README.md |
Documents annotation behavior and alias merging. | — |
mix.lock |
Locks spectra at 0.14.0. |
— |
mix.exs |
Updates project and dependency versions. | — |
lib/spectral.ex |
Translates invalid-example errors to ArgumentError. |
— |
CHANGELOG.md |
Records the release changes. | — |
Review details
Suppressed comments (1)
test/spectral_nested_doc_test.exs:14
- The new tests only render JSON Schema, but the PR also changes the generated OpenAPI schemas through
:spectra_openapi. Without an OpenAPI rendering assertion for these nested annotations, a regression in that path could pass the suite.
describe "annotations on inlined types" do
test "a remote annotated type keeps its metadata as a map field value" do
- Files reviewed: 7/8 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- Cover examples_function at inlined positions. 0.14.0 changes its call count from once per schema to once per inline position, which the tests asserted nothing about. The fixture now counts its own invocations, and a type inlining it twice asserts two calls and the examples on both properties. - Cover the OpenAPI rendering path. The existing tests only exercised JSON Schema, so a regression in spectra_openapi would have passed. The new test builds an endpoint, follows the response body $ref into components.schemas, and asserts the nested titles and descriptions. - Reword the ungrammatical sentence in the test module comment. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XTMXez4gy2fHp6HgovtfGG
andreashasse
added a commit
to andreashasse/ecto_spectral
that referenced
this pull request
Sep 14, 2026
Spectral 0.14.0 is about to be released. The requirement becomes `~> 0.13.0 or ~> 0.14.0` rather than `~> 0.14.0` alone, because 0.14.0 is not on Hex yet and a 0.14-only bound would stop `mix deps.get` from resolving until it is. The lock stays on 0.13.0 until then. Checked against Spectral's 0.14.0 release branch (andreashasse/spectral#39), which moves spectra to 0.14.0: the full suite passes, 88 tests, and the build is free of warnings. Both releases only change schema generation, which this library never calls. The one thing that could have tied us to a version was the rescue around Spectral.encode/5. For a badly shaped value Spectral raises from inside its own error handling rather than returning errors, in 0.13 and in the 0.14 branch alike. Every caller already treats a raise and an error return the same way, so a later release that fixes it changes nothing here. The comment now says that instead of describing the raise as how Spectral behaves. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Merges in the non-empty list shorthand fix (#42), which landed on main after this branch. Folds its CHANGELOG entry into the same 0.14.0 section as the spectra bump, since main is still at 0.13.0 and this branch is the one cutting that release. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XTMXez4gy2fHp6HgovtfGG
Merges in the unexpected-crash reraise fix (#43), which landed on main after this branch. Resolves the handle_erlang_error/5 conflict by keeping both the new fallback clause and the existing describe_type helper. Also bumps spectra to 0.14.1 (still satisfied by the existing ~> 0.14.0 constraint) and adds a regression test plus a CHANGELOG entry for its fix: encoding a struct with non-map data crashed with a raw badmap error instead of returning {:error, [...]}. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XTMXez4gy2fHp6HgovtfGG
Merges in the Ecto jsonb docs and codec spec fixes (#40), which landed on main after this branch. Only CHANGELOG.md conflicted — folded both Fixed lists and the new Added section into the shared 0.14.0 heading. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XTMXez4gy2fHp6HgovtfGG
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XTMXez4gy2fHp6HgovtfGG
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.
What
Bumps the
spectradependency from~> 0.13.1to~> 0.14.0(which now resolves to0.14.1) and bumps Spectral to0.14.0. The~> 0.14.0constraint already covers every future0.14.xpatch release — it excludes0.15.0and above, where spectra's pre-1.0 versioning may carry breaking changes.spectra 0.14.0 fixes doc annotations being dropped when a type is inlined into another schema.
title,description,deprecated,examplesandexamples_functionset with thespectral/1macro now reach:Previously only the type schema generation was entered with kept its annotations, so
deprecated: trueon a type used as a struct field produced nothing in the output.spectra 0.14.1 additionally fixes encoding a struct with non-map data (a string, integer, list, or atom): it crashed with a raw
badmaperror instead of returning{:error, [spectra:error()]}. Only the struct branch of encoding was affected; plain map types, list types, record types, and decoding were unaffected.Wrapper compatibility
No API change was needed. The existing test suite passes unchanged against 0.14.1, and no callback signature, option, or delegation in
Spectral,Spectral.OpenAPI,Spectral.TypeInfoorSpectral.Codecis affected.One wrapper improvement is included. An
examplesvalue that does not encode as its own type raises{invalid_example, Type, Term, Errors}from spectra, whichhandle_erlang_error/4previously re-raised as a rawErlangError. 0.14.0 validates examples at every position a type appears in rather than only at entry points, so this error is far more reachable. It is now translated to anArgumentErrornaming the offending example and type, matching how the other spectra errors are handled.Behaviour change to be aware of
Generated JSON Schema and OpenAPI output changes for annotated sub-schemas: nested properties now carry the titles, descriptions, deprecation flags and examples their types declare. Consumers asserting on exact schema output may need updating.
examples_functionis now invoked once per position the type appears in, rather than once per schema, so such functions should stay cheap and free of side effects.Encoding a struct with non-map data now returns
{:error, [%Spectral.Error{type: :type_mismatch}]}(or raisesSpectral.Errorfrom the bang variant) instead of crashing with a rawbadmaperror.Tests
test/spectral_nested_doc_test.exswith two support modules covers:examples_functioncall counts — a fixture counts its own invocations, and a type inlining it twice asserts two calls$refis followed intocomponents.schemasand the nested titles and descriptions asserted theretest/spectral_struct_encode_test.exs(new) locks in the 0.14.1 fix: encoding non-map data against a struct type returns atype_mismatcherror instead of crashing, for bothencode/3andencode!/3.Suite is now 234 tests (20 doctests, 3 properties).
make ciis green: compile with--warnings-as-errors, tests,credo --strict,ex_dna,dialyzer, format check.Docs
README gains a section on annotation propagation, alias merging, the three positions that still do not carry an annotation (all-literal unions, custom-codec types, parameterized types), and the per-position cost of
examples_function. Install instructions and CHANGELOG updated for both the 0.14.0 and 0.14.1 spectra changes.Note
make cover_difffails on this branch, but it fails identically onmainwith spectra 0.13.1: 14 tests error under cover compilation with{:beam_lib_error, :cover_compiled, ...}because cover-compiled modules cannot be read back throughbeam_lib. Not caused by this change.🤖 Generated with Claude Code
https://claude.ai/code/session_01XTMXez4gy2fHp6HgovtfGG