chore(M001/S05): auto-commit after complete-slice
This commit is contained in:
@@ -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 |
|
| 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 |
|
| 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 |
|
| 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 |
|
||||||
|
|||||||
@@ -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 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.
|
- `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.
|
- 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`.
|
||||||
|
|||||||
+2
-2
@@ -10,7 +10,7 @@ The product must let one person run a real job search without losing the thread:
|
|||||||
|
|
||||||
## Current State
|
## 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
|
## Architecture / Key Patterns
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ See `.gsd/REQUIREMENTS.md` for the explicit capability contract, requirement sta
|
|||||||
|
|
||||||
## Milestone Sequence
|
## 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.
|
- [ ] 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.
|
- [ ] 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.
|
- [ ] M004: Trust, launchability, and hardening — Polish validation, clarity, performance, and operational trust surfaces for sustained daily use.
|
||||||
|
|||||||
+15
-15
@@ -26,17 +26,6 @@ This file is the explicit capability and coverage contract for the project.
|
|||||||
- Validation: mapped
|
- Validation: mapped
|
||||||
- Notes: Shared/team workflows are not the current product target.
|
- 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
|
## Validated
|
||||||
|
|
||||||
### R001 — The user finds a job outside the app, imports it into the app, and starts the application workflow from that imported role.
|
### 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.
|
- 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.
|
- 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
|
## Deferred
|
||||||
|
|
||||||
### R011 — The app should later expand overview analytics, saved views, and clearer strategy readouts beyond the core daily loop.
|
### 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. |
|
| 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. |
|
| 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 |
|
| 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 |
|
| R011 | operability | deferred | M002/S02 | none | unmapped |
|
||||||
| R012 | integration | deferred | M003/S01 | none | unmapped |
|
| R012 | integration | deferred | M003/S01 | none | unmapped |
|
||||||
| R013 | differentiator | deferred | M003/S02 | 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
|
## Coverage Summary
|
||||||
|
|
||||||
- Active requirements: 3
|
- Active requirements: 2
|
||||||
- Mapped to slices: 3
|
- Mapped to slices: 2
|
||||||
- Validated: 7 (R001, R002, R003, R004, R005, R006, R007)
|
- Validated: 8 (R001, R002, R003, R004, R005, R006, R007, R010)
|
||||||
- Unmapped active requirements: 0
|
- Unmapped active requirements: 0
|
||||||
|
|||||||
@@ -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.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: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.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}}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ This milestone is complete only when all are true:
|
|||||||
- [x] **S04: Daily control loop surfaces** `risk:medium` `depends:[S01,S03]`
|
- [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.
|
> 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.
|
> 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
|
## Boundary Map
|
||||||
|
|||||||
@@ -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.
|
||||||
@@ -1,90 +1,246 @@
|
|||||||
# S05 Live-Safe UAT: Trust Loop Verification
|
# S05 UAT — End-to-end trust and workflow polish
|
||||||
|
|
||||||
## Goal
|
## 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
|
## 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.
|
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 you are not certain the outbound email path is safe, stop after reviewing the generated follow-up draft.
|
2. If safe outbound handling is not confirmed, stop after reviewing the follow-up draft and the manual-send boundary copy.
|
||||||
3. Do not paste private recruiter or correspondence bodies into screenshots, tickets, or logs.
|
3. Do not capture or share screenshots containing sensitive recruiter or correspondence content.
|
||||||
4. Prefer a job that already has:
|
4. Use one job that already has all or most of the following:
|
||||||
- saved package material on the job,
|
- a saved tailored CV and/or other saved package material
|
||||||
- at least one linked Gmail thread,
|
- at least one imported Gmail thread linked to the job
|
||||||
- a follow-up reason/readiness signal.
|
- a workflow action from the overview surfaces
|
||||||
|
- follow-up context that should produce a draft
|
||||||
|
|
||||||
## Preconditions
|
## 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.
|
- Gmail integration is authenticated for the current user.
|
||||||
- The selected job has an identifiable company, job title, and recruiter mailbox/thread history.
|
- The selected job belongs to the current user and has real recruiter/thread context.
|
||||||
- If you plan to verify the send step, outbound email must point at a safe sink/stub. Otherwise stop before sending.
|
- 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`
|
- show the same general next action
|
||||||
- `/dashboard`
|
- open the same job workspace
|
||||||
- `/reminders`
|
- 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,
|
- package save-state chips
|
||||||
- linked Gmail refresh checks already-linked threads instead of requiring full re-import,
|
- a signal that saved package material feeds follow-up drafting
|
||||||
- follow-up draft generation is grounded in saved package + correspondence context,
|
- linked-thread continuity state in Correspondence
|
||||||
- email sending remains manual.
|
- 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`.
|
1. Open `/jobs`.
|
||||||
2. Find a job with a trust/workflow signal chip or next-action button.
|
2. Find a job row with a workflow chip, readiness signal, or next-action control.
|
||||||
3. Open the job via the primary next-action control.
|
3. Open that job using the primary workflow action.
|
||||||
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.
|
|
||||||
|
|
||||||
## Flow B — Start from `/dashboard`
|
### Expected
|
||||||
|
|
||||||
1. Open `/dashboard`.
|
- The dialog/workspace opens for the selected job.
|
||||||
2. Find the same job in an attention/reminder card.
|
- The opened tab matches the job’s workflow need rather than a generic default.
|
||||||
3. Open it from the dashboard action.
|
- The selected company and role match the job row you opened.
|
||||||
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.
|
|
||||||
|
|
||||||
## Flow C — Start from `/reminders`
|
---
|
||||||
|
|
||||||
1. Open `/reminders`.
|
## Test Case 2 — saved package material is visible and reusable
|
||||||
2. Find the same job in the appropriate reminder grouping.
|
|
||||||
3. Open it from the reminder action.
|
### Steps
|
||||||
4. Confirm it lands in the same workspace for the same job and preserves the same action semantics.
|
|
||||||
|
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
|
## Pass Criteria
|
||||||
|
|
||||||
- The same job can be opened from `/jobs`, `/dashboard`, and `/reminders`.
|
S05 passes UAT when all of the following are true for the same job:
|
||||||
- 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.
|
- `/jobs`, `/dashboard`, and `/reminders` all open the same job workspace coherently.
|
||||||
- The follow-up draft is grounded in saved package and correspondence context.
|
- Saved package material is visible as reusable workflow state.
|
||||||
- No recruiter email is sent unless the human explicitly chooses `Send and log email` in a safe environment.
|
- 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
|
## Failure Clues
|
||||||
|
|
||||||
- Entry points route to different tabs or imply different next actions for the same job.
|
- Different surfaces route the same job to conflicting next actions.
|
||||||
- Saved package material is missing or no longer called out as reusable context.
|
- Generic notes make the job appear package-ready when saved package material is actually missing.
|
||||||
- Linked-thread refresh state is invisible or requires re-importing a thread that is already linked.
|
- Linked-thread freshness is hidden, ambiguous, or only discoverable through import-only UI.
|
||||||
- Follow-up drafting triggers outbound send behavior or makes send/regenerate coupling unclear.
|
- Refreshing linked threads requires a new full-thread import.
|
||||||
- Workspace state differs depending on whether the job was opened from jobs, dashboard, or reminders.
|
- Regenerating a follow-up draft appears coupled to sending.
|
||||||
|
- Workspace state changes depending on whether the job was opened from jobs, dashboard, or reminders.
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user