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
endManual 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 --> PROGHICP 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/listreturns 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
Osmosecategory 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=MISSINGcards in their normal category so users can investigate. - Pro draft generation is owned by the shared
DailyDoseDraftProgramServiceincommon. 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 usesDailyDoseAiAdvisorwith 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-correctionand is overridden by active version rows inenv-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-reviewswithLIST,GET,SAVE, andRECALCULATEactions. 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-resultcreates 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, orAll) callsRECALCULATE, 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
trendHistorysequence 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 laterRECALCULATEcalls both populate this sequence from the requested comparison scope. - When a manual test is saved,
test-save-test-historycreates 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/savebackend 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_reviewperforms a constrained per-finding severity sanity check before persistence, whilebedrock_prompt_reef_review_interpretationrewrites 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-reviewopens 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/:idpresents 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 anOpen Reef Reviewlink when a generated review exists. - Pro users receive future projections and advanced dose-response analysis; Basic users see measured history only.