docs/architecture/test-and-icp.md

Test And ICP Processing

This slice covers manual tests, ICP PDF upload, ICP extraction, corrections, element trends, Reef Review generation, and test-history storage.

ICP Upload And Processing

sequenceDiagram
    participant User
    participant UI as ICPUpload modal
    participant API as REST API Gateway
    participant Pre as upload-presigned
    participant S3 as env-reef-a-matic-upload
    participant Convert as upload-convert
    participant Validate as Extraction validation gate
    participant TestElement as env-test-element
    participant Queue as SQS FIFO env-upload-results.fifo
    participant Eval as corrections-eval-element-test-result
    participant TestHistory as env-test-history
    participant DailyDraft as Shared DailyDoseDraftProgramService
    participant ProgramHistory as env-program-history
    participant ReefReview as env-reef-review
    participant AppConfig as env-app-config
    participant Bedrock as Amazon Bedrock
    participant Feedback as env-program-draft-feedback
    participant WS as WebSocket notifiers

    User->>UI: Select PDF batch and click Upload
    UI->>API: POST /test validateOnly
    API->>Pre: Check subscription allowance before upload
    Pre-->>UI: Allowed or entitlement error
    loop per PDF
        UI->>API: POST /test
        API->>Pre: Create signed upload request
        Pre->>TestHistory: Create PROCESSING placeholder with selected ICP lab brand
        Pre-->>UI: S3 PUT URL + test id
        UI->>S3: PUT PDF bytes
        S3->>Convert: S3 notification
        Convert->>TestHistory: Read placeholder to resolve ICP lab brand
        Convert->>Convert: Extract with Bedrock using selected lab panel and deterministic PDF text overrides
        Convert->>TestHistory: Save IN_PROGRESS ICP row
        Convert->>Validate: Validate metadata, duplicates, and expected tank panel
        Validate->>TestElement: Load source=tank validation_required elements
        alt structurally valid
            Validate->>TestHistory: Add MISSING placeholders in normal categories
            Validate->>Queue: Publish non-RO elements for evaluation
            Queue->>Eval: Event source mapping invokes per element
            Eval->>TestHistory: Categorize, target, recommend, and trend-assess
            Eval->>DailyDraft: Build Pro daily-dose suggestions from active program, ICP history, dose history, and HILT outcomes
            DailyDraft->>ProgramHistory: Create/update draft program when applicable
            Eval->>AppConfig: Load Reef Review prompt templates
            Eval->>Bedrock: Review finding severity guardrails and interpret findings/actions
            Eval->>ReefReview: Create/update guided Reef Review
            Eval->>Feedback: Later receives draft activation edits/outcomes
            Eval->>TestHistory: Mark DONE after expected elements finish
        else invalid extraction
            Validate->>TestHistory: Mark ERROR and persist support reference
        end
        TestHistory->>WS: DynamoDB stream update
        WS-->>UI: Update left nav and detail status
    end

Manual Test And ICP Detail

flowchart LR
    subgraph UI["UI"]
        TESTPAGE["Testing page"]
        ICPPAGE["ICPTest detail"]
        CARD["ParameterWidget element card"]
        TRENDMODAL["Element trend modal"]
        CORRBOX["Correction checkboxes"]
        REVIEW["Reef Review workflow"]
        REVIEWPAGE["ReefReviewPage"]
    end

    subgraph API["REST API Gateway"]
        LISTE["POST /test/elements/list"]
        GETTEST["POST /test/history"]
        SAVETEST["POST /test/history/save"]
        GETICP["POST /test/history/icp"]
        TREND["POST /test/history/icp/trend"]
        APPLY["POST /corrections"]
        REVIEWS["POST /user/reef-reviews"]
    end

    subgraph Lambdas["Lambdas"]
        L_LISTE["test-list-test-elements"]
        L_GETTEST["test-get-test-history"]
        L_SAVETEST["test-save-test-history"]
        L_GETICP["test-get-icp-test-history"]
        L_TREND["test-get-icp-element-trend"]
        L_APPLY["corrections-apply-correction"]
        L_REVIEWS["user-reef-reviews"]
    end

    subgraph Data["DynamoDB + SQS"]
        TESTE["env-test-element"]
        TESTH["env-test-history"]
        DOSEH["env-dose-history"]
        PROGH["env-program-history"]
        CORR["env-element-correction"]
        TARGETOVR["env-element-target-override"]
        REEFREV["env-reef-review"]
        QCORR["env-icp-correction.fifo"]
    end

    subgraph Shared["Shared Common Services"]
        DAILYDRAFT["DailyDoseDraftProgramService"]
        DAILYAI["DailyDoseAiAdvisor"]
    end

    TESTPAGE --> LISTE --> L_LISTE --> TESTE
    TESTPAGE --> GETTEST --> L_GETTEST --> TESTH
    TESTPAGE --> SAVETEST --> L_SAVETEST --> TESTH
    L_SAVETEST --> REEFREV
    ICPPAGE --> GETICP --> L_GETICP --> TESTH
    L_GETICP --> DOSEH
    L_GETICP --> DAILYDRAFT
    DAILYDRAFT --> DAILYAI
    DAILYDRAFT --> PROGH
    CARD --> TRENDMODAL
    TRENDMODAL --> TREND --> L_TREND
    L_TREND --> TESTH
    L_TREND --> DOSEH
    L_TREND --> CORR
    L_TREND --> TARGETOVR
    CORRBOX --> APPLY --> L_APPLY
    L_APPLY --> TESTH
    L_APPLY --> PROGH
    L_APPLY --> QCORR
    L_APPLY --> REEFREV
    REVIEW --> REVIEWS --> L_REVIEWS --> REEFREV
    REVIEWPAGE --> REVIEWS
    ICPPAGE --> REVIEWPAGE
    L_REVIEWS --> TESTH
    L_REVIEWS --> PROGH

