← Back

Workforce Early-Warning System

An early-warning system for burnout and resignation. It reads the HR records a company already keeps, finds the patterns that come before somebody breaks down or leaves, and raises them while there is still time to help.

Role
AI Engineer
Year
2026
Status
Pre-production
Tests
~1,350, all offline

Most large employers run their HR on a system called Workday. It is the filing cabinet for everything about a job: who works here and who they report to, hours logged, holiday booked and taken, sick days, pay and pay reviews, performance ratings, training completed, contract end dates, visa expiries. Almost none of that is read forward. It is used to count what already happened — to run payroll, to close the quarter, and occasionally to build a case about somebody after the fact.

This system reads the same records the other way round. Take the founding example. Somebody takes a sick day, or a sick week, roughly every three months. Ordinary absence management counts the days, notices the total has crossed a line, and schedules a conversation about attendance. Read forward, that regularity is the interesting part: a body claiming the recovery the calendar never gave it. The gap between episodes is stable enough to take a median of, which means the next dip has an approximate date, which means somebody can offer a break before it lands rather than a warning after it.

The same method is applied to every part of working life the HR system can see — starting a job, growing in it, being paid for it, being recognised for it, and leaving it. Thirty-one patterns in all. Each one names a thing that tends to precede a bad outcome, computes the date the outcome is expected, and surfaces it early with the evidence attached.

The obvious objection is that a system watching individual employees this closely is one bad decision away from being a surveillance tool. That objection shaped the architecture more than anything else. The engine cannot act. It has no write path back into Workday, no drafting layer, no send button — it detects, scores, and displays, and every decision about what to do belongs to a person. Aggregates below five people are refused outright, the manager-facing copy is physically stripped of anything medical, and none of that is a policy document. It is the code.

Architecture

The engine is Python with no third-party runtime dependencies at all — the standard library and nothing else. That was a deliberate constraint rather than an aesthetic one: this is software that reads an entire company's HR records, and every dependency it does not have is a supply-chain question nobody has to answer before it is allowed near a real tenant.

Getting the data out of Workday takes three protocols, because no one of them can see everything. Modern REST endpoints cover most of the day-to-day records. A much older SOAP interface is the only route to manager chains, compensation, leavers, contingent contract dates and visa expiries. A query language called WQL fills the remaining gaps, mostly benefits and tenure cross-checks. The engine speaks all three behind a single interface, so the rest of the code never learns which protocol a fact arrived on — and a fourth implementation of that same interface is a fake tenant, which is why every test runs offline with no Workday, no network and no credentials.

What comes back is normalised into plain records and stored as a dated snapshot. Detectors then read the snapshot and emit signals. A signal is not a score on its own: it carries the evidence that produced it, a confidence, and where the maths allows one, a horizon — the computed date the predicted problem lands. Signals that describe a condition true right now are labelled differently from signals making a dated claim about the future, because only the second kind can be graded later.

The layer that makes it more than a set of thresholds is the personal baseline. A fixed rule that fires at 45 hours a week is wrong for almost everybody: it is a crisis for one person and an ordinary Tuesday for another. So every worker's metrics are resampled into a per-metric time series, and a robust baseline — median plus median absolute deviation, which a few extreme weeks cannot drag around — learns what is normal for that person specifically. A detector family fires on sustained deviation from somebody's own history rather than from a constant everybody shares. On top of that, changepoint detection turns "a threshold was crossed" into the more useful "this person's hours changed regime on the third of March".

Because the forecasts carry dates, they are falsifiable, and the engine is made to grade its own homework. Every cycle scores the predictions that came due — the sick dip either happened or it did not, the flight-risk person stayed past their anniversary or left — and prints a running record. That tally is the honest evidence, and it is also the tuning signal that catches a wrong detector before intuition does. Raw detector confidence is not shown as a probability until it has been mapped through an empirical, confidence-bounded calibration; below twenty observations an insight says it does not have the evidence yet instead of inventing a number.

No change to a detector or a model can ship on the strength of looking better. Every change replays against stored history and has to beat the incumbent on precision, Brier score and lead time before it is allowed in. The predictive models — discrete-time hazard models for attrition, sustained sick absence, probation non-completion and contract non-renewal — each carry a model card and a fairness audit, and each refuses to take over from the simpler rule-based logic until it has earned it on that same replay. When a model does run before it has earned the switch, its output is tagged in the interface as shadow: shown, but not deciding anything.

The privacy floors are structural. No aggregate over a team, manager, region, cost centre or location is computed below five people — below that it reports a count and nothing else, so a number can never be arithmetic away from naming a person. Location is off by default on top of that, because a small office is identifying on its own. The person a signal is about always sees the whole thing; the copy their manager sees goes through a redaction step that removes absence type, medical adjacency and the raw pattern parameters, so a manager is told somebody could use support without being handed a medical inference. Protected and parental leave never map to sickness anywhere in the signal path. Engagement-survey data has no per-worker field in the data model at all — not a rule about it, an absence of anywhere to put it.

Failures are loud in a specific way. If a data source degrades, the cycle does not crash and it does not quietly return a healthy-looking workforce: the gap is listed in the brief as a gap. Snapshots also record how much of the workforce was actually pulled, and anything reading history compares like with like — a run capped at 150 of 791 workers used to leave evidence indistinguishable from a genuine 150-person company, which is exactly the kind of silence that gets mistaken for good news.

