Skip to content

Research: Persist review results to blob storage + wire up ReportStatus.Reviewed #269

@willvelida

Description

@willvelida

Summary

Research and plan blob persistence for report review results in the Chat.Api → Reporting.Api flow. This is Phase 2 of the ReportReviewerService fail-closed fix, to be implemented after the Phase 1 fail-closed PR merges.

Background

Phase 1 (in progress) converts the 3 fail-open paths in ReportReviewerService to a fail-closed "present with warnings" pattern with in-memory caching via IMemoryCache. Phase 2 adds durable persistence so that once a report is reviewed, subsequent CheckReportStatus calls skip re-review entirely by reading persisted review fields from blob metadata.

Research Areas

New Reporting.Api Endpoint

  • PUT /api/reports/{jobId}/review — accepts review result, updates blob metadata
  • Auth: same ChatApiAgent policy (no new auth configuration)
  • Validation: reject if report status is not generated (idempotent first review only)
  • Error responses: 404 (not found), 400 (not in generated status), 401/403 (auth)

ReportMetadata Extension (4 new nullable fields)

  • ReviewedAt (DateTimeOffset?)
  • ReviewApproved (bool?)
  • ReviewConcerns (List<string>?)
  • ValidatedSummary (string?)
  • All nullable for backward compatibility with existing blobs

ReportStatus.Reviewed Wiring

  • ReportStatus.Reviewed constant exists but is never set anywhere in the codebase
  • SubmitReviewAsync should set metadata.Status = ReportStatus.Reviewed
  • Existing switch expressions in ReportEndpoints.cs and ReportGenerationAgent.cs already handle the Reviewed status

Updated Chat.Api Flow

  • "generated" → review + PUT review to Reporting.Api + present result
  • "reviewed" → skip review, present persisted review fields directly
  • Phase 1 in-memory cache retained as defense-in-depth (handles PUT failures)

APIM Impact

  • One new operation resource in infra/apps/reporting-api/main.bicep
  • API-level JWT policy applies to all operations — no policy changes needed

IBlobStorageService Extension

  • New method: Task<ReportMetadata> SubmitReviewAsync(string jobId, bool approved, List<string> concerns, string validatedSummary)
  • Implementation: get metadata → validate status → set review fields + status → upload → return

Estimated Blast Radius

14 files across 3 components:

  • Reporting.Api: 4 modified + 2 created (ReportMetadata, IBlobStorageService, BlobStorageService, Program.cs, ReviewEndpoints.cs, tests)
  • Chat.Api: 4 modified (A2AReportTool, GetReportStatusTool + test files)
  • Infra: 1 modified (reporting-api main.bicep)

Existing Research

Preliminary research is documented in:

  • .copilot-tracking/research/2026-04-12/report-reviewer-fail-closed-research.md (Phase 2 section)
  • .copilot-tracking/research/subagents/2026-04-12/blob-persistence-phase2.md
  • .copilot-tracking/research/subagents/2026-04-12/review-result-persistence.md

Dependency

Blocked on Phase 1 PR (ReportReviewerService fail-closed fix) merging first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions