> 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/understand-your-capacity/throughput-and-attendance.md).

# Throughput and attendance

> **Operator guide for BPP-V1.7.7-THROUGHPUT-RETROSPECTIVE-FOUNDATIONS (P46, shipped 2026-08-05).** Retrospective view of planned vs actual patient counts, treatments delivered, and no-shows across daily, weekly, and monthly grains. Complements the HCS Job Planning framework with per-session throughput evidence.

## What this feature is for

Two audiences see two related surfaces:

1. **Admins on the Trust Admin readiness screens** get an inline input for *patients planned* per (service line, date). Setting a number tells everyone downstream what the target is for that session.
2. **Workers on their personal roster** get a numeric badge showing the planned count on each of their sessions, plus — for sessions on service lines that contribute to their Logbook — a confirmation panel appearing after the session ends where they enter the *patients seen* and *treatments delivered* counts. Confirmation auto-populates a Logbook entry using the treatments count as CPD credit.

Both feed a **trend dashboard** at `/ui/admin/throughput` that renders the daily / weekly / monthly rollups across four axes (treatments / patients / no-shows / sessions) with department, service-line, and worker filters.

## Two counts, two different truths

Two numeric axes are recorded per session and can diverge:

* `patients_actual` — how many distinct patients attended.
* `treatments_actual` — how many discrete treatments were delivered.

One patient may receive multiple treatments in one session (an echo + a follow-up ECG on the same visit). The two axes are independent — treatments can exceed patients.

**Where dedup matters**: sometimes the same patient is counted in two service lines in the same session (e.g. an ECG and a phlebotomy run in one visit). To avoid double-counting patients across the trust, each session carries a `contributes_to_patient_count` flag (default TRUE). Setting it FALSE excludes that session from the patient axis in aggregate reports (treatments are still counted).

**No-shows** are derived — never stored: `patients_planned - patients_actual`. When the admin never set a planned count, no-shows for that session are unknown (not zero). The trend dashboard shows this as a `—` placeholder rather than `0`.

## What "contributes to Logbook" gates

Per service line, admins flip a boolean `contributes_to_logbook` (default FALSE). It gates:

* The worker confirmation panel on `/ui/my-roster` (only appears for sessions on TRUE-flagged SLs).
* The Logbook auto-entry on confirmation (only fires for TRUE-flagged SLs).

