Skip to content

0.2.0: full parity with the 2026-08 Fanar spec - #53

Merged
omahjoub merged 1 commit into
mainfrom
spec-update
Aug 6, 2026
Merged

0.2.0: full parity with the 2026-08 Fanar spec#53
omahjoub merged 1 commit into
mainfrom
spec-update

Conversation

@omahjoub

@omahjoub omahjoub commented Aug 6, 2026

Copy link
Copy Markdown
Owner

Summary

  • The Fanar API moved: the 2026-08-05 spec (refreshed api-spec/openapi.json, normative + new api-spec/openapi.yaml twin) added capabilities the SDK didn't model — madhab-aware Fanar-Sadiq-2, persona, streamed (stream) and emotional (with_emotion) TTS, a rich voice catalogue, image prompt revision (revise/revised/revised_prompt), and a 499 client_closed_request error on every endpoint. This PR brings core, both codecs, and the Spring AI adapters to full parity. Plan and status: docs/PROJECT_STATE.md.
  • It also lands the refactors this work surfaced: ExceptionMapper now routes by the error envelope's typed code with HTTP-status fallback (ADR-006 amendment (docs/adr/006-unchecked-exception-hierarchy.md)) — fixing a latent bug where 499s were retried as server errors, making FanarQuotaExceededException reachable, and no longer mapping every 400 to content-filter. FanarTextToSpeechModel.stream(...) now streams real chunks instead of a single-element Flux (ADR-023 (docs/adr/023-streaming-tts-via-flow-publisher.md)), and Fanar-only knobs are reachable from Spring AI via FanarChatOptions / FanarTextToSpeechOptions / FanarImageOptions (ADR-024 (docs/adr/024-spring-ai-vendor-options.md)).
  • Three pre-1.0 breaking changes, allowed by ADR-019 (docs/adr/019-pre-10-stability-policy.md) and documented in CHANGELOG.md — migration notes below.

Type of change

  • Bug fix
  • New feature / capability
  • New module
  • Refactoring (no behavior change)
  • Breaking change
  • Documentation / tooling / CI only

Breaking changes (pre-1.0, ADR-019)

  1. FanarClientException gained a ninth permitted subtype (FanarClientClosedRequestException). Exhaustive switches over its leaves need a new case; switches over the four top-level FanarException branches compile unchanged, and the new type is correctly non-retryable.
  2. VoiceResponse.voices() is now List (was List), and the listing now always includes the built-in public voices. Migration: voice.name() where the raw string was used.
  3. ImageGenerationItem is now (String b64Json, boolean revised, String revisedPrompt) (was single-component), matching the spec's now-required response fields.

Test plan

  • mvn verify passes locally — full 14-module reactor, JaCoCo 100 % on all five counters, dependency:analyze strict, doclint
  • Live tests run against the real Fanar API (2026-08-06). Three findings, each resolved in this PR:
    • /v1/models is visibility-scoped (gated models omitted per key) — LiveModelsTest now exempts MODEL_GATED
    • Fanar-Diwan works now but nondeterministically 422s "No suitable verses found" on identical requests — LivePoemsTest retries only that exception (3×); everything else still fails loudly
    • Fanar-Sadiq-2 gate answers 422 "Model not authorized" (not 403) — §2.6 stays red by design until the key is upgraded; caveats corrected. The madhab wire format is accepted up to the gate, and §2.5 (persona) passes live.
  • GraalVM --self-test — runs via the PR-time native-smoke workflow (reachability edits: ChatRequest 31→33 accessors, AvailableVoice entry, TTS/images updates, plus the previously-missing SpeechToTextResponseDeserializer entries in both codec metadata files)

Reviewer checklist

  • Public API changes are intentional, documented in javadoc, and an ADR was added/updated if the design changed
  • Breaking changes carry @Deprecated(since, forRemoval = true) and a migration path in the PR description
  • BOM updated if modules were added or removed
  • No third-party types leak into qa.fanar.core public API
  • If a non-obvious project decision was made, capture it in memory/ so future contributors find it

@omahjoub
omahjoub merged commit 115769e into main Aug 6, 2026
5 checks passed
@omahjoub
omahjoub deleted the spec-update branch August 6, 2026 12:40
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