Workforce early-warning system architecture Six layers, flowing downward, with one line running back up. A Workday tenant is read over REST, SOAP and WQL — directly or through an MCP server — because no single protocol exposes everything; an engagement survey is read at aggregate scopes only, since the data model has no per-worker field for it. One client interface covers all three protocols, and a fake implementation of that same interface is what lets every test run offline. Per-domain pullers map tolerantly and fail soft, so a source that goes dark becomes a recorded gap rather than a healthy-looking result, and what they produce is a dated snapshot alongside the trajectory archive, insight log and prediction ledger. Detection then runs as a chain: an analytics layer computes each worker's own median-and-MAD baseline, changepoints and cohort position; thirty-one detectors emit signals carrying evidence, confidence and a predicted date; composites combine those into flight risk and related patterns; and hazard models run last, in shadow, until they beat the rules they would replace. Scoring is also a chain, and privacy is deliberately its final link: signals are scored into domain facets, mapped through an empirical calibration that declines to state a probability under twenty observations, suppressed if the same standing pattern was surfaced inside its cooldown window, and only then passed through floors that refuse any aggregate below five people and strip medical detail from the manager copy. Those floors gate all three outputs: the cycle brief, a console that opens on no individual, and a redacted handoff export that is off by default. Finally the learning loops grade what was predicted, replay proposed changes against history, sweep detector constants, and watch the models against their own cards — and none of them change anything by themselves. Their conclusions re-enter detection only as a reviewed change. Nothing in the system writes back to Workday. Sources Ingest Detection Scoring & gates Surfaces Learning loops Workday tenant REST · SOAP (WWS) · WQL No one protocol sees everything OAuth refresh handled internally WD-MCP-Server Four meta-tools over 3,891 operations An optional route to the same tenant A missing consent is a data gap Engagement survey A separate product, its own API Aggregate scopes only — there is no per-worker field to populate Client seam One interface, four implementations Http · Direct · Fake The Fake is why every test is offline Pullers One per domain, tolerant mapping Fail-soft, never fatal A dark source becomes a recorded gap Snapshot & store Dated, normalised records Trajectory archive · insight log Prediction ledger · pull scope Analytics Baselines: median + MAD, per person Changepoints: CUSUM Cohorts: k-floored z-scores Ambient: sub-threshold strain First pass 31 detectors, one pattern each joining · wellbeing · growth compliance · retention · leaving Each emits evidence, confidence and a dated horizon Second pass Composites over the first list flight_risk · signal_pile_up manager_cascade · keyperson_exposure They roll up their constituents Hazard post-pass Attrition · sick absence · probation · contract Model card + fairness audit Shadow until it beats the rules it would replace Domain scorecard Wellness · Delivery · Citizenship facet = 100 − ambient − Σ penalty × confidence attention / neutral / thriving Calibration gate Raw confidence → empirical rate Wilson-bounded Under n=20 it says so rather than bluffing a number Cooldown A standing pattern surfaces once per window, not daily Quiet cycles are the goal Privacy floors k ≥ 5 for every aggregate Manager copy redacted Location off by default Enforced here, not downstream Cycle brief What was found — and what was dark, named as a gap Prediction scorecard Console Opens company-wide, on nobody Individuals sit behind two deliberate doors Handoff Per-audience, redaction applied Off by default And it still writes nothing Outcomes Grades every forecast that came due Held, or missed Backtest gate Replays against history Must beat the incumbent on precision, Brier, lead time Tune Sweeps detector constants Prints a patch — applies nothing itself Self-watch Calibration drift + walk-forward AUC, against each model card Recommends, never retrains 1 2 3 4 5 6 7 8
1 Workforce pull · daily 2 Survey read · aggregate only 3 Normalised snapshot 4 Scored insights 5 Privacy floors applied · before anything renders 6 Handoff · off by default 7 Forecasts graded · when they come due 8 What the loops conclude · re-enters only as a reviewed change

Platforms used

Engine

  • Python 3.11
  • Standard library only
  • No runtime dependencies
  • Protocol seams + offline fake

Workday integration

  • REST
  • SOAP (Workday Web Services)
  • WQL
  • OAuth token refresh
  • Model Context Protocol

Detection & modelling

  • Median + MAD baselines
  • CUSUM changepoints
  • Discrete-time hazard models
  • Wilson-bounded calibration
  • Cohort z-scores
  • Backtest ship gate

Console

  • React 19
  • TypeScript
  • Tailwind CSS
  • Recharts
  • Playwright smoke suite

Assurance

  • ~1,350 offline tests
  • Model cards
  • Fairness audits
  • Schema-fidelity tests
  • Ruff

Features

Screens

Company overview — the landing view, with no individual on it: how many people could use support, org-level health, and the trend across the last twelve runs
Company overview — the landing view, with no individual on it: how many people could use support, org-level health, and the trend across the last twelve runs
Signals — every pattern the engine can find, grouped by category, each card one click from the people it applies to
Signals — every pattern the engine can find, grouped by category, each card one click from the people it applies to
Track record — the engine grading its own forecasts against what actually happened, per pattern, including the ones it got wrong
Track record — the engine grading its own forecasts against what actually happened, per pattern, including the ones it got wrong
Organisation — the same health scores by region, cost centre, team and manager, every figure an aggregate of five people or more
Organisation — the same health scores by region, cost centre, team and manager, every figure an aggregate of five people or more
← Back