ICP Queue Handoff

flowchart LR
    CONVERT["Lambda: upload-convert"] -->|"SendMessage per non-RO element"| Q["SQS FIFO: env-upload-results.fifo"]
    Q -->|"event source mapping batch_size=1"| EVAL["Lambda: corrections-eval-element-test-result"]
    EVAL --> TESTH["DynamoDB: env-test-history"]
    EVAL --> DAILYDRAFT["Shared: DailyDoseDraftProgramService"]
    DAILYDRAFT --> PROGH["DynamoDB: env-program-history draft"]
    EVAL --> APPCFG["DynamoDB: env-app-config prompts"]
    EVAL --> BEDROCK["Amazon Bedrock severity review + interpretation"]
    EVAL --> REEFREV["DynamoDB: env-reef-review"]
    TESTH --> WST["WebSocket: ws-test-history-notify"]
    PROGH --> WSP["WebSocket: ws-program-history-notify"]

Notes

  • POST /test/elements/list returns tank test catalog rows and filters out non-tank reference rows for pickers.
  • ICP extraction stores Osmose/RO rows as ICP result cards in the Osmose category and skips them for corrections/draft generation.
  • Triton can be selected as an ICP lab brand for uploads. That selection is stored on the upload placeholder and used for the extraction/reference panel; it does not enable Triton as a user profile dosing method.
  • Missing expected elements are represented as status=MISSING cards in their normal category so users can investigate.
  • Pro draft generation is owned by the shared DailyDoseDraftProgramService in common. Both upload processing (corrections-eval-element-test-result) and ICP detail reads (test-get-icp-test-history) call the same service so draft recommendations are not dependent on opening the ICP detail page after upload. The service uses DailyDoseAiAdvisor with deterministic guardrails, active program snapshots, selected weekdays, ICP history, dose history, target ranges, and prior draft feedback. Generated drafts preserve nonzero active-program elements and suggested changes, but do not seed zero-dose placeholder elements when there is no active program baseline.
  • Trend chart data is fetched only when the chart icon is clicked. The response includes the active tank target range, which defaults from env-element-correction and is overridden by active version rows in env-element-target-override.
  • Users manage target ranges from Tank Settings through POST /user/target-ranges, which versions custom ranges much like program history by closing the prior active row and creating a new active version.
  • Reef Review storage is exposed through POST /user/reef-reviews with LIST, GET, SAVE, and RECALCULATE actions. Reviews are scoped by user and tank and can reference the source test, selected comparison test, generated draft program, triage findings, recommended actions, and user decisions.
  • When the final ICP element evaluation marks a test complete, corrections-eval-element-test-result creates or updates one review for that ICP. The generated review defaults to the latest three prior completed ICPs for the tank when comparison history exists, captures target/correction findings, creates one-time correction actions, creates per-element daily draft-program adjustment actions when a Pro draft exists, and links the draft program. Daily adjustment actions use explicit draft suggestion metadata when available; for restored or first-draft scenarios without that metadata, Reef Review derives the current value from the latest non-ICP-correction dose history before the source test date so the right-side daily adjustment rail still reflects the generated draft.
  • Reef Review finding severity checks absolute measured value against the available target range before trend stability. This prevents a dangerous value from being shown as stable just because it did not move much between tests. When the source report lacks a target range, deterministic fallback thresholds apply only to explicitly guarded hazards such as high Copper or source guidance that uses hazard language such as toxic/dangerous; the generic Pollutants category alone does not override an acceptable ICP status. After deterministic severity is calculated, a constrained Bedrock severity review can downgrade contextual false positives or add nuance for non-hard-guard findings. Hard safety findings such as high Copper, toxic/danger source text, far-outside target ranges, missing elements, and generated correction actions are clamped so AI cannot silently downgrade them below the deterministic guardrail.
  • Changing the Reef Review compare scope (Last 3, Last 5, Last 10, or All) calls RECALCULATE, selects the comparison test from the chosen lookback scope, regenerates comparison-derived findings/actions, derives daily draft actions from dose-history baselines when needed, and preserves applied/dismissed action state.
  • Each Reef Review finding can carry a trendHistory sequence from the selected prior tests plus the source test so Element Attention mini charts reflect the selected compare scope instead of only previous/current values. Initial upload-time review generation and later RECALCULATE calls both populate this sequence from the requested comparison scope.
  • When a manual test is saved, test-save-test-history creates or updates a lightweight Reef Review if the result is out of the tank target range, has a non-green status, or carries a concerning trend. Manual-test reviews do not create correction checklists or draft programs; they guide the user back to the source test, dose history, and program history.
  • The manual Test History editor uses the same polished command-center visual pattern as Reef Review: source context tiles for date/templates/actions, a guided element board, and fixed-size manual test cards. This keeps manually entered tests visually aligned with the Reef Review 2.0 experience while preserving the same POST /test/history/save backend contract.
  • ICP detail pages use the same polished command-center shell for report context, source facts, and primary Reef Review/draft-program links before showing corrections, daily adjustments, and element group tabs. The redundant legacy overview block is intentionally omitted because the context bar owns report metadata, and element cards use a compact fixed-size presentation so each tab scans consistently.
  • Reef Review AI uses two prompt layers stored in env-app-config. bedrock_prompt_reef_review_severity_review performs a constrained per-finding severity sanity check before persistence, while bedrock_prompt_reef_review_interpretation rewrites human-readable review summary and recommendation text after findings/actions are generated. Deterministic code still owns action type, target ranges, correction amounts, dose amounts, record links, and all hard safety clamps. Both prompt templates auto-seed with default fallbacks if missing.
  • Reef Review action state is synchronized with user workflows. Applying ICP correction checkboxes updates one-time correction action status, activating a generated draft program updates the draft-program action while storing the accepted or overridden values as review decisions, and review-level dismissed/completed timestamps keep active queues distinct from historical reviews. Review reads and recalculations can reconcile one-time correction progress from dose history, but only from ICP-correction dose rows dated on or after the review source test date so older ICP corrections cannot make a newer review appear partially applied. Daily adjustment counts include only draft-program element rows where amount, unit, or selected dosing days actually changed.
  • Reef Review detail GET computes read-time outcome checks from the next completed test for the same tank. Outcomes compare each finding's source measured value against the follow-up measured value and target range so users can see whether the review's concern moved closer to target, stayed on target, or worsened without persisting another table.
  • The dashboard lazy-loads a compact Reef Review summary so open review counts do not block the global app shell, and Element Trends are loaded only after the user asks for them from the landing dashboard. The UI route /reef-review opens the highest-priority review when one exists or shows a structured command-center empty state with ICP Test, Since Last ICP, One-Time Corrections, Daily Adjustments, Review Decisions, and Element Attention placeholders. Reef Review command-center blocks use semantic SVG icon components for the source context, trend, action, and draft-program tiles. The detail route /reef-review/:id presents a Tailwind command-center review with source context, correction actions, daily adjustments, decision timeline, element attention, outcome checks, and links back to the source test and draft program when applicable. Element Attention cards and insight rows open an in-page element detail modal with a larger trend chart, target/status context, recommendation text, and raw trend points instead of navigating away to the general source test. ICP detail pages show an Open Reef Review link when a generated review exists.
  • Pro users receive future projections and advanced dose-response analysis; Basic users see measured history only.