Part of #645 (approval-outcome prediction epic — read it first for the big picture).
Goal
Expose the prediction on the read side: the query detail endpoint, the review queue list, and a realtime WebSocket event so open pages refresh when a prediction lands. Backend only — the UI is the next sub-issue.
Depends on the core.api sub-issue.
Steps
Copy the AF-624 cost-estimate exposure pattern throughout — it walked exactly this path.
core/api/QueryDetailView.java — add a nested record ApprovalPredictionDetail(UUID id, Double probability, boolean skipped, String skippedReason, boolean failed, Instant createdAt) and a new field. Add a backward-compatible constructor delegating with null, exactly like the existing cost-estimate constructor chain — don't break existing callers.
core/internal/DefaultQueryRequestLookupService.java — populate it via ApprovalPredictionLookupService (see how toCostEstimateDetail joins the estimate).
workflow/internal/web/QueryDetailResponse.java — add an approval_prediction sub-record (snake_case JSON) with a from(...) mapper; null when no row yet (frontend shows "pending").
- Review queue: add nullable
approvalProbability to workflow.api.ReviewService.PendingReview and workflow/internal/web/PendingReviewItem. Populate in workflow/internal/DefaultReviewService with one batch call findByQueryRequestIds(...) over the page of queue items — never a per-row lookup (N+1).
- Realtime: in
realtime/internal/RealtimeEventDispatcher, consume core/events/ApprovalPredictionCompletedEvent → emit query.prediction_complete to the relevant users (mirror the existing query.estimate_complete handler).
- Docs:
docs/04-api-spec.md — add the approval_prediction block to the query-detail response example, the approval_probability field to the review-queue item, and the query.prediction_complete WS event to the events table.
Acceptance criteria
- Updated mapper/unit tests:
QueryDetailResponse mapping (present / null / skipped / failed variants), PendingReviewItem mapping, DefaultReviewService batch-lookup test (verify a single findByQueryRequestIds call), RealtimeEventDispatcher test for the new event.
- Springdoc
@Operation/@ApiResponse annotations remain accurate on touched controllers.
mvn test -Dtest=ApplicationModulesTest and -Dtest=ApiPackageDependencyTest pass.
Part of #645 (approval-outcome prediction epic — read it first for the big picture).
Goal
Expose the prediction on the read side: the query detail endpoint, the review queue list, and a realtime WebSocket event so open pages refresh when a prediction lands. Backend only — the UI is the next sub-issue.
Depends on the core.api sub-issue.
Steps
Copy the AF-624 cost-estimate exposure pattern throughout — it walked exactly this path.
core/api/QueryDetailView.java— add a nested recordApprovalPredictionDetail(UUID id, Double probability, boolean skipped, String skippedReason, boolean failed, Instant createdAt)and a new field. Add a backward-compatible constructor delegating withnull, exactly like the existing cost-estimate constructor chain — don't break existing callers.core/internal/DefaultQueryRequestLookupService.java— populate it viaApprovalPredictionLookupService(see howtoCostEstimateDetailjoins the estimate).workflow/internal/web/QueryDetailResponse.java— add anapproval_predictionsub-record (snake_case JSON) with afrom(...)mapper; null when no row yet (frontend shows "pending").approvalProbabilitytoworkflow.api.ReviewService.PendingReviewandworkflow/internal/web/PendingReviewItem. Populate inworkflow/internal/DefaultReviewServicewith one batch callfindByQueryRequestIds(...)over the page of queue items — never a per-row lookup (N+1).realtime/internal/RealtimeEventDispatcher, consumecore/events/ApprovalPredictionCompletedEvent→ emitquery.prediction_completeto the relevant users (mirror the existingquery.estimate_completehandler).docs/04-api-spec.md— add theapproval_predictionblock to the query-detail response example, theapproval_probabilityfield to the review-queue item, and thequery.prediction_completeWS event to the events table.Acceptance criteria
QueryDetailResponsemapping (present / null / skipped / failed variants),PendingReviewItemmapping,DefaultReviewServicebatch-lookup test (verify a singlefindByQueryRequestIdscall),RealtimeEventDispatchertest for the new event.@Operation/@ApiResponseannotations remain accurate on touched controllers.mvn test -Dtest=ApplicationModulesTestand-Dtest=ApiPackageDependencyTestpass.