fix: align Clip + Voice contracts with the live gateway - #48
Conversation
Verified by probing api.wave.online: ClipCreate previously required the
rejected numeric videoId/startTime/endTime shape; the gateway accepts
{ source: "<recording-id>", in: "5s", out: "10s" }. The voice path is
POST /voice (not /voice/generate), requiring only text, and the primary
200 returns raw audio/mpeg bytes.
- ClipCreate: source (recording id string) + in/out relative time strings.
- /voice/generate -> /voice; VoiceGenerateRequest.text required, voiceId
optional (also sent as voice_id).
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_4433be5b-ea99-4ac6-9085-eb4bb1bdfe31) |
|
Warning Review limit reachedNext included review available in 39 minutes. View limit detailsLimit details: You’ve used the included review currently available. Your 91 included PR review attempts over the past 7 days set your current allowance at 1 review per hour. Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Team Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (4)
Comment |
ApprovabilityVerdict: Would Approve Macroscope's review found this PR approvable — This is a focused, author-owned OpenAPI contract correction for the existing Voice endpoint, with synchronized generated types and drift metadata and no production runtime or infrastructure changes. The remaining comments concern unchanged or stale areas and do not establish a concrete blocker for this diff. Not approved because:
Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more. |
PR Summary by QodoFix OpenAPI ClipCreate + Voice endpoints to match live gateway
AI Description
Diagram
High-Level Assessment
Files changed (2)
|
|
Running ultrareview automatically — This PR makes significant changes to the Clip and Voice API contracts—replacing required fields, altering endpoint paths, and updating response types—which risk breaking client integrations if any detail is misaligned with the live gateway.. I'll post findings when complete. |
|
I can't run this ultrareview because your workspace has reached its monthly review limit. cubic has reviewed 100,145 of the 100,000 allowed lines of code this month. Reviews resume on 4 September 2026 (in 25 days). Enable flex capacity to cover overages automatically and resume reviews now. Learn how flex capacity works. To help optimise your usage, you can tune cubic to get the most out of your usage limits:
|
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
Code Review by Qodo
1.
|
Qodo FixerNo findings are within the configured fix scope. To change which findings are fixed, adjust the setting on your Qodo configuration page. |
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
🟢 WAVE BugBot — clearNo confident findings on the changed lines. Local review · $0 inference · wave-dispatch |
Premise verification against the live gateway — the path rename looks backwardsReviewing this for GA criterion CONTRACT-001 / COMPAT-001. CI is fully green (15/15) and the branch is 1.
|
| Probe | Result | Meaning |
|---|---|---|
POST /voice/generate |
401 | mapped |
POST /clips |
401 | mapped |
POST /voice/clone |
401 | mapped |
POST /clips/detect |
500 UPSTREAM_ERROR |
mapped, reached upstream |
POST /voice/voices |
405 | mapped GET-only — correctly rejects POST |
POST /voice |
405 | not mapped |
POST /voice/zzz1 (control) |
405 | not mapped |
POST /clips/zzz2 (control) |
405 | not mapped |
POST /voice/generate2 (control) |
405 | not mapped |
POST /clips/detectx (control) |
405 | not mapped |
11/11 probes reproduce the live spec's method map exactly, including correctly 405-ing the GET-only
/voice/voices. POST /voice groups with the fabricated controls, not with the real routes.
Note the documented server base https://api.wave.online/v1 cannot be probed this way — every /v1/* path,
including fabricated ones, returns a uniform x402 402 payment required that echoes back whatever path you
send. So the 402s carry no route-existence signal; the discriminating surface is the un-prefixed mount, which
returns genuine WAVE error envelopes (UPSTREAM_ERROR, with suggestions) and is therefore a real gateway
surface, not the marketing app.
2. The published live spec contradicts all three changes
curl https://api.wave.online/openapi.json → HTTP 200, 1.0.0, 54 paths / 75 operations:
- path is
/voice/generate, not/voice ClipCreate.required=[videoId, startTime, endTime](numeric), not[source, in, out]VoiceGenerateRequest.required=[voiceId, text], not[text]
Independently corroborated: sdk-python pins tests/fixtures/openapi_snapshot.json captured 2026-09-01
from that same URL — info_version 1.0.0, total_ops 75, and {"operationId":"generateSpeech","method":"POST","path":"/voice/generate"}.
3. origin/main already agrees with live on these three items
origin/main (now 1.1.0, 209 paths / 230 operations) still carries /voice/generate,
ClipCreate.required=[videoId,startTime,endTime], and VoiceGenerateRequest.required=[voiceId,text] —
byte-identical in meaning to what the gateway serves. There is no drift here to remove. As written this PR
would introduce drift on exactly the three items it aims to fix, which is the failure CONTRACT-001 is meant to
catch: an unverified claim laundered into the contract.
4. The branch is also badly stale
Branch spec measures 1.0.0, 43 paths / 62 operations against main's 1.1.0 / 209 / 230. Merge base is
6649096. Git reports no textual conflict, so the rename would apply cleanly onto a file that has since moved
a long way — worth a rebase before any merge regardless of the outcome above.
What would change my read
The PR body says the shapes were "verified today by probing api.wave.online" but carries no attached output.
An authenticated transcript — request line, status, and response body for POST /v1/voice with {text},
plus a POST /v1/clips with {source, in, out} — would settle it, since body validation never runs on my
unauthenticated probes. If the gateway really does accept those shapes behind auth, then the published
openapi.json is the stale artifact and the right fix is to regenerate/repoint it, with this PR rebased on
current main. Happy to re-verify the moment that transcript exists.
Separate finding, not this PR's file
Both SDKs POST to /v1/voice/synthesize (sdk/src/voice.ts:155, sdk-python/wave_sdk/voice.py:29), and
POST /voice/synthesize probes 405 — unmapped, same as the controls. That is a third path, matching
neither the spec nor this PR, and looks like a real COMPAT-001 defect in the SDK repos. Flagging for whoever
owns those; out of scope here.
🤖 Generated with Claude Code
…ice rename + ClipCreate ClipCreate: main independently re-verified this schema against the live gateway since this PR branched, with a more thorough contract (source + in, out/duration alternatives, sourceType, visibility). Keeping mains version; this PRs source/in/out variant is superseded. Voice path rename (/voice/generate -> /voice): dropped. Verified live that the gateways x402 paywall gates on the top-level product path segment for ANY sub-path under /voice/ (including nonexistent ones, e.g. /v1/voice/nonexistent-xyz -> 402), so an unauthenticated probe cannot distinguish /voice from /voice/generate. main already documents /voice/generate; the rename claim is unverifiable, so the path stays. Kept: VoiceGenerateRequest now requires only text (voiceId optional, also accepted as the voice_id wire alias; supplying both is rejected at the schema level), and the /voice/generate 200 response description clarified that audio/mpeg is the default (JSON shapes are opt-in) -- verified live via POST /voice/generate. Added a published-drift shared-drift allowlist entry for this response-description change, keyed on the published documents current (unchanged) description. Regenerated contract-drift.json and generated/api-types.d.ts.
🤖 CodeAnt AI — Review Status
|
Thanks for using CodeAnt! 🎉We're free for open-source projects. if you're enjoying it, help us grow by sharing. Share on X · |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_167ef0b9-ae0a-4a7c-9deb-9773b8947fb1) |
|
ⓘ Qodo reviews are paused because your workspace is out of credits. Ask your workspace admin to add credits to resume reviews. Manage billing |
…ce contract alignment Resolves conflicts from #40 (README), #43 (CI/body-guard), and #48 (Clip/Voice contract alignment) landing ahead of this PR. - CHANGELOG.md: kept both this PR entry (Enhance AI video super-resolution surface) and mains body content-policy gate entry. - contract-drift.json: took mains version then regenerated via published-drift.mjs against the merged openapi.yaml (exit OK, no drift). - generated/api-types.d.ts: regenerated via npm run gen:types against the merged openapi.yaml. - openapi.yaml and README.md merged cleanly with no manual edits needed. Live-verified POST /v1/enhance still returns 402 (x402 challenge, priced wave_enhance_minutes meter) against https://api.wave.online/v1/enhance, confirming the route is live and staying published (not draft).
User description
The api-spec was out of sync with the live gateway (verified today by probing api.wave.online):
ClipCreatepreviously required the rejected numericvideoId/startTime/endTimeshape. The gateway accepts{ source: "<recording-id>", in: "5s", out: "10s" }.POST /voice(not/voice/generate), requiring onlytext(voiceIdoptional, also sent asvoice_id). The primary 200 returns rawaudio/mpegbytes.CHANGELOG updated.
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is enabled.Note
Align Clip and Voice API contracts with live gateway
POST /voice/generatetoPOST /voice; the 200 response now returns rawaudio/mpegbytes by default, with JSON only when opting into timestamps or async engines.ClipCreatenow requiressource,in, andout(relative time strings e.g.5s,2m30s) instead ofvideoId,startTime, andendTime(numeric).VoiceGenerateRequestnow only requirestext;voiceIdandvoice_idare optional snake/camel aliases but mutually exclusive — providing both is invalid./voice/generate, numeric clip times, or passingvoiceIdas required must update.Macroscope summarized 16af177.
Note
Medium Risk
OpenAPI schema changes (
requiredfields and new mutual-exclusion rule) can affect generated clients and strict validators; response docs reorder wire semantics but clarify defaultaudio/mpeg.Overview
This PR narrows an earlier Clip/path-rename proposal:
POST /voice/generatestays, andClipCreateis unchanged (CHANGELOG explains why). The work alignsPOST /voice/generatewith live gateway behavior.The 200 response is documented so raw
audio/mpegis the default;application/json(VoiceSynthesisInline/VoiceGeneration) applies only when the request opts into timestamps or async paths. The OpenAPI content map listsaudio/mpegfirst and the description is rewritten accordingly;generated/api-types.d.tsmirrors that.VoiceGenerateRequestnow requires onlytext.voiceIdis optional (default voice when omitted), andvoice_idis documented as the SDK wire alias, with a schemanotrule rejecting both camel and snake on one body.Published drift adds a
shared-driftallowlist entry for the richer repo 200 description vs the published spec, andcontract-drift.jsonis regenerated (allowlisted count 9 → 10).Reviewed by Cursor Bugbot for commit aaeb252. Bugbot is set up for automated code reviews on this repo. Configure here.
Summary by Sourcery
Align the voice synthesis API specification with the live gateway while retaining the existing endpoint and clip contract.
Bug Fixes:
Enhancements:
Documentation:
Chores:
CodeAnt-AI Description
Align voice generation contracts with the live gateway
What Changed
voiceIdorvoice_id, while rejecting requests that provide bothImpact
✅ Direct MP3 responses by default✅ Voice generation without specifying a voice✅ Clearer validation for conflicting voice IDs💡 Usage Guide
Checking Your Pull Request
Every time you make a pull request, our system automatically looks through it. We check for security issues, mistakes in how you're setting up your infrastructure, and common code problems. We do this to make sure your changes are solid and won't cause any trouble later.
Talking to CodeAnt AI
Got a question or need a hand with something in your pull request? You can easily get in touch with CodeAnt AI right here. Just type the following in a comment on your pull request, and replace "Your question here" with whatever you want to ask:
This lets you have a chat with CodeAnt AI about your pull request, making it easier to understand and improve your code.
Example
Preserve Org Learnings with CodeAnt
You can record team preferences so CodeAnt AI applies them in future reviews. Reply directly to the specific CodeAnt AI suggestion (in the same thread) and replace "Your feedback here" with your input:
This helps CodeAnt AI learn and adapt to your team's coding style and standards.
Example
Retrigger review
Ask CodeAnt AI to review the PR again, by typing:
Check Your Repository Health
To analyze the health of your code repository, visit our dashboard at https://app.codeant.ai. This tool helps you identify potential issues and areas for improvement in your codebase, ensuring your repository maintains high standards of code health.