# S03: Reply and follow-up drafting from real thread context — UAT **Milestone:** M001 **Written:** 2026-03-24 ## UAT Type - UAT mode: mixed - Why this mode is sufficient: S03 changes both backend draft assembly and the per-job Follow-up workspace, so the right acceptance script combines artifact-backed checks (focused backend/frontend tests and build) with a human review of draft specificity, editability, and the manual-send boundary. ## Preconditions - The API and UI for this worktree are running from `/home/pi/development/JobTracker/.gsd/worktrees/M001`. - A job exists with all of the following: - imported Gmail correspondence tied to the job - recruiter email populated on the company/job - saved tailored CV, cover letter, recruiter message, and/or saved application-answer draft material - The tester can open that job in the job workspace. - No autonomous outbound-email automation is enabled anywhere in the environment. ## Smoke Test Open one seeded job, switch to the **Follow-up** tab, and confirm the tab shows a generated draft plus a visible context panel that names the thread/package grounding rather than only a blank email form. ## Test Cases ### 1. Generate a thread-grounded follow-up draft 1. Open a job that already has imported correspondence and saved application package material. 2. Open the **Follow-up** tab. 3. Wait for the draft to load. 4. Review the context panel above/alongside the draft. 5. **Expected:** - a draft subject and body are generated - the UI shows why the draft was generated now (for example, waiting-update timing) - the UI shows thread/package grounding such as thread subject, latest sender, context summary, or context signals - the draft content feels tied to the actual thread stage and saved package context instead of reading like a generic template ### 2. Edit the draft before sending and verify manual-send behavior 1. In the **Follow-up** tab, edit the generated subject and/or body. 2. Confirm the recipient field is editable or clearly visible before any send action. 3. Verify the helper text/button copy makes the manual-send boundary explicit. 4. Click **Send and log email**. 5. **Expected:** - nothing is sent before the explicit button click - the edited draft text, not the original generated text, is what gets submitted - the workflow behaves like a manual send/log action rather than background automation - there is a clear success state or logged result after submission ### 3. Confirm the sent follow-up reappears in job history/correspondence 1. After sending/logging the follow-up, switch to the job’s correspondence/history surface. 2. Refresh the job workspace if needed. 3. Find the newly logged outbound follow-up entry. 4. **Expected:** - the sent/logged follow-up appears back in the same job timeline/correspondence record - the entry is attached to the correct job and thread context - the app reflects history continuity instead of treating the send as an isolated compose event ## Edge Cases ### Missing package or thin thread context still preserves user control 1. Open a job that has weaker context than the happy path (for example, imported correspondence but little/no saved package material, or saved package material but only a thin thread). 2. Generate a follow-up draft. 3. **Expected:** - the app still returns an editable draft or a clearly explained degraded draft state - the UI reflects missing/limited grounding rather than pretending the draft is strongly informed - the manual-send boundary remains unchanged: no autonomous send occurs, and the user still must explicitly send/log ## Failure Signals - The Follow-up tab loads only a blank compose form with no visible context grounding. - The generated draft ignores obvious thread details (subject, recruiter, recent message content) and reads like a generic reminder. - Editing the draft does not persist into the send/log request. - A follow-up appears to be sent or logged without an explicit user action. - The sent follow-up does not return to the job’s correspondence/history surface. - The tab crashes, build/test regressions appear, or the follow-up endpoint no longer returns the grounding fields expected by the UI. ## Not Proven By This UAT - This UAT does not prove Gmail OAuth/import itself; that was covered by S01 and is only consumed here as prerequisite context. - This UAT does not prove end-to-end milestone coherence across table/dashboard/control-loop surfaces; S04 and S05 still own that broader workflow validation. ## Notes for Tester Use a job with real-looking imported thread content and saved package material; otherwise the quality signal will be too weak to judge whether S03 actually improved grounding. If the environment cannot support live send/log execution, fall back to the focused checks that already passed for this slice: - `$HOME/.dotnet/dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsFollowUpDraftTests` - `CI=true npm --prefix job-tracker-ui test -- --watch=false --runTestsByPath src/job-details-followup-drafts.test.tsx` - `CI=true npm --prefix job-tracker-ui run build`