From aa325ac7ba15f6cc3d53d46080cd3921e09eb50c Mon Sep 17 00:00:00 2001 From: cesnimda Date: Tue, 24 Mar 2026 14:42:09 +0100 Subject: [PATCH] chore(M001/S05): auto-commit after complete-slice --- .gsd/DECISIONS.md | 1 + .gsd/KNOWLEDGE.md | 1 + .gsd/PROJECT.md | 4 +- .gsd/REQUIREMENTS.md | 30 +- .gsd/journal/2026-03-24.jsonl | 4 + .gsd/milestones/M001/M001-ROADMAP.md | 2 +- .../milestones/M001/slices/S05/S05-SUMMARY.md | 118 ++++++++ .gsd/milestones/M001/slices/S05/S05-UAT.md | 280 ++++++++++++++---- .../M001/slices/S05/tasks/T02-VERIFY.json | 25 ++ 9 files changed, 385 insertions(+), 80 deletions(-) create mode 100644 .gsd/milestones/M001/slices/S05/S05-SUMMARY.md create mode 100644 .gsd/milestones/M001/slices/S05/tasks/T02-VERIFY.json diff --git a/.gsd/DECISIONS.md b/.gsd/DECISIONS.md index 87625f8..43eaa4c 100644 --- a/.gsd/DECISIONS.md +++ b/.gsd/DECISIONS.md @@ -17,3 +17,4 @@ | D009 | M001/S01 closure | gmail-matching | Where Gmail candidate aggregation and ranking logic should live for job-aware import | Keep Gmail query-hit aggregation, dedupe, matched-query traces, and ranking reasons in the backend contract instead of recreating that logic in the React workspace. | The correspondence workspace needs explanatory candidate ranking plus duplicate visibility, and putting the logic in the API keeps one source of truth for scoring/import state while preventing browser-side heuristic drift. | Yes | agent | | D010 | M001/S03 closeout | followup-drafting | How follow-up grounding should be exposed to the workspace | Return explicit follow-up grounding fields (`contextSummary`, `contextSignals`, `threadSubject`, and last-correspondence metadata) from the backend DTO instead of making the React workspace infer them client-side. | The slice needed draft trust, not just draft text. Putting grounding signals in the API contract gives the UI a durable explanation surface, keeps thread/package inference in one place with generation logic, and makes backend/frontend tests assert the same source of truth. | Yes | agent | | D011 | M001/S05 planning | workflow-trust | How S05 should represent daily-loop readiness and next-action state across overview surfaces | Introduce explicit workflow trust/action signals from the backend/UI contract and reuse them across the table, dashboard, reminders, and shared workspace instead of continuing to infer behavior from free-form `followUpReason` strings or raw `notes` presence in each component. | S05 is an end-to-end polish slice where the remaining risk is fragmented trust, not missing subsystems. Centralizing workflow signals avoids heuristic drift between overview surfaces, respects the saved application-answer notes-block constraint, and gives the final integrated regression one source of truth for R010 while preserving the explicit manual-send boundary required by R008. | Yes | agent | +| D012 | M001/S05 | workspace-observability | Where linked Gmail thread continuity status should be exposed in the final trust loop | Show linked-thread refresh state directly in the correspondence workspace, including linked thread count and last refresh outcome, instead of hiding continuity feedback inside the Gmail import modal only. | The end-to-end trust loop depends on users being able to verify that already-linked Gmail threads stay current without re-importing. Surfacing continuity state in the main workspace keeps the job timeline trustworthy, supports final UAT, and avoids making thread refresh feel like a hidden one-off import behavior. | Yes | agent | diff --git a/.gsd/KNOWLEDGE.md b/.gsd/KNOWLEDGE.md index ee82ec2..e8d350c 100644 --- a/.gsd/KNOWLEDGE.md +++ b/.gsd/KNOWLEDGE.md @@ -6,3 +6,4 @@ - `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsApplicationPackageTests` is now a trustworthy direct verification command in this worktree for package-generation and notes-replacement behavior; prefer it over older isolated-harness guidance when checking S02 regressions. - `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsFollowUpDraftTests` is now trustworthy again in this worktree after restoring the missing ASP.NET Core / Identity / xUnit test-project references in `JobTrackerApi.Tests/JobTrackerApi.Tests.csproj`; older task notes that require an isolated Docker harness are stale. - Running `npm --prefix job-tracker-ui start` alone is not enough for browser UAT in this worktree: the frontend calls `http://localhost:5202/api/...`, so without the backend (or a matching CORS/proxy setup) the UI loads but shows empty-state surfaces with `net::ERR_FAILED`/CORS errors instead of real job data. +- In this CRA frontend, `react-scripts` resolves the app directory from the current working directory. Run UI tests/builds from `job-tracker-ui/` (for example `cd job-tracker-ui && CI=true ./node_modules/.bin/react-scripts ...`) instead of invoking `npm --prefix job-tracker-ui ...` from the repo root, or `react-scripts` may fail looking for a root-level `package.json`. diff --git a/.gsd/PROJECT.md b/.gsd/PROJECT.md index 9ef6747..790ccfa 100644 --- a/.gsd/PROJECT.md +++ b/.gsd/PROJECT.md @@ -10,7 +10,7 @@ The product must let one person run a real job search without losing the thread: ## Current State -A substantial brownfield app already exists. The repo has a React frontend, an ASP.NET Core API, and a local FastAPI AI service. Current capabilities already include job tracking, companies, attachments, correspondence, reminders, job import preview, Gmail connection/import, profile CV upload/parsing/rewrite flows, AI-assisted tailored CV and cover-letter generation, candidate-fit/focus-plan/interview-prep/readiness endpoints, and dashboard/system surfaces. S01 is complete: the Gmail workspace is job-aware, backend ranking happens server-side, Gmail imports persist thread/from/to metadata, duplicate-safe single-message and thread imports are explicit, and already-linked Gmail threads refresh back into the same job automatically via a bounded `ExternalThreadId` pull. S02 is complete: backend package generation consumes imported correspondence plus recruiter/job state, and the Tailored CV tab treats tailored CV, cover letter, recruiter message, and saved application-answer material as one editable workspace tied back to the job instead of a throwaway preview pane. S03 is now complete as well: follow-up drafting reuses imported correspondence plus saved package material, the Follow-up tab shows why the draft was generated and what thread/package context informed it, and the user must still manually send/log any outbound message. The next planned phase is S04, which will reconnect the daily control loop through the table/dashboard surfaces before S05 re-validates the end-to-end trust loop. +A substantial brownfield app already exists. The repo has a React frontend, an ASP.NET Core API, and a local FastAPI AI service. Current capabilities already include job tracking, companies, attachments, correspondence, reminders, job import preview, Gmail connection/import, profile CV upload/parsing/rewrite flows, AI-assisted tailored CV and cover-letter generation, candidate-fit/focus-plan/interview-prep/readiness endpoints, and dashboard/system surfaces. M001 is now complete across S01-S05: the Gmail workspace is job-aware, backend ranking happens server-side, Gmail imports persist thread/from/to metadata, duplicate-safe single-message and thread imports are explicit, already-linked Gmail threads refresh back into the same job automatically via a bounded `ExternalThreadId` pull, the Tailored CV workspace persists reusable package material, follow-up drafting reuses imported correspondence plus saved package context, and `/jobs`, `/dashboard`, and `/reminders` now share one workflow-signal contract that routes into the same job workspace semantics. S05 finished the trust-loop polish by centralizing workflow trust/action metadata, surfacing linked-thread continuity state directly in the workspace, and adding an integrated regression that proves overview entry → package reuse → Gmail continuity → grounded follow-up drafting without crossing the manual-send boundary. The next planned milestone is M002, which can build on this coherent single-user loop rather than re-solving Gmail/package continuity. ## Architecture / Key Patterns @@ -22,7 +22,7 @@ See `.gsd/REQUIREMENTS.md` for the explicit capability contract, requirement sta ## Milestone Sequence -- [ ] M001: Gmail and draft quality loop — Make Gmail import and AI drafting strong enough to trust as a daily workflow, including whole-thread Gmail continuity after import. +- [x] M001: Gmail and draft quality loop — Make Gmail import and AI drafting strong enough to trust as a daily workflow, including whole-thread Gmail continuity after import. - [ ] M002: Tracking control center — Strengthen the job table, follow-up surfaces, and tracking rhythm into a clearer control center. - [ ] M003: Deeper inbox-aware assistance — Extend correspondence awareness and context-driven assistance beyond the first Gmail improvements. - [ ] M004: Trust, launchability, and hardening — Polish validation, clarity, performance, and operational trust surfaces for sustained daily use. diff --git a/.gsd/REQUIREMENTS.md b/.gsd/REQUIREMENTS.md index b6cfc52..c3ba9ea 100644 --- a/.gsd/REQUIREMENTS.md +++ b/.gsd/REQUIREMENTS.md @@ -26,17 +26,6 @@ This file is the explicit capability and coverage contract for the project. - Validation: mapped - Notes: Shared/team workflows are not the current product target. -### R010 — The app must preserve a coherent history across manual status changes, imported Gmail correspondence, linked-thread updates, reminders, and follow-up work. -- Class: continuity -- Status: active -- Description: The app must preserve a coherent history across manual status changes, imported Gmail correspondence, linked-thread updates, reminders, and follow-up work. -- Why it matters: The product promise is to keep the thread of the job search intact over time, including new Gmail replies that happen after the first import. -- Source: user -- Primary owning slice: M001/S04 -- Supporting slices: M001/S01, M001/S03, M001/S05 -- Validation: mapped -- Notes: This now explicitly includes automatic continuity for already-linked Gmail threads so the correspondence timeline does not become a stale snapshot. - ## Validated ### R001 — The user finds a job outside the app, imports it into the app, and starts the application workflow from that imported role. @@ -116,6 +105,17 @@ This file is the explicit capability and coverage contract for the project. - Validation: Validated by M001/S03 and M001/S04: the per-job workspace now supports imported correspondence review, package drafting, follow-up drafting, and routed entry from overview surfaces, with focused tests and browser verification covering package and follow-up loops. - Notes: S01-S04 now make the individual job workspace the real execution surface for import, drafting, and follow-up work. The reopened Gmail continuity work extends what that correspondence review surface must keep current over time. +### R010 — The app must preserve a coherent history across manual status changes, imported Gmail correspondence, linked-thread updates, reminders, and follow-up work. +- Class: continuity +- Status: validated +- Description: The app must preserve a coherent history across manual status changes, imported Gmail correspondence, linked-thread updates, reminders, and follow-up work. +- Why it matters: The product promise is to keep the thread of the job search intact over time, including new Gmail replies that happen after the first import. +- Source: user +- Primary owning slice: M001/S04 +- Supporting slices: M001/S01, M001/S03, M001/S05 +- Validation: Validated by M001/S05: `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsWorkflowSignalsTests` proves backend reminders/readiness return normalized workflow trust signals, `CI=true ./node_modules/.bin/react-scripts test --watch=false --runTestsByPath src/workflow-trust-signals.test.tsx src/end-to-end-trust-loop.test.tsx src/correspondence-gmail-import.test.tsx src/job-details-generated-drafts.test.tsx src/job-details-followup-drafts.test.tsx src/daily-control-loop.test.tsx` proves `/jobs`, `/dashboard`, and `/reminders` route into the same workspace semantics while preserving saved package reuse, linked-thread continuity, and grounded follow-up drafting, and `CI=true ./node_modules/.bin/react-scripts build` confirms the integrated UI ships as one coherent loop. +- Notes: S05 centralized workflow signals in `job-tracker-ui/src/jobWorkflowSignals.ts`, re-proved linked Gmail continuity in the shared workspace, and added an integrated trust-loop regression so coherence no longer depends on per-surface string heuristics. + ## Deferred ### R011 — The app should later expand overview analytics, saved views, and clearer strategy readouts beyond the core daily loop. @@ -210,7 +210,7 @@ This file is the explicit capability and coverage contract for the project. | R007 | core-capability | validated | M001/S03 | M001/S02, M001/S04 | Validated by M001/S03 and M001/S04: the per-job workspace now supports imported correspondence review, package drafting, follow-up drafting, and routed entry from overview surfaces, with focused tests and browser verification covering package and follow-up loops. | | R008 | constraint | active | M001/S03 | M001/S05 | Constrained by S03 follow-up tests and workspace UX: focused backend/frontend verification proves drafting uses context while outbound follow-up still requires an explicit manual send/log action. | | R009 | constraint | active | M001/S04 | M002/S01, M004/S01 | mapped | -| R010 | continuity | active | M001/S04 | M001/S01, M001/S03, M001/S05 | mapped | +| R010 | continuity | validated | M001/S04 | M001/S01, M001/S03, M001/S05 | Validated by M001/S05: `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsWorkflowSignalsTests` proves backend reminders/readiness return normalized workflow trust signals, `CI=true ./node_modules/.bin/react-scripts test --watch=false --runTestsByPath src/workflow-trust-signals.test.tsx src/end-to-end-trust-loop.test.tsx src/correspondence-gmail-import.test.tsx src/job-details-generated-drafts.test.tsx src/job-details-followup-drafts.test.tsx src/daily-control-loop.test.tsx` proves `/jobs`, `/dashboard`, and `/reminders` route into the same workspace semantics while preserving saved package reuse, linked-thread continuity, and grounded follow-up drafting, and `CI=true ./node_modules/.bin/react-scripts build` confirms the integrated UI ships as one coherent loop. | | R011 | operability | deferred | M002/S02 | none | unmapped | | R012 | integration | deferred | M003/S01 | none | unmapped | | R013 | differentiator | deferred | M003/S02 | none | unmapped | @@ -221,7 +221,7 @@ This file is the explicit capability and coverage contract for the project. ## Coverage Summary -- Active requirements: 3 -- Mapped to slices: 3 -- Validated: 7 (R001, R002, R003, R004, R005, R006, R007) +- Active requirements: 2 +- Mapped to slices: 2 +- Validated: 8 (R001, R002, R003, R004, R005, R006, R007, R010) - Unmapped active requirements: 0 diff --git a/.gsd/journal/2026-03-24.jsonl b/.gsd/journal/2026-03-24.jsonl index 9f3a260..e0962c3 100644 --- a/.gsd/journal/2026-03-24.jsonl +++ b/.gsd/journal/2026-03-24.jsonl @@ -85,3 +85,7 @@ {"ts":"2026-03-24T13:28:41.701Z","flowId":"e3a17c2a-1e81-4cd3-982a-05e166ddb465","seq":2,"eventType":"dispatch-match","rule":"executing → execute-task","data":{"unitType":"execute-task","unitId":"M001/S05/T02"}} {"ts":"2026-03-24T13:28:41.708Z","flowId":"e3a17c2a-1e81-4cd3-982a-05e166ddb465","seq":3,"eventType":"unit-start","data":{"unitType":"execute-task","unitId":"M001/S05/T02"}} {"ts":"2026-03-24T13:36:46.139Z","flowId":"e3a17c2a-1e81-4cd3-982a-05e166ddb465","seq":4,"eventType":"unit-end","data":{"unitType":"execute-task","unitId":"M001/S05/T02","status":"completed","artifactVerified":true},"causedBy":{"flowId":"e3a17c2a-1e81-4cd3-982a-05e166ddb465","seq":3}} +{"ts":"2026-03-24T13:36:46.544Z","flowId":"8a0208a5-1128-4bfe-ae92-18c403ed59b0","seq":1,"eventType":"iteration-start","data":{"iteration":4}} +{"ts":"2026-03-24T13:36:46.634Z","flowId":"8a0208a5-1128-4bfe-ae92-18c403ed59b0","seq":2,"eventType":"dispatch-match","rule":"summarizing → complete-slice","data":{"unitType":"complete-slice","unitId":"M001/S05"}} +{"ts":"2026-03-24T13:36:46.641Z","flowId":"8a0208a5-1128-4bfe-ae92-18c403ed59b0","seq":3,"eventType":"unit-start","data":{"unitType":"complete-slice","unitId":"M001/S05"}} +{"ts":"2026-03-24T13:42:09.837Z","flowId":"8a0208a5-1128-4bfe-ae92-18c403ed59b0","seq":4,"eventType":"unit-end","data":{"unitType":"complete-slice","unitId":"M001/S05","status":"completed","artifactVerified":true},"causedBy":{"flowId":"8a0208a5-1128-4bfe-ae92-18c403ed59b0","seq":3}} diff --git a/.gsd/milestones/M001/M001-ROADMAP.md b/.gsd/milestones/M001/M001-ROADMAP.md index f4ebc00..a409c98 100644 --- a/.gsd/milestones/M001/M001-ROADMAP.md +++ b/.gsd/milestones/M001/M001-ROADMAP.md @@ -64,7 +64,7 @@ This milestone is complete only when all are true: - [x] **S04: Daily control loop surfaces** `risk:medium` `depends:[S01,S03]` > After this: The job table works as the primary overview and the follow-up/dashboard surfaces clearly show what needs attention next for an individual user. -- [ ] **S05: End-to-end trust and workflow polish** `risk:low` `depends:[S01,S02,S03,S04]` +- [x] **S05: End-to-end trust and workflow polish** `risk:low` `depends:[S01,S02,S03,S04]` > After this: The full loop works cleanly in a real environment: import job → generate package → apply externally → import/update correspondence automatically from linked Gmail threads → draft follow-up/reply → track progress confidently. ## Boundary Map diff --git a/.gsd/milestones/M001/slices/S05/S05-SUMMARY.md b/.gsd/milestones/M001/slices/S05/S05-SUMMARY.md new file mode 100644 index 0000000..938e48a --- /dev/null +++ b/.gsd/milestones/M001/slices/S05/S05-SUMMARY.md @@ -0,0 +1,118 @@ +# S05 Summary — End-to-end trust and workflow polish + +## Slice Outcome + +S05 completed the final trust-loop assembly for M001. The slice did not add a second workflow; it tightened the existing one so `/jobs`, `/dashboard`, `/reminders`, and the job workspace now describe the same next action, reuse the same saved package state, expose Gmail linked-thread continuity clearly, and keep follow-up drafting separate from any outbound send action. + +In practice, this slice turned the milestone from a set of individually working subsystems into one coherent daily-use loop: + +- overview surfaces route into the same workspace semantics +- saved package material is treated as explicit reusable workflow state +- linked Gmail thread refresh is visible in the workspace instead of hidden behind import-only UI +- grounded follow-up drafting remains available without crossing the manual-send boundary + +## What This Slice Actually Delivered + +### 1. Shared workflow trust/action model + +S05 centralized workflow trust signals across backend DTOs and frontend routing helpers so overview surfaces no longer guess from free-form `followUpReason` text or raw `notes` presence. + +Delivered pattern: + +- backend reminders/readiness return normalized `workflowSignal` metadata +- frontend consumes that contract through `job-tracker-ui/src/jobWorkflowSignals.ts` +- `JobTable`, `DashboardView`, and `RemindersView` route from the same source of truth into the existing `/jobs?open=...&tab=...` workspace entry model + +This is the main coherence pattern future slices should preserve: if a new daily-loop surface needs a next action, it should consume `workflowSignal`, not invent another heuristic. + +### 2. Explicit saved-package trust in the workspace + +The Tailored CV workspace now makes the saved-package chain obvious: + +- tailored CV, cover letter, application answer, and recruiter message each show save state +- the UI explicitly says saved package material feeds follow-up drafting +- the saved working-material panel shows what later workflow steps can trust and reuse + +This matters because S02 already established package persistence, but S05 made that persistence legible as workflow state rather than hidden implementation detail. + +### 3. Visible Gmail continuity state in the correspondence workspace + +S05 surfaced linked-thread continuity directly in `Correspondence.tsx`. + +The workspace now shows: + +- Gmail connection state +- linked-thread count +- explicit linked-thread refresh action +- last refresh outcome + +That makes the S01 continuity work inspectable in the same workspace where the user reviews correspondence, rather than requiring them to infer freshness from the Gmail import modal alone. + +### 4. Integrated trust-loop regression + +S05 added `job-tracker-ui/src/end-to-end-trust-loop.test.tsx` as the integrated proof for the slice. The test starts from an overview entry point and verifies the assembled path in one place: + +1. open the job from an overview action +2. confirm saved package material is already present +3. confirm linked-thread refresh updates correspondence without re-importing the thread +4. confirm the follow-up draft is grounded in saved package + correspondence context +5. confirm drafting/regeneration does not trigger send behavior + +This is now the best single regression to read when future work risks breaking the milestone’s core loop. + +## Patterns Established + +- **Workflow actions come from normalized workflow signals.** Do not parse `followUpReason` strings or generic `notes` content in overview surfaces. +- **Saved package state is explicit workflow state.** Future slices should continue treating tailored CV / cover letter / application answer / recruiter message as reusable job-scoped material. +- **Continuity status belongs in the main workspace.** If refresh or sync trust matters, expose its state where the user does the work. +- **Integrated proof should start from an overview surface.** Final-loop regressions should validate real entry routing, not isolated component state only. +- **Manual-send boundary must stay explicit.** Draft generation/regeneration and outbound send must remain visibly separate. + +## Verification Run + +All slice-plan command checks passed in this worktree. + +### Backend + +- `~/.gsd/agent/bin/dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsWorkflowSignalsTests` + +### Frontend tests + +- `cd job-tracker-ui && CI=true ./node_modules/.bin/react-scripts test --watch=false --runTestsByPath src/workflow-trust-signals.test.tsx` +- `cd job-tracker-ui && CI=true ./node_modules/.bin/react-scripts test --watch=false --runTestsByPath src/end-to-end-trust-loop.test.tsx` +- `cd job-tracker-ui && CI=true ./node_modules/.bin/react-scripts test --watch=false --runTestsByPath src/correspondence-gmail-import.test.tsx src/job-details-generated-drafts.test.tsx src/job-details-followup-drafts.test.tsx src/daily-control-loop.test.tsx` + +### Build + +- `cd job-tracker-ui && CI=true ./node_modules/.bin/react-scripts build` + +## Observability / Diagnostic Surfaces Confirmed + +The slice-plan observability surfaces are in place and useful: + +- `GET /api/jobapplications/reminders` +- `GET /api/jobapplications/{id}/readiness` +- `GET /api/jobapplications/{id}/followup-draft` +- `GET /api/correspondence/{jobId}` +- `POST /api/gmail/refresh-linked-threads` +- `job-tracker-ui/src/jobWorkflowSignals.ts` +- `job-tracker-ui/src/workflow-trust-signals.test.tsx` +- `job-tracker-ui/src/end-to-end-trust-loop.test.tsx` + +Backend tests proved normalized workflow-signal behavior. Frontend tests proved overview routing consistency and integrated trust-loop behavior. A live browser check also confirmed the app shell renders, but the current environment still has a CORS/runtime mismatch on `http://localhost:5202/api/...`, so full live UAT depends on running the backend with the expected CORS behavior. + +## Requirement Impact + +- **R010** is now validated. S05 proved coherent history and action continuity across overview routing, saved package reuse, linked Gmail updates, and follow-up drafting using one shared workflow contract. +- **R008** remains active by design. S05 re-proved the manual-send boundary, but the requirement stays active as an ongoing product constraint rather than a one-time feature box. + +## Decisions / Gotchas Worth Carrying Forward + +- Saved application answers should remain explicit workflow state, not inferred from generic notes. +- Linked-thread refresh state should stay visible in the main correspondence workspace. +- In this CRA frontend, run `react-scripts` from `job-tracker-ui/`; invoking via `npm --prefix ...` from repo root can mis-resolve the app directory and fail looking for a root-level `package.json`. +- Browser UAT still requires a correctly configured backend on port `5202`; otherwise the UI shell loads with CORS failures and empty data surfaces. + +## What The Next Slice / Milestone Should Know + +M001 is now assembled as one coherent single-user loop. Future work should build on the shared `workflowSignal` contract and the integrated trust-loop regression instead of adding new routing heuristics or duplicate readiness logic. If a later slice changes reminders, workspace entry, Gmail continuity, or follow-up drafting, it should update both the focused workflow-signal tests and the integrated trust-loop test together. diff --git a/.gsd/milestones/M001/slices/S05/S05-UAT.md b/.gsd/milestones/M001/slices/S05/S05-UAT.md index 68c6339..43cf6e7 100644 --- a/.gsd/milestones/M001/slices/S05/S05-UAT.md +++ b/.gsd/milestones/M001/slices/S05/S05-UAT.md @@ -1,90 +1,246 @@ -# S05 Live-Safe UAT: Trust Loop Verification +# S05 UAT — End-to-end trust and workflow polish ## Goal -Verify the end-to-end trust loop on one real job without accidentally sending recruiter email. +Verify that one real job can be entered from `/jobs`, `/dashboard`, and `/reminders`, then carried through the same trusted workspace loop: + +- saved package material is visible and reusable +- linked Gmail threads stay current without thread re-import +- follow-up drafting is grounded in saved package + correspondence +- no recruiter email is sent unless the human explicitly chooses the send action in a safe environment ## Safety Guardrails -1. **Do not press `Send and log email`** unless the environment is explicitly configured to a safe sink, stub mailbox, or other non-production outbound target. -2. If you are not certain the outbound email path is safe, stop after reviewing the generated follow-up draft. -3. Do not paste private recruiter or correspondence bodies into screenshots, tickets, or logs. -4. Prefer a job that already has: - - saved package material on the job, - - at least one linked Gmail thread, - - a follow-up reason/readiness signal. +1. **Do not click `Send and log email`** unless outbound mail is intentionally routed to a safe sink, stub mailbox, or other non-production target. +2. If safe outbound handling is not confirmed, stop after reviewing the follow-up draft and the manual-send boundary copy. +3. Do not capture or share screenshots containing sensitive recruiter or correspondence content. +4. Use one job that already has all or most of the following: + - a saved tailored CV and/or other saved package material + - at least one imported Gmail thread linked to the job + - a workflow action from the overview surfaces + - follow-up context that should produce a draft ## Preconditions -- The API and UI are running against the intended environment. +- API is running on the expected backend origin with working CORS for the frontend. +- UI is running and can load real API-backed job data. - Gmail integration is authenticated for the current user. -- The selected job has an identifiable company, job title, and recruiter mailbox/thread history. -- If you plan to verify the send step, outbound email must point at a safe sink/stub. Otherwise stop before sending. +- The selected job belongs to the current user and has real recruiter/thread context. +- If the final send step will be tested, outbound mail is pointed at a safe sink/stub. -## Shared Expected Trust Signals +## Shared Expected Signals For The Same Job -The same job should present one coherent next action across all entry points: +Across `/jobs`, `/dashboard`, and `/reminders`, the same job should: -- `/jobs` -- `/dashboard` -- `/reminders` +- show the same general next action +- open the same job workspace +- land on the same tab or equivalent workflow destination +- preserve the same saved package, correspondence, and follow-up state -The workspace should make these states clear: +Inside the job workspace, expect to see: -- saved package material can be reused, -- linked Gmail refresh checks already-linked threads instead of requiring full re-import, -- follow-up draft generation is grounded in saved package + correspondence context, -- email sending remains manual. +- package save-state chips +- a signal that saved package material feeds follow-up drafting +- linked-thread continuity state in Correspondence +- explicit manual-send boundary copy in Follow up -## Flow A — Start from `/jobs` +--- + +## Test Case 1 — `/jobs` routes into the trusted workspace + +### Steps 1. Open `/jobs`. -2. Find a job with a trust/workflow signal chip or next-action button. -3. Open the job via the primary next-action control. -4. Confirm the workspace opens on the expected tab for that action. -5. In **Tailored CV**: - - verify the saved tailored CV, cover letter, application answer, and recruiter message are present if the job previously had them, - - confirm the workspace explicitly says the saved package material feeds follow-up drafting. -6. In **Correspondence**: - - confirm the linked-thread continuity panel is visible, - - confirm Gmail connection state is shown, - - confirm linked thread count is shown when applicable, - - trigger **Refresh linked threads** if manual confirmation is needed, - - verify new linked correspondence appears without importing the full thread again. -7. In **Follow up**: - - confirm the draft context references saved package material and thread context, - - confirm the manual-send boundary copy is visible, - - review the generated draft but **stop before `Send and log email`** unless the environment is explicitly safe. +2. Find a job row with a workflow chip, readiness signal, or next-action control. +3. Open that job using the primary workflow action. -## Flow B — Start from `/dashboard` +### Expected -1. Open `/dashboard`. -2. Find the same job in an attention/reminder card. -3. Open it from the dashboard action. -4. Confirm it lands in the same job workspace and the same trust state is visible: - - package material is still saved, - - correspondence continuity is preserved, - - follow-up context remains grounded. +- The dialog/workspace opens for the selected job. +- The opened tab matches the job’s workflow need rather than a generic default. +- The selected company and role match the job row you opened. -## Flow C — Start from `/reminders` +--- -1. Open `/reminders`. -2. Find the same job in the appropriate reminder grouping. -3. Open it from the reminder action. -4. Confirm it lands in the same workspace for the same job and preserves the same action semantics. +## Test Case 2 — saved package material is visible and reusable + +### Steps + +1. In the opened job workspace, go to **Tailored CV**. +2. Review the save-state chips for: + - Tailored CV + - Cover letter + - Application answer + - Recruiter message +3. Review the “Saved working material” panel. +4. If the job already has saved package data, confirm those fields show as saved. + +### Expected + +- The page shows save-state chips instead of leaving package trust implicit. +- The workspace explicitly indicates that saved package material feeds follow-up drafting. +- Saved material reflects the job’s current stored state, not just the latest generated draft. +- Resetting or revisiting the tab preserves the saved package state. + +### Edge checks + +- If one package field is unsaved, only that field should look incomplete; generic notes alone should not make the job appear package-ready. +- If the application answer exists, it should come back from saved state rather than disappearing or duplicating. + +--- + +## Test Case 3 — correspondence shows linked-thread continuity in the workspace + +### Steps + +1. Open the **Correspondence** tab for the same job. +2. Confirm the Gmail connection state is visible. +3. Confirm the linked-thread panel/state is visible in the main workspace. +4. Review the linked-thread count. +5. Click **Refresh linked threads**. + +### Expected + +- The workspace shows Gmail connection status without needing the import modal to explain trust. +- If linked Gmail threads already exist, the workspace shows the linked-thread count. +- After refresh, the UI reports whether new messages were imported or whether linked threads were already current. +- The user is not forced through a full thread re-import flow for a thread that is already linked. + +### Edge checks + +- If no new Gmail messages exist, the refresh should say the linked threads are current rather than failing silently. +- If the job has no linked threads, the UI should say so clearly instead of implying a broken refresh. + +--- + +## Test Case 4 — new linked correspondence appears without thread re-import + +### Steps + +1. Use a job whose recruiter thread has changed since the last import, or create that condition safely before the test. +2. With the same job open in **Correspondence**, trigger **Refresh linked threads**. +3. Review the correspondence timeline/list after refresh. + +### Expected + +- The new inbound or user-sent Gmail message appears in the same job’s correspondence. +- The refresh uses the already-linked Gmail thread. +- The user does not need to search for and re-import the whole thread manually. + +### Edge checks + +- Duplicate refreshes should not keep importing the same message repeatedly. +- Imported message order and thread continuity should still look sensible in the correspondence list. + +--- + +## Test Case 5 — grounded follow-up drafting stays separate from send + +### Steps + +1. Open the **Follow up** tab for the same job. +2. Review the follow-up context panel. +3. Confirm it references package/correspondence grounding such as thread subject, last activity, or other grounding signals. +4. Click **Regenerate draft** if needed. +5. Review the manual-send boundary panel. +6. Edit the subject/body if desired. +7. **Stop before clicking `Send and log email`** unless outbound mail is confirmed safe. + +### Expected + +- The draft context clearly reflects saved package material and imported correspondence. +- Regenerating the draft changes/reloads draft content only; it does not send email. +- The manual-send boundary copy clearly states that generation/regeneration never sends recruiter email. +- The only outbound action remains the explicit send button. + +### Edge checks + +- If the recruiter email field is blank, drafting should still work; only the manual send step should be blocked or require completion. +- Draft review/editing should remain possible without side effects in correspondence. + +--- + +## Test Case 6 — `/dashboard` opens the same job with the same semantics + +### Steps + +1. Close the workspace. +2. Open `/dashboard`. +3. Find the same job in an attention, readiness, or reminder card. +4. Open the job from the dashboard action. + +### Expected + +- The same job workspace opens. +- The opened tab/action meaning matches the job’s workflow need. +- Saved package state, linked-thread continuity state, and follow-up context are the same as when the job was opened from `/jobs`. + +### Edge checks + +- The dashboard should not route the same job to a conflicting tab/action compared with `/jobs`. + +--- + +## Test Case 7 — `/reminders` opens the same job with the same semantics + +### Steps + +1. Close the workspace. +2. Open `/reminders`. +3. Find the same job in its reminder grouping. +4. Open the job from the reminder action. + +### Expected + +- The same job workspace opens. +- The same job lands in the same workflow area or equivalent action destination as the other entry points. +- Package state, correspondence continuity, and follow-up trust state remain unchanged. + +### Edge checks + +- Reminder grouping should reflect the same workflow classification seen elsewhere, not a conflicting heuristic. + +--- + +## Test Case 8 — optional safe-sink send verification + +> Run this only if outbound email is confirmed safe. + +### Steps + +1. Confirm the environment is using a stub mailbox, sink, or other non-production target. +2. In **Follow up**, click `Send and log email`. +3. Re-open **Correspondence** and/or refresh the job state. + +### Expected + +- The outbound action occurs only after the explicit click. +- The job history/correspondence reflects the sent follow-up appropriately. +- No autonomous send happened before this explicit action. + +### Edge checks + +- If the send endpoint is intentionally stubbed, the UI should still make the boundary clear and report the stubbed result consistently. + +--- ## Pass Criteria -- The same job can be opened from `/jobs`, `/dashboard`, and `/reminders`. -- The saved application package is visible and clearly reusable for follow-up drafting. -- Linked Gmail refresh shows continuity on already-linked threads without requiring a whole-thread re-import workflow. -- The follow-up draft is grounded in saved package and correspondence context. -- No recruiter email is sent unless the human explicitly chooses `Send and log email` in a safe environment. +S05 passes UAT when all of the following are true for the same job: + +- `/jobs`, `/dashboard`, and `/reminders` all open the same job workspace coherently. +- Saved package material is visible as reusable workflow state. +- Linked-thread continuity is visible in the correspondence workspace. +- Refreshing linked threads updates correspondence without requiring re-import of an already-linked thread. +- Follow-up drafting is clearly grounded in package + correspondence context. +- Draft generation/regeneration never sends email on its own. +- No recruiter email is sent unless the human explicitly chooses the send action in a safe environment. ## Failure Clues -- Entry points route to different tabs or imply different next actions for the same job. -- Saved package material is missing or no longer called out as reusable context. -- Linked-thread refresh state is invisible or requires re-importing a thread that is already linked. -- Follow-up drafting triggers outbound send behavior or makes send/regenerate coupling unclear. -- Workspace state differs depending on whether the job was opened from jobs, dashboard, or reminders. +- Different surfaces route the same job to conflicting next actions. +- Generic notes make the job appear package-ready when saved package material is actually missing. +- Linked-thread freshness is hidden, ambiguous, or only discoverable through import-only UI. +- Refreshing linked threads requires a new full-thread import. +- Regenerating a follow-up draft appears coupled to sending. +- Workspace state changes depending on whether the job was opened from jobs, dashboard, or reminders. diff --git a/.gsd/milestones/M001/slices/S05/tasks/T02-VERIFY.json b/.gsd/milestones/M001/slices/S05/tasks/T02-VERIFY.json new file mode 100644 index 0000000..aac5d44 --- /dev/null +++ b/.gsd/milestones/M001/slices/S05/tasks/T02-VERIFY.json @@ -0,0 +1,25 @@ +{ + "schemaVersion": 1, + "taskId": "T02", + "unitId": "M001/S05/T02", + "timestamp": 1774359406536, + "passed": false, + "discoverySource": "none", + "checks": [], + "retryAttempt": 1, + "maxRetries": 2, + "runtimeErrors": [ + { + "source": "bg-shell", + "severity": "crash", + "message": "[jobtracker-api] exitCode=127", + "blocking": true + }, + { + "source": "bg-shell", + "severity": "crash", + "message": "[jobtracker-api] exitCode=134 errors: --- End of inner exception stack trace ---; --- End of inner exception stack trace ---", + "blocking": true + } + ] +}