Repository navigation
Fix schema constraint loss in json_schema_updater.py recursive_update() #3095
Description
What happened
PR #3093 regenerated developer documentation. CodeRabbit's review found that the generated docs/user_doc/config.json schema diverges from runtime Pydantic validators in two ways: (1) streaming_output_check_interval_tokens (a PositiveInt field, valid values ≥ 1) was emitted as minimum: 0, allowing zero; (2) AllowedModel.model_type (typed as Optional[Literal["llm", "embedding", "rerank"]]) was emitted as bare type: string with no enum constraint. Both inaccuracies are pre-existing, introduced by the recursive_update() function in src/utils/json_schema_updater.py which transforms Pydantic-generated JSON Schema into OpenAPI 3.0.
What could go better
The recursive_update() function has two bugs that silently drop schema constraints:
-
exclusiveMinimumconversion (line 52-53): Pydantic v2 emits{"exclusiveMinimum": 0}forPositiveInt(meaning value > 0). The function rewrites this to{"minimum": 0}(meaning value ≥ 0), losing the exclusive semantics. For OpenAPI 3.0, the correct output is{"minimum": 0, "exclusiveMinimum": true}or equivalently{"minimum": 1}for integer types. -
anyOfnullable handling (lines 36-49): When convertinganyOf: [{type, enum, format, ...}, {type: null}]to a nullable type, the function extracts onlyvalue[0]["type"]and discards all other constraints (enum,format,maxLength,items, etc.). This is whyLiteralenums and array item types are lost in the generated schema.
The existing unit tests in tests/unit/utils/test_json_schema_updater.py encode the incorrect behavior as expected — e.g., test_exclusive_minimum_handling_zero_value asserts that exclusiveMinimum: 0 becomes minimum: 0, and test_anyof_with_additional_fields_on_first_item asserts that format and maxLength are dropped.
Confidence: High. The bugs are visible in the source code and confirmed by the test expectations matching the observed schema output.
Proposed change
Fix both bugs in src/utils/json_schema_updater.py::recursive_update():
-
exclusiveMinimum: Change the conversion fromnew["minimum"] = valuetonew["minimum"] = value; new["exclusiveMinimum"] = True(OpenAPI 3.0 style), which correctly encodes "strictly greater thanvalue". -
anyOfnullable: After extractingval = value[0]["type"], copy all remaining keys fromvalue[0]intonew(e.g.,enum,format,maxLength,items,$ref). Something like:
for k, v in value[0].items():
if k != "type":
new[k] = recursive_update(v) if isinstance(v, dict) else v-
Update unit tests to assert the corrected behavior:
exclusiveMinimum: 0→{"minimum": 0, "exclusiveMinimum": true}; nullable types preserveenum,format,maxLength, etc. -
Regenerate all doc artifacts (
uv run make generate-documentation) to propagate the fixes todocs/user_doc/config.json,docs/models/requests.json, etc.
Validation criteria
After the fix: (1) docs/user_doc/config.json should show streaming_output_check_interval_tokens with "minimum": 0, "exclusiveMinimum": true or "minimum": 1. (2) AllowedModel.model_type schema should include "enum": ["llm", "embedding", "rerank"]. (3) All existing unit tests pass after updating expectations. (4) uv run make verify passes.
Related issues checked
Searched: PositiveInt schema minimum; config schema generation accuracy; openapi schema accuracy validation; json_schema_updater exclusiveMinimum anyOf constraint loss
No overlapping issues found.
Generated by retro agent from #3093
Activity
coderabbitai commentedon Nov 1, 2026
🔗 Related PRs
#3093 - LCORE-4923: Updated devel documentation [closed]
📝 Issue Planner
Check the box below or use the
@coderabbitai plancommand to generate an implementation plan and prompts that you can use with your favorite coding assistant.🧪 Issue enrichment is currently in open beta.
You can configure auto-planning by selecting labels in the issue_enrichment configuration.
To disable automatic issue enrichment, add the following to your
.coderabbit.yaml:💬 Have feedback or questions? Drop into our discord!
fullsend-ai-triage commentedon Nov 1, 2026
🤖 Finished Triage · ✅ Success · Started 12:22 PM UTC · Completed 12:27 PM UTC
Commit:
7850c3c· View workflow run →Runtime: pi · Model: opus → claude-opus-4-6 · Effort: high · Cost: $1.01
fullsend-ai-triage commentedon Nov 1, 2026
Proposed test case
After fixing, regenerate doc artifacts with
uv run make generate-documentationand verify the generated schemas reflect the corrected constraints.Next steps:
/fs-code— agent creates a PR to implement this issue/fs-code <your instruction>— agent implements with your specific guidancefullsend-ai-coder commentedon Nov 1, 2026
🤖 Finished Code · ✅ Success · Started 12:28 PM UTC · Completed 12:37 PM UTC
Commit:
7850c3c· View workflow run →Runtime: pi · Model: opus → claude-opus-4-6 · Effort: high · Cost: $1.92