> For the complete documentation index, see [llms.txt](https://help.resouris.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://help.resouris.com/job-planning/job-plan-monitoring-kpis.md).

# Job-plan monitoring KPIs

> **Reference**: NHS "Job Planning for Healthcare Science Staff" Guidelines §6.12 (15 monitoring KPIs). See `hcs-job-planning-framework.md` for framework overview.

## The 15 Guidelines §6.12 KPIs, and a sixteenth widget

Every widget in `adapters/widgets_hcs_job_planning/` maps to a specific Guidelines §6.12 KPI. All 15 are gated on `admin.job_plan_monitoring.read` (held by `tenant_admin` + `rostering_manager` by default).

| #  | Widget code                     | KPI intent                                              | Data source                                       |
| -- | ------------------------------- | ------------------------------------------------------- | ------------------------------------------------- |
| 1  | `hcs_team_plan_coverage`        | % services with a current team job plan                 | `team_job_plan` (MIG-196)                         |
| 2  | `hcs_staff_plan_review_current` | % HCS staff with plan reviewed within 12mo              | `job_plan_review_schedule` (MIG-195)              |
| 3  | `hcs_plan_objective_alignment`  | % plans aligned with recorded objectives                | `job_plan` + objectives seed                      |
| 4  | `hcs_spa_allocation_core`       | % staff meeting SPA minimum (Guidelines Table 2)        | `role_spa_minimum` (MIG-190) + entitlement rollup |
| 5  | `hcs_category_distribution`     | DCC/SPA/ANR/ED distribution by service (stacked)        | `job_plan_entitlement.category_id` (MIG-188)      |
| 6  | `hcs_additional_activity`       | Activity recorded outside a plan entitlement            | `job_plan_ledger` unmatched to entitlement        |
| 7  | `hcs_vacancy_absence_turnover`  | Vacancy/absence/turnover panel                          | `staff_sickness` + `staff_extended_leave`         |
| 8  | `hcs_accreditation_readiness`   | Accreditation readiness + outstanding actions           | `staff_accreditations`                            |
| 9  | `hcs_competency_supervision`    | Competency + supervision compliance %                   | `competencies` + `staff_competencies`             |
| 10 | `hcs_statutory_safety_roles`    | Roles with planned time                                 | `staff_external_duty` + accreditation             |
| 11 | `hcs_planned_vs_delivered`      | Variance buckets (green ≤ 5% / amber ≤ 15% / red > 15%) | `entitlement_bank` (MIG-193)                      |
| 12 | `hcs_turnaround_reporting`      | Median + P90 turnaround hours                           | Roster + report packs                             |
| 13 | `hcs_capacity_utilisation`      | Session capacity utilisation %                          | Roster telemetry                                  |
| 14 | `hcs_demand_vs_capacity`        | Signed PA gap (surplus/shortfall)                       | Demand model + `entitlement_bank`                 |
| 15 | `hcs_review_overdue`            | Overdue + due-within-30-days counts                     | `job_plan_review_schedule` (MIG-195)              |

## Widget contract

Every widget follows the standard IWidget contract:

* `code()` — stable identifier used to place the widget on dashboards.
* `accessible_name()` — screen-reader label + card title.
* `required_perms()` — always returns `("admin.job_plan_monitoring.read",)` for every monitoring widget.
* `render(properties, request_context)` — HTML string. Graceful "no data" card when the dataset dict is empty.

## Composing into a dashboard

Each widget is composable into any dashboard (the SharePoint-modern-page editor at `/ui/admin/widget-dashboards/{id}/edit`). The Trust Admin picks widgets from the catalogue picker; layouts + colours per the standard widget-dashboards editor.

**Curated preset dashboard** at `/ui/admin/job-plan-monitoring` — all **16** widgets in a 3-column Trust-Admin-oriented layout shipped in Cohort C. Provisioning is one-shot per tenant via `scripts/provision-hcs-kpi-preset-dashboard.py`, which seeds one `dashboard` row + 15 `dashboard_widget_instance` rows wiring every KPI producer to its widget instance.

## Render posture

Factual + non-evaluative per the enhancement #31 guidance that shaped the widgets\_absence\_toolkit pack. Percentages are shown to one decimal (e.g. `72.5%`); PA totals to one decimal with signed prefix on gap widgets (e.g. `+4.5 PAs`, `-3.2 PAs`). Variance bucket pills use colour + text label so the render is accessible without colour cues.

## Data plane wiring (v1.7.4 landed)

Real datasets sit behind all of them.

> ⓘ **Fifteen KPIs, sixteen widgets.** The Guidelines define 15; ReSouris adds **Coverage by open cycle** (`hcs_cycle_coverage_percent`) for the plan-history surface, which is not a Guidelines KPI. This page said 15 widgets after the sixteenth had shipped — the producer existed and had no widget to render it, so the dashboard had a hole where a working data source already was. Producers are organised in three Python modules per KPI group:

| Module                                         | KPIs                                                                                                            | Data source                                                                                                                                                                          |
| ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `application/job_plan_monitoring/kpi_1_5.py`   | 1–5 (TeamPlanCoverage, StaffPlanReviewCurrent, PlanObjectiveAlignment, SpaAllocationCore, CategoryDistribution) | MIG-206 KPI dataset views (`hcs_kpi_*` with `security_invoker=true` for per-tenant RLS).                                                                                             |
| `application/job_plan_monitoring/kpi_6_10.py`  | 6–10 (AppealVolume, SignoffTurnaround, ReconciliationSignoffRate, ReviewOverdue, CycleProgress)                 | Direct-table queries against `job_plan_appeal`, `job_plan_signoff`, `job_plan_quarterly_reconciliation`, `job_plan_review_schedule`, `job_plan_cycle`.                               |
| `application/job_plan_monitoring/kpi_11_15.py` | 11–15 (ExternalDutyRatio, DlsCoverage, EnhancedScrutinyTripRate, MicroAllocationDrift, SpaMinOverrideRate)      | Direct-table queries against `staff_external_duty`, `job_plan_designated_lead`, `enhanced_scrutiny_rule` + `job_plan_signoff`, `job_plan_ledger` (derived rows), audit-event stream. |

All 15 KPI SQL queries have fingerprint snapshots locked at `tests/ui/kpi_snapshots/kpi_N.sql.snap` per the plan doc §7.3 rigor gate — any accidental query change trips a golden-file test at the KPI granularity.

Widget 3 (`hcs_plan_objective_alignment`) reads the `objectives_jsonb` field added to `job_plan` by MIG-206 (`text NULL CHECK <= 4000`).

## Auditability

Every dashboard render fires a standard dashboard-view audit event. Individual widget interactions don't emit audit events (the widgets are read-only visualisations); the underlying data changes carry their own audit trails: `job_plan.state_changed`, `job_plan_entitlement.created`, `team_job_plan.published`, `job_plan.review_due` (v1.7.4 payload extended with `line_manager_staff_id`), `job_plan.spa_minimum_violated`, `staff_external_duty.recorded`, `job_plan.signoff_recorded`, and the v1.7.4 additions `job_plan.spa_drift_detected` + `job_plan.appeal_sla_breached`.

**v1.7.4 addition**: WTE-aware denominators. KPI 4 (SpaAllocationCore) computes per-worker expected hours using WTE-scaled contracted hours rather than the assumed-full-time raw number. The visible effect: PT-heavy teams no longer show a systemic under-compliance signal because the denominator matches the actual contract. See [WTE scaling + session-based rendering](/job-planning/wte-and-session-based.md).

## Data-quality signal

Widget 5 (`hcs_category_distribution`) surfaces unclassified entitlement rows explicitly — pre-P42 entitlements that never had a DCC/SPA/ANR/ED tag applied render in a distinct "unclassified" column. Trust Admins can use this as a nudge to retro-tag legacy entitlements.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://help.resouris.com/job-planning/job-plan-monitoring-kpis.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