Admin-support service lines (say, a rota-management clinic that a worker helps run but isn't clinically responsible for) stay FALSE — their throughput still feeds the admin dashboards but nothing lands in the worker's Logbook.

## The 7-day arrears window

Workers see the confirmation panel for **7 days after a session ends**. The panel disappears afterwards; unconfirmed sessions stay unconfirmed. This is deliberate — the design chose a soft nudge over hard-blocking so a worker on leave the day after a clinic doesn't get chased. If evidence quality becomes an issue, later phases may weight unconfirmed rows lower rather than block.

## Trend dashboard reads

`/ui/admin/throughput` renders one chart per (grain, axis) selection. Three grains (daily / weekly / monthly) render as line or bar accordingly. Four axes:

* **Treatments** — sum of `treatments_actual` across confirmed sessions.
* **Patients** — sum of `patients_actual` across confirmed sessions that contribute to patient count.
* **No-shows** — sum of derived (`patients_planned - patients_actual`) where both are set.
* **Sessions confirmed** — count of confirmations.

Filters: department, service line, worker (any subset), plus a date-range window (default: last 30 days). The five summary chips above the chart show aggregate totals across the whole window; the chart shows the same axis over time.

**Trust-total view** (no dimension filters set) aggregates every service line + department + worker in the tenant.

## Nightly rollup vs on-demand recompute

The three rollup tables (`throughput_rollup_daily / _weekly / _monthly`) are refreshed nightly at 02:00 tenant-local by an external K8s CronJob invoking `application.throughput.scheduled_job.tick`. The job sweeps every tenant + recomputes the last 31 days (so a missed night still catches up on the next).

If you need an immediate refresh (say, after correcting an admin entry), click **"Recompute now"** on the trend dashboard. This runs the same rollup service synchronously against the current tenant + emits the same audit event with `trigger='admin_recompute'`.

Delete-then-insert semantics make the recompute idempotent — a re-run produces byte-identical rollups modulo freshly-set source rows.

## Logbook auto-entry semantics

When a worker confirms attendance on a Logbook-contributing session, a `staff_logbook_entry` row is inserted automatically:

* **Kind**: `cpd_credit`
* **Title**: `{Service line name} attendance {ISO date}`
* **Credit hours**: `treatments_actual` — the accurate CPD count. A worker who sees 3 of 4 planned patients and delivers 3 treatments gets **3 credit**, not 4.
* **Description**: `{N} treatment(s) delivered (WP-P46.D3 auto-entry)` — marker so downstream consumers can distinguish auto-entries from manual ones.

Workers can still add manual notes to the entry after the fact (via the Worker Logbook tab).

Idempotency: re-confirming the same session does **not** duplicate the Logbook entry.

## Perms

Four new closed-set permissions gate the surfaces:

| Perm                                     | Held by        | Gates                                                                 |
| ---------------------------------------- | -------------- | --------------------------------------------------------------------- |
| `admin.session.set_patient_count`        | `tenant_admin` | Inline `patients_planned` input on Trust Admin readiness screens (C1) |
| `admin.throughput_rollup.read`           | `tenant_admin` | Trend dashboard reads (C2/C3)                                         |
| `admin.throughput_rollup.recompute`      | `tenant_admin` | On-demand "Recompute now" button (C4)                                 |
| `my_rostaire.session.confirm_attendance` | `staff_member` | Worker confirmation panel + POST (D2)                                 |

The worker perm is self-scope: even with the perm, a worker can only confirm attendance for sessions where they were the assigned staff (enforced application-side via a `users.staff_id → assignments.staff_id` guard).

## Sidebar navigation

New top-level **Throughput** group sits between **Operations** and **Roster area admin**. Contains one item today (**Trend dashboard**); v1.7.8 (P47) adds the counterfactual skills-recommendation surfaces here.

## Not in this surface

✅ **The counterfactual solver has since shipped** — "if you retrained N workers to competency X, throughput would rise by Y", with its own screens at `/ui/admin/counterfactual` and a **Training impact** item in the sidebar. See [Training impact and capacity economics](/understand-your-capacity/capacity-economics-and-attainment.md). It is no longer deferred, and this section said it was.

Still not built:

* **CSV/PDF export** from the trend dashboard.
* **Comparative benchmarking** across departments.
* **Automatic PII-scrub audit** for external integrations.
* **7-day arrears auto-close** (§0.S3 tail behaviour) — today it's soft-nudge only; unconfirmed sessions stay unconfirmed.
* **Patient-record integration** (PAS / EPR) — v1.7.9+ conversation.

## Where things live

* Data plane: `service_line_admin_status` (MIG-215 six new columns), `service_lines.contributes_to_logbook` (MIG-216), three `throughput_rollup_*` tables (MIG-217/218/219).
* Perms: MIG-220 seed.
* Writers: `application/throughput/session_counts.py`.
* Rollups: `application/throughput/rollup_service.py`.
* Reads: `application/throughput/rollup_query.py`.
* Nightly sweep: `application/throughput/scheduled_job.py`.
* Admin UI: `host/ui/admin_throughput.py` + `host/ui/trust_admin.py` (readiness input).
* Worker UI: `host/ui/router.py` (`/ui/my-roster` + POST `/confirm-attendance`).
* Rollup tables + OpenAPI operations: `v1.1/docs/api/api-v1.1.md` — POST `/admin/service-line-readiness/{sl}/{date}/patient-count`, GET `/admin/throughput/rollup`, POST `/admin/throughput/rollup/recompute`, POST `/me/service-line-readiness/{sl}/{date}/confirm-attendance`.


---

# 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/understand-your-capacity/throughput-and-attendance.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.
