feat(S05/T01): Unified workflow trust signals across the API, table, da…

- JobTrackerApi/Controllers/JobApplicationsController.cs
- JobTrackerApi.Tests/JobApplicationsWorkflowSignalsTests.cs
- job-tracker-ui/src/jobWorkflowSignals.ts
- job-tracker-ui/src/components/JobTable.tsx
- job-tracker-ui/src/components/DashboardView.tsx
- job-tracker-ui/src/components/RemindersView.tsx
- job-tracker-ui/src/workflow-trust-signals.test.tsx
This commit is contained in:
2026-03-24 14:28:01 +01:00
parent d166f9854d
commit 9adbde3f5e
12 changed files with 974 additions and 314 deletions
+8
View File
@@ -68,3 +68,11 @@
{"ts":"2026-03-24T13:02:04.657Z","flowId":"9a9419e5-3975-4382-a2e4-b1323aa878eb","seq":2,"eventType":"dispatch-match","rule":"planning → plan-slice","data":{"unitType":"plan-slice","unitId":"M001/S05"}}
{"ts":"2026-03-24T13:02:04.662Z","flowId":"9a9419e5-3975-4382-a2e4-b1323aa878eb","seq":3,"eventType":"unit-start","data":{"unitType":"plan-slice","unitId":"M001/S05"}}
{"ts":"2026-03-24T13:05:20.939Z","flowId":"9a9419e5-3975-4382-a2e4-b1323aa878eb","seq":4,"eventType":"unit-end","data":{"unitType":"plan-slice","unitId":"M001/S05","status":"completed","artifactVerified":true},"causedBy":{"flowId":"9a9419e5-3975-4382-a2e4-b1323aa878eb","seq":3}}
{"ts":"2026-03-24T13:05:21.511Z","flowId":"9a9419e5-3975-4382-a2e4-b1323aa878eb","seq":5,"eventType":"iteration-end","data":{"iteration":1}}
{"ts":"2026-03-24T13:05:21.513Z","flowId":"f7f931a0-5c2a-4941-952e-74d3f5d60ab0","seq":1,"eventType":"iteration-start","data":{"iteration":2}}
{"ts":"2026-03-24T13:05:21.639Z","flowId":"f7f931a0-5c2a-4941-952e-74d3f5d60ab0","seq":2,"eventType":"dispatch-match","rule":"executing → execute-task","data":{"unitType":"execute-task","unitId":"M001/S05/T01"}}
{"ts":"2026-03-24T13:05:21.648Z","flowId":"f7f931a0-5c2a-4941-952e-74d3f5d60ab0","seq":3,"eventType":"unit-start","data":{"unitType":"execute-task","unitId":"M001/S05/T01"}}
{"ts":"2026-03-24T13:12:04.885Z","flowId":"09dff360-cfa9-4365-b737-b6aea08e2378","seq":1,"eventType":"iteration-start","data":{"iteration":1}}
{"ts":"2026-03-24T13:12:04.965Z","flowId":"09dff360-cfa9-4365-b737-b6aea08e2378","seq":2,"eventType":"dispatch-match","rule":"executing → execute-task","data":{"unitType":"execute-task","unitId":"M001/S05/T01"}}
{"ts":"2026-03-24T13:12:04.972Z","flowId":"09dff360-cfa9-4365-b737-b6aea08e2378","seq":3,"eventType":"unit-start","data":{"unitType":"execute-task","unitId":"M001/S05/T01"}}
{"ts":"2026-03-24T13:28:01.394Z","flowId":"09dff360-cfa9-4365-b737-b6aea08e2378","seq":4,"eventType":"unit-end","data":{"unitType":"execute-task","unitId":"M001/S05/T01","status":"completed","artifactVerified":true},"causedBy":{"flowId":"09dff360-cfa9-4365-b737-b6aea08e2378","seq":3}}
+1 -1
View File
@@ -44,7 +44,7 @@ The work is grouped into two tasks because the slice has two different risks. Fi
## Tasks
- [ ] **T01: Centralize workflow trust signals across overview and readiness surfaces** `est:5h`
- [x] **T01: Centralize workflow trust signals across overview and readiness surfaces** `est:5h`
- Why: S05 cannot prove coherence while table, dashboard, reminders, and readiness still infer next actions from separate brittle rules.
- Files: `JobTrackerApi/Controllers/JobApplicationsController.cs`, `JobTrackerApi.Tests/JobApplicationsWorkflowSignalsTests.cs`, `job-tracker-ui/src/types.ts`, `job-tracker-ui/src/jobWorkflowSignals.ts`, `job-tracker-ui/src/components/JobTable.tsx`, `job-tracker-ui/src/components/DashboardView.tsx`, `job-tracker-ui/src/components/RemindersView.tsx`, `job-tracker-ui/src/workflow-trust-signals.test.tsx`
- Do: add explicit workflow trust/action fields or normalized routing metadata at the controller/DTO layer, introduce a shared UI helper that consumes those fields instead of parsing free-form strings or raw `notes`, and update table/dashboard/reminders to route from the same source of truth without breaking the existing shared `/jobs?open=...&tab=...` workspace entry pattern.
@@ -0,0 +1,84 @@
---
id: T01
parent: S05
milestone: M001
provides:
- Shared workflow trust/action signals for overview and readiness surfaces
key_files:
- JobTrackerApi/Controllers/JobApplicationsController.cs
- JobTrackerApi.Tests/JobApplicationsWorkflowSignalsTests.cs
- job-tracker-ui/src/jobWorkflowSignals.ts
- job-tracker-ui/src/components/JobTable.tsx
- job-tracker-ui/src/components/DashboardView.tsx
- job-tracker-ui/src/components/RemindersView.tsx
- job-tracker-ui/src/workflow-trust-signals.test.tsx
key_decisions:
- Treated saved application answers as explicit workflow state via WorkflowSignal instead of inferring package readiness from generic notes text.
patterns_established:
- Overview surfaces must derive routing, labels, and grouping from workflowSignal plus jobWorkflowSignals.ts, not from followUpReason string matching.
observability_surfaces:
- GET /api/jobapplications/reminders
- GET /api/jobapplications/{id}/readiness
- job-tracker-ui/src/jobWorkflowSignals.ts
- job-tracker-ui/src/workflow-trust-signals.test.tsx
- JobTrackerApi.Tests/JobApplicationsWorkflowSignalsTests.cs
duration: 2h 10m
verification_result: passed
completed_at: 2026-03-24T14:02:04+01:00
blocker_discovered: false
---
# T01: Centralize workflow trust signals across overview and readiness surfaces
**Unified workflow trust signals across the API, table, dashboard, and reminders.**
## What Happened
I verified the local controller and UI code first, found that the backend already had the beginnings of a `WorkflowSignal` contract, and confirmed the remaining drift was on the consumer side: `JobTable`, `DashboardView`, and `RemindersView` still fell back to `followUpReason` parsing or raw `notes`/`tailoredCvText` heuristics.
On the backend, I fixed the broken `RulesEngine.Decision` type references so the controller compiled again, kept the saved-application-answer block parsing as the package-readiness source of truth, and added focused tests proving two things: generic notes do not satisfy saved-answer readiness, and reminders/readiness now expose normalized workflow routing metadata for both package work and follow-up work.
On the frontend, I completed the shared type contract by adding `WorkflowSignal` to `job-tracker-ui/src/types.ts`, extended `ReadinessResponse` to surface that signal, and rewrote `job-tracker-ui/src/jobWorkflowSignals.ts` as the one shared helper for overview routing, labels, and reminder grouping.
I then updated the three overview surfaces to consume that helper directly. `JobTable` now drives urgency chips, primary actions, and the readiness filter from `workflowSignal` instead of raw `notes` or `followUpReason`. `DashboardView` now chooses reminder labels/routes from the same helper. `RemindersView` now groups jobs and opens workspace tabs from `workflowSignal` rather than parsing reason text.
To keep the existing integrated coverage useful, I also updated `src/daily-control-loop.test.tsx` to the new contract so the broader slice-level regression continues to validate the overview loop instead of enforcing the old heuristic behavior.
## Verification
I ran the focused T01 backend and frontend checks from the task plan and both passed. I also ran the slice-level verification commands relevant at this stage: the broader focused UI regression bundle now passes, the production build passes, and the only remaining slice-level failure is the missing `src/end-to-end-trust-loop.test.tsx`, which belongs to T02 and is expected for this intermediate task.
## Verification Evidence
| # | Command | Exit Code | Verdict | Duration |
|---|---------|-----------|---------|----------|
| 1 | `dotnet test JobTrackerApi.Tests/JobTrackerApi.Tests.csproj --filter JobApplicationsWorkflowSignalsTests` | 0 | ✅ pass | 3.62s |
| 2 | `CI=true npm --prefix job-tracker-ui test -- --watch=false --runTestsByPath src/workflow-trust-signals.test.tsx` | 0 | ✅ pass | 3.37s |
| 3 | `CI=true npm --prefix job-tracker-ui test -- --watch=false --runTestsByPath src/end-to-end-trust-loop.test.tsx` | 1 | ❌ fail | 0.62s |
| 4 | `CI=true npm --prefix job-tracker-ui 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` | 0 | ✅ pass | 4.62s |
| 5 | `CI=true npm --prefix job-tracker-ui run build` | 0 | ✅ pass | 12.73s |
## Diagnostics
Inspect `GET /api/jobapplications/reminders` and `GET /api/jobapplications/{id}/readiness` to confirm `workflowSignal.actionKey`, `workspaceTab`, `followMode`, and package/interview/follow-up booleans. On the UI side, inspect `job-tracker-ui/src/jobWorkflowSignals.ts` and run `src/workflow-trust-signals.test.tsx` to catch any routing/grouping drift. Failures now surface as deterministic targeted test failures instead of silent string-parsing mismatches.
## Deviations
I also corrected a pre-existing controller compile issue (`RulesEngine.Decision` vs. `FollowUpDecision`) and updated the existing `src/daily-control-loop.test.tsx` regression so it validates the new shared workflow contract instead of the retired heuristic behavior.
## Known Issues
- `src/end-to-end-trust-loop.test.tsx` does not exist yet, so that slice-level verification command still fails until T02 adds the integrated trust-loop proof.
- The React test runs emit React Router future-flag warnings, but they are warnings only and did not affect pass/fail outcomes.
## Files Created/Modified
- `JobTrackerApi/Controllers/JobApplicationsController.cs` — fixed the follow-up decision type usage while preserving and exposing the normalized workflow signal contract.
- `JobTrackerApi.Tests/JobApplicationsWorkflowSignalsTests.cs` — added focused backend proofs for package-gap vs. generic-notes handling and normalized reminder routing metadata.
- `job-tracker-ui/src/types.ts` — added the shared `WorkflowSignal` type and extended readiness responses to carry it.
- `job-tracker-ui/src/jobWorkflowSignals.ts` — centralized workflow routing, labels, and reminder grouping for overview surfaces.
- `job-tracker-ui/src/components/JobTable.tsx` — switched next-action chips/buttons and readiness filtering to the shared workflow signal.
- `job-tracker-ui/src/components/DashboardView.tsx` — switched reminder labels/routes to the shared workflow signal helper.
- `job-tracker-ui/src/components/RemindersView.tsx` — switched grouping and open-action routing to workflow signal metadata.
- `job-tracker-ui/src/workflow-trust-signals.test.tsx` — added focused frontend regression coverage proving overview surfaces stay aligned.
- `job-tracker-ui/src/daily-control-loop.test.tsx` — updated the broader loop regression to the shared workflow contract.