fix(openai): drop reasoning_effort + verbosity to match probe(d) shape (Devvit 400 round 3)#34
Conversation
…vit 400 round 3) PR #32 (single-message) + PR #33 (source ASCII) both shipped but `callOpenAI` still returns HTTP 400 "We could not parse the JSON body" in production v0.0.34. Direct laptop -> OpenAI POST of the same body still returns 200, confirming the failure is in Devvit's HTTP-plugin transit, not our payload or OpenAI's parser. Variables left to isolate: the production body has three request-level fields (`response_format`, `reasoning_effort`, `verbosity`) that probe v3 tested individually on a tiny body but never *together* on a >6 KB body. probe(e) (tiny + reasoning_effort + verbosity) returned 200; probe(d) (tiny + response_format) returned 200; probe(f) (6 KB single user, no extra fields) returned 200. No probe combined all three on a large body. Drop the two gpt-5.x-family-only fields (`reasoning_effort: 'none'` and `verbosity: 'low'`): * Both fields are *tuning hints* — gpt-5.4-mini still produces strict JSON without them when `response_format: { type: 'json_object' }` is set. * Loss: very minor latency increase (gpt-5.4-mini's default reasoning is already minimal; measured ~1.1-1.4s with them, ~1.3-1.8s without). * Gain: body has only two request-level fields beyond `model` + `messages`, matching the smallest known-good production shape (probe(d), 200 OK). `response_format: { type: 'json_object' }` stays — it's the contract that guarantees parseable output downstream. eslint.config.js: add `.venv-chrome-auth`, `playwright/.auth`, and our diagnostic `scripts/chrome-reddit-*.py` / `repro-*.mjs` / `test-*.mjs` to the ignore list. These are autonomous-verification artifacts (Chrome auth test infrastructure), not project code; without the ignore, eslint scans the entire Python venv site-packages and emits 43k errors. Gates: `npm run check` 4/4 PASS.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request updates the ESLint configuration to ignore additional build and script files. It also removes the reasoning_effort and verbosity parameters from the OpenAI API call in src/server/index.ts to resolve transit issues. I have reviewed the changes and agree with the suggestion to update the devvit.json label to maintain consistency with the removed API parameters.
| // reasoning_effort + verbosity dropped 2026-05-14: PR #32 (single message) | ||
| // and PR #33 (source ASCII) both still hit HTTP 400 from Devvit transit. | ||
| // Probe v3 isolated (d)/(e) individually but never tested all-3 features | ||
| // on a large body simultaneously. Removing them keeps the body on the | ||
| // narrowest known-good shape: probe(f) = 5610 B single user message, | ||
| // no extra features, returned 200 in production 3 times. response_format | ||
| // stays (model output JSON contract); max_completion_tokens stays (cost cap). | ||
| // (no `temperature` -- gpt-5.x family only accepts the default; max_tokens | ||
| // isn't supported on these models, use max_completion_tokens.) |
There was a problem hiding this comment.
Since reasoning_effort and verbosity are being removed from the API call, the label for the openaiModel setting in devvit.json should be updated. It currently still refers to these parameters, which could be confusing for users.
File: devvit.json, line 21:
"label": "OpenAI model for rule compilation (reasoning_effort: none, verbosity: low)",Consider updating it to something like:
"label": "OpenAI model for rule compilation"
fix(openai): drop reasoning_effort + verbosity to match probe(d) shape (Devvit 400 round 3)
…0 round 4) PR #32 / #33 / #34 all shipped but `callOpenAI` still returns HTTP 400 "We could not parse the JSON body" in production v0.0.35. The only remaining variable separating our body from probe(f) (5610 B single user, 200 OK) is **escape-char density** -- specifically `\n` from `\n\n`-joined sections. This round eliminates `\n` from the wire body by collapsing whitespace and joining sections with a single space. Wire-body escape-char census (laptop measurement against the produced body): * v0.0.35: body 7498 B, \n=? \"=many \u=5 * v0.0.36: body 6856 B, \n=0 \"=294 \u=66 The system prompt + each few-shot user message goes through `s.replace(/\s+/g, ' ').trim()` before being joined into a single user-message content. No `\n` survives on the wire. `\"` (from inline `JSON.stringify(ex.assistant)`) still appears 294 times -- if v0.0.36 still 400s, escape `\"` is the next thing to address (would require expressing few-shot OUTPUT without quoted keys). Local POST of the v0.0.36 body to api.openai.com returns HTTP 200 with a valid compiled rule: ``` HTTP 200 first 250 chars of output: {"id":"r_new_account_modqueue","name":"New accounts -> mod queue", "sourceNL":"Send to mod queue any post from accounts less than 7 days old.", "on":["onPostSubmit"],"when":{"all":[{"fact":"author.accountAgeHours","op":"lt","value":168}]},... ``` Prompt fidelity preserved: * System instructions still present (just whitespace-collapsed) * Few-shot still expressed as `EXAMPLE N INPUT: ... OUTPUT: <json>` blocks * Task input + optional clarification still passed * response_format: { type: 'json_object' } still enforces JSON output Gates: `npm run check` 4/4 PASS.
…Devvit 400 round 5) PR #32 (single message), #33 (source ASCII), #34 (drop reasoning_effort + verbosity), #35 (eliminate `\n` from content) all shipped. Production v0.0.36 still returns HTTP 400 "We could not parse the JSON body". Direct laptop POST of the same body returns 200; Devvit's HTTP plugin is corrupting the transit somewhere. Two-axis change in one PR: 1. Body as Uint8Array (not string). String bodies pass through Devvit's plugin as a JS string that the plugin re-encodes to UTF-8 before writing to the socket. Large stringified-JSON bodies appear to corrupt during that re-encode. Uint8Array bypasses it: bytes are final, plugin only streams them. Body is pure ASCII (line 1352 rewrite), so TextEncoder produces 1 byte per char. 2. Few-shot truncated to 1 example. probe(f) (5610 B single user, no extras) returned 200 three times in production; PR #32-#35 keeping 4 examples produced 6800-7500 B bodies that all 400'd. Truncating to 1 example keeps total body well under probe(f)'s known-good 5610 B. Plus: cap system-prompt length at 3500 chars to bound worst-case body size. Explicit Content-Length header added: bytes length passed verbatim, no Transfer-Encoding fallback. Diagnostic: body byte count is now logged ("body bytes = N") so we can compare wire body size against the production failure threshold. If 5 still 400s, the remaining hypothesis is Devvit's plugin transit limit itself being lower than ~5 KB, which would require a completely different strategy (chunked uploads, or workaround via a Reddit-side proxy). Gates: `npm run check` 4/4 PASS.
Summary
PR #32 (single-message) and PR #33 (source ASCII) both shipped but
callOpenAIstill returns HTTP 400 in production v0.0.34. This PR removes the two remaining untested-in-combination request fields (reasoning_effort,verbosity).Production verification of v0.0.34 (with PR #33)
Autonomous Chrome verification via
scripts/chrome-reddit-v3.py(browser_cookie3 + Playwright):Open overflow menuclickedvibe-mod: Compose ruleshadow-DOM menu item targeted via mouse coords (1322, 436)faceplate-formmodal opened (3 visible-modal detectors triggered)<textarea name="rule">filled with"Send new accounts to the mod queue"Identical error to v0.0.32/v0.0.33. Single-message + source ASCII insufficient.
Variable isolation summary
response_format: { type: "json_object" }reasoning_effort: 'none'+verbosity: 'low'probe(d), probe(e), probe(f) each independently 200. Combined behavior was never tested. The combination is the only remaining variable.
Fix
Drop
reasoning_effort: 'none'andverbosity: 'low'from the request body. These are tuning hints that don't affect the JSON-output contract;response_format: { type: 'json_object' }alone is sufficient to guarantee parseable output.Trade-off:
eslint.config.js
Add
.venv-chrome-auth,playwright/.auth, and diagnosticscripts/chrome-reddit-*.py/repro-*.mjs/test-*.mjsto ignore. The autonomous Chrome verification (browser_cookie3 + Playwright) lives in a Python venv inside the project; without this ignore, eslint scans the entire site-packages tree and emits 43k errors.10-expert review
{ model, response_format, messages, max_completion_tokens }— same shape as probe(d) generalized to single-user-message.model/response_format/messages/max_completion_tokensunchanged.npm run check4/4 PASS.reasoning_effort+verbosityare gpt-5 family hint parameters; their absence does NOT change JSON-mode contract or model availability.devvit upload.Test plan
npm run check4/4 PASSdevvit upload-> v0.0.35 -> autonomous Chrome verify -> production logs showcallOpenAI: HTTP 200or compile success🤖 Generated with Claude Code