feat(assessment): Persist batch results and deliver them in callback metadata - #1199
feat(assessment): Persist batch results and deliver them in callback metadata#1199vprashrex wants to merge 5 commits into
Conversation
- Callback envelope now carries presigned result-file URLs and the failure reason; both were hardcoded null. - Every provider batch dump is recorded on assessment.result_files, plus an errors.jsonl assembled from run, row and OpenAI error-file failures. - Assessment gets its own assessment_submission table; evaluation_dataset is no longer touched by the assessment domain. - BATCH input takes rows inline or by submission_doc_id, exactly one of the two. - Submission rows move out of Postgres into object storage, loaded only when a stage is submitted. - Legacy cron no longer polls API-created runs, which it corrupted so callbacks never fired; deterministic errors now fail the run instead of looping. - Gemini structured output no longer sends a duplicate ordering key; Anthropic effort and thinking are mapped instead of dropped.
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
OpenAPI changes 🔴 12 breaking changesCaution Downstream consumers may need an update before merging. Breaking changes ·
|
| Method | Path | Change | |
|---|---|---|---|
| 🔴 | GET |
/api/v1/assessment/datasets |
added #/components/schemas/AssessmentSubmissionPreview to the data/anyOf[subschema #1]/items/preview response property anyOf list for the response status 200 |
| 🔴 | GET |
/api/v1/assessment/datasets |
removed the required property data/anyOf[subschema #1]/items/dataset_id from the response with the 200 status |
| 🔴 | GET |
/api/v1/assessment/datasets |
removed the required property data/anyOf[subschema #1]/items/dataset_name from the response with the 200 status |
| 🔴 | POST |
/api/v1/assessment/datasets |
added #/components/schemas/AssessmentSubmissionResponse to the data response property anyOf list for the response status 200 |
| 🔴 | DELETE |
/api/v1/assessment/datasets/{dataset_id} |
for the path request parameter dataset_id, the type/format was changed from integer to string/uuid |
| 🔴 | GET |
/api/v1/assessment/datasets/{dataset_id} |
for the path request parameter dataset_id, the type/format was changed from integer to string/uuid |
| 🔴 | GET |
/api/v1/assessment/datasets/{dataset_id} |
added #/components/schemas/AssessmentSubmissionResponse to the data response property anyOf list for the response status 200 |
| 🔴 | GET |
/api/v1/assessment/runs |
response property data/anyOf[subschema #1]/items/execution/anyOf[subschema #1: RunExecution]/pipeline list-of-types was widened by adding types array to media type application/json of response 200 |
| 🔴 | POST |
/api/v1/assessment/runs |
added the new required request property submission_id |
| 🔴 | GET |
/api/v1/assessment/runs/{run_id} |
response property data/anyOf[subschema #1: AssessmentRunPublic]/execution/anyOf[subschema #1: RunExecution]/pipeline list-of-types was widened by adding types array to media type application/json of response 200 |
| 🔴 | PATCH |
/api/v1/assessment/runs/{run_id}/post-processing |
response property data/anyOf[subschema #1: AssessmentRunPublic]/execution/anyOf[subschema #1: RunExecution]/pipeline list-of-types was widened by adding types array to media type application/json of response 200 |
| 🔴 | POST |
/api/v1/assessment/runs |
removed the request property dataset_id |
Full changelog · 47
| Method | Path | Change | |
|---|---|---|---|
| 🔴 | GET |
/api/v1/assessment/datasets |
added #/components/schemas/AssessmentSubmissionPreview to the data/anyOf[subschema #1]/items/preview response property anyOf list for the response status 200 |
| 🔴 | GET |
/api/v1/assessment/datasets |
removed the required property data/anyOf[subschema #1]/items/dataset_id from the response with the 200 status |
| 🔴 | GET |
/api/v1/assessment/datasets |
removed the required property data/anyOf[subschema #1]/items/dataset_name from the response with the 200 status |
| 🔴 | POST |
/api/v1/assessment/datasets |
added #/components/schemas/AssessmentSubmissionResponse to the data response property anyOf list for the response status 200 |
| 🔴 | DELETE |
/api/v1/assessment/datasets/{dataset_id} |
for the path request parameter dataset_id, the type/format was changed from integer to string/uuid |
| 🔴 | GET |
/api/v1/assessment/datasets/{dataset_id} |
for the path request parameter dataset_id, the type/format was changed from integer to string/uuid |
| 🔴 | GET |
/api/v1/assessment/datasets/{dataset_id} |
added #/components/schemas/AssessmentSubmissionResponse to the data response property anyOf list for the response status 200 |
| 🔴 | GET |
/api/v1/assessment/runs |
response property data/anyOf[subschema #1]/items/execution/anyOf[subschema #1: RunExecution]/pipeline list-of-types was widened by adding types array to media type application/json of response 200 |
| 🔴 | POST |
/api/v1/assessment/runs |
added the new required request property submission_id |
| 🔴 | GET |
/api/v1/assessment/runs/{run_id} |
response property data/anyOf[subschema #1: AssessmentRunPublic]/execution/anyOf[subschema #1: RunExecution]/pipeline list-of-types was widened by adding types array to media type application/json of response 200 |
| 🔴 | PATCH |
/api/v1/assessment/runs/{run_id}/post-processing |
response property data/anyOf[subschema #1: AssessmentRunPublic]/execution/anyOf[subschema #1: RunExecution]/pipeline list-of-types was widened by adding types array to media type application/json of response 200 |
| 🔴 | POST |
/api/v1/assessment/runs |
removed the request property dataset_id |
| 🟢 | — |
— |
removed the schema APIResponse_AssessmentDatasetResponse_ |
| 🟢 | — |
— |
removed the schema APIResponse_list_AssessmentDatasetResponse__ |
| 🟢 | — |
— |
removed the schema AssessmentDatasetPreview |
| 🟢 | — |
— |
removed the schema AssessmentDatasetResponse |
| 🟢 | — |
— |
a breaking change was detected but the version is still 0.5.0 |
| 🟢 | GET |
/api/v1/assessment/datasets |
removed the optional property data/anyOf[subschema #1]/items/file_extension from the response with the 200 status |
| 🟢 | GET |
/api/v1/assessment/datasets |
removed #/components/schemas/AssessmentDatasetPreview from the data/anyOf[subschema #1]/items/preview response property anyOf list for the response status 200 |
| 🟢 | GET |
/api/v1/assessment/datasets |
added the required property data/anyOf[subschema #1]/items/name to the response with the 200 status |
| 🟢 | GET |
/api/v1/assessment/datasets |
added the required property data/anyOf[subschema #1]/items/submission_id to the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/datasets |
removed #/components/schemas/AssessmentDatasetResponse from the data response property anyOf list for the response status 200 |
| 🟢 | GET |
/api/v1/assessment/datasets/{dataset_id} |
removed #/components/schemas/AssessmentDatasetResponse from the data response property anyOf list for the response status 200 |
| 🟢 | POST |
/api/v1/assessment/runs |
added the optional property data/anyOf[subschema #1: AssessmentRunResponse]/submission_id to the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs |
added the optional property data/anyOf[subschema #1: AssessmentRunResponse]/submission_name to the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs |
removed the optional property data/anyOf[subschema #1: AssessmentRunResponse]/dataset_id from the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs |
removed the optional property data/anyOf[subschema #1: AssessmentRunResponse]/dataset_name from the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs/{run_id}/resume |
added the optional property data/anyOf[subschema #1: AssessmentRunResponse]/submission_id to the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs/{run_id}/resume |
added the optional property data/anyOf[subschema #1: AssessmentRunResponse]/submission_name to the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs/{run_id}/resume |
removed the optional property data/anyOf[subschema #1: AssessmentRunResponse]/dataset_id from the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs/{run_id}/resume |
removed the optional property data/anyOf[subschema #1: AssessmentRunResponse]/dataset_name from the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs/{run_id}/retry |
added the optional property data/anyOf[subschema #1: AssessmentRunResponse]/submission_id to the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs/{run_id}/retry |
added the optional property data/anyOf[subschema #1: AssessmentRunResponse]/submission_name to the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs/{run_id}/retry |
removed the optional property data/anyOf[subschema #1: AssessmentRunResponse]/dataset_id from the response with the 200 status |
| 🟢 | POST |
/api/v1/assessment/runs/{run_id}/retry |
removed the optional property data/anyOf[subschema #1: AssessmentRunResponse]/dataset_name from the response with the 200 status |
| 🟢 | POST |
/api/v1/assessments |
added the new optional request property input/anyOf[subschema #2: BatchInput]/submission_doc_id |
| 🟢 | POST |
/api/v1/assessments |
the request property input/anyOf[subschema #2: BatchInput]/data became optional |
| 🟢 | POST |
/api/v1/assessments |
request property input/anyOf[subschema #2: BatchInput]/data list-of-types was widened by adding types null to media type application/json |
| 🟢 | POST |
/api/v1/assessments |
the input/anyOf[subschema #2: BatchInput]/data request property's minItems was unset from 1 |
| 🟢 | POST |
/api/v1/configs |
added the new optional request property config_blob/completion/anyOf[subschema #2: KaapiTextCompletionConfig]/params/thinking |
| 🟢 | POST |
/api/v1/configs |
added the new optional request property config_blob/completion/anyOf[subschema #2: KaapiTextCompletionConfig]/params/thinking_level |
| 🟢 | POST |
/api/v1/llm/call |
added the new optional request property config/blob/anyOf[subschema #1: ConfigBlob]/completion/anyOf[subschema #2: KaapiTextCompletionConfig]/params/thinking |
| 🟢 | POST |
/api/v1/llm/call |
added the new optional request property config/blob/anyOf[subschema #1: ConfigBlob]/completion/anyOf[subschema #2: KaapiTextCompletionConfig]/params/thinking_level |
| 🟢 | POST |
/api/v1/llm/chain |
added the new optional request property blocks/items/config/blob/anyOf[subschema #1: ConfigBlob]/completion/anyOf[subschema #2: KaapiTextCompletionConfig]/params/thinking |
| 🟢 | POST |
/api/v1/llm/chain |
added the new optional request property blocks/items/config/blob/anyOf[subschema #1: ConfigBlob]/completion/anyOf[subschema #2: KaapiTextCompletionConfig]/params/thinking_level |
| 🟢 | POST |
/api/v1/llm/chain/sts |
added the new optional request property rag/anyOf[subschema #1: RAGBlockSpec]/params/anyOf[subschema #1: TextLLMParams]/thinking |
| 🟢 | POST |
/api/v1/llm/chain/sts |
added the new optional request property rag/anyOf[subschema #1: RAGBlockSpec]/params/anyOf[subschema #1: TextLLMParams]/thinking_level |
main ↔ 7eb4778d · generated by oasdiff
Follow-up to the rename: test modules still imported the dataset-era symbols and asserted the old result-file shape, so collection failed.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Patch coverage was below target on the new submission path: the crud, the object-store round trip and the submission_doc_id branch had none.
Patch coverage was below target on the new submission path: the crud, the object-store round trip and the submission_doc_id branch had none.
Issue
Closes #1200
Summary
The BATCH assessment API could finish a paid-for run and leave the client with nothing: the callback inlined every row (413 from the receiver), carried no failure reason, and pointed at no durable copy of the results. Separately, the legacy cron was polling API-created runs and crashing on their differently-shaped state, so those runs never finalised and never fired a callback at all.
This makes the result durable and the callback self-describing, and clears the driver and provider bugs found alongside it.
Major changes
Storage layout restructured
<project.storage_path>/assessment/<assessment_id>/, holdingsubmission.jsonl, per-stageresults.jsonlanderrors.jsonl; uploaded files move toassessment/submissions/<name>.<ext>.Batch results and errors are durable
assessment.result_filesas its stage completes, so results outlive the Celery tick that produced them.errors.jsonlper run, now including OpenAI's error file, which was previously read as a boolean only, so a run with 389 provider failures reportederrors=0.Callback carries the result
metadatanow holds a 24-hour presigned URL per result file anderrorholds the failure reason; both were hardcodednull.Submissions get their own table
assessment_submissiontable;evaluation_datasetmultiplexed four surfaces behind atypecolumn and its name uniqueness ignored that column, so an evaluation dataset name blocked an assessment one.submission_doc_id, and those rows (3-6MB) now live in object storage rather than inline in Postgres.Fixes
json_output_schema.effortandthinkingare mapped instead of silently dropped, so "high effort" is no longer a no-op plus a log warning.RunExecution.pipelineadmits both shapes actually stored in it, so the next mismatch is a type error rather than a runtime crash.Migration
083— newassessment_submissiontable,assessment.result_files/submission_input/submission_id(replacingdataset_id),batch_job.provider_error_file_id. Verified upgrade and downgrade on a throwaway database.Notes
Not in this PR, deferred by decision: retrying a rejected callback, a per-row correlation id in the result, and a
GET /assessments/{id}read path.