learn-people-analytics-with-phoebe / Deep-dive session 9 of 10
Learn People Analytics with Phoebe · Deep-dive session 9 of 10

AI on people data, and what the law forbids

Every earlier session produced a number a person read. A model produces a decision, or something close enough to one that people treat it that way, and people data is where that stops being a technical question. Tonight draws the fence: GDPR Article 22 on decisions made solely by automated processing, Article 9 on special categories such as health and trade union membership, the EU AI Act's Annex III point 4, which lists recruitment, promotion, termination and monitoring among its high-risk uses, and New York City's Local Law 144, which since 5 July 2023 has required an annual independent bias audit. Then two stories about what goes wrong inside the fence: a recruiting tool Reuters reported Amazon had scrapped, and a study of what happened when managers overrode a hiring test. No model is trained tonight. The build-along writes the checklist and the list of what a model may not see, and runs both against Apex.

🟡 Core People analysts, HR tech owners, anyone asked to "just add a model" Python, pandas 45 min
0-3 · Welcome 3-18 · The fence, the past, the override 18-40 · Build-along: the checklist in code 40-45 · Q&A
Part 0

Where we start

The request usually arrives as a sentence: can we predict who is going to leave, or rank the applicants, or flag the managers whose teams are at risk. Each is a model on people data, and each can be built in an afternoon on a table like Apex. Whether it should be, what it may be fed, and who has to check it afterwards are questions the law has already partly answered, and they are cheapest to answer before the first line of modelling code. Apex is constructed and nobody in it is real; the columns are the shape of a real export, which is what makes the fence concrete.

🎫 Clear all three quiz questions to stamp your passport Live = presented in the 45 minutes Self-study = the full depth, after class ★ Build-along = run the code yourself

★ What you walk out with tonight. A may-not-see list with the reason and the rule beside every entry, a scan that finds the Apex columns able to carry health information, an outcome list that keeps a model from being fed its own answer, a seven-question checklist that refuses to report ready while any answer, evidence or owner is empty, and an audit record that says in one sentence what was dropped, what was allowed, and that no model was trained.

Part 1 · covers GDPR Articles 22 and 9, the EU AI Act and NYC Local Law 144

The fence around a people model

5 min live

Four rules, and each asks a different question. GDPR Article 22 asks about the decision: was it made solely by automated processing, with a legal or similarly significant effect on the person? Article 9 asks about the data: does it include a special category, health and trade union membership among them? Annex III point 4 of the EU AI Act, Regulation (EU) 2024/1689, asks about the use: recruitment, selection, promotion, termination, task allocation and monitoring are listed as high-risk. New York City's Local Law 144 of 2021 asks about the audit. A people model can clear one and fail another, so the checklist asks all four.

THE FENCE: WHAT A PEOPLE MODEL MAY SEE, AND FOUR RULES ON THE GATE Department Company group tenure is_transfer inside: may be fed, after review Resignation Reason, free text, on the fence can carry health: Personal/Health holds 15 of the 210 leavers OUTSIDE: ARTICLE 9 health trade union membership HELD FOR THE AUDIT sex, race/ethnicity the audit sees them; the model does not GDPR Article 22 · the decision solely automated, significant effect GDPR Article 9 · the data special categories: health, union AI Act, Annex III 4 · the use hiring to monitoring: high-risk NYC Local Law 144 · the audit annual, independent, published Apex's columns and the 15 are from the constructed table; the four rules each ask a different question. The law in depth lives in the GDPR, PDPA and AI governance courses; the fence is the map, not the territory.
🔍 Click to zoom - the hachured column is the one nobody thinks of as health data, and it sits on the fence because a person wrote it in their own words
LiveFour rules, four different questions3 min▶

The decision (GDPR Article 22). It concerns decisions based solely on automated processing that produce legal or similarly significant effects on a person. A score that ranks applicants and a person who then decides is a different situation from a score that rejects applicants with nobody looking, and the difference has to be real: a reviewer who approves every score unread is automation with a signature. The data (GDPR Article 9). Special categories of personal data, health and trade union membership among them, carry stricter conditions for processing at all. The use (EU AI Act Annex III point 4). Systems used for recruitment and selection, for decisions on promotion and termination, for task allocation and for monitoring are listed as high-risk, which brings obligations that attach to the use, whatever the model. The audit (NYC Local Law 144). Enforced from 5 July 2023, it requires an annual independent bias audit of automated employment decision tools, a published summary of it, and impact ratios by sex and by race/ethnicity.

Read them as four gates, not one. An attrition model that only informs a manager may sit outside Article 22 and still be a monitoring use under Annex III. A screening tool that never sees a special category can still owe a bias audit. None of the four is the whole law of anywhere, and the jurisdiction you work in may add its own; the checklist leaves a line for it.

Self-studyWhat each rule does not say, and where the law in depth lives2 min▶

The four rules are named so that a people analyst recognises when a request has crossed into them. Each has exceptions, conditions and safeguards that decide real cases, and those belong with the courses that teach the law. The GDPR course covers Articles 22 and 9 in depth; the PDPA course is the Singapore counterpart; the AI Governance and EU AI Act course covers what a high-risk classification requires; the Data Governance course covers who owns a column and who may grant access to it.

Local Law 144's audit reports impact ratios, and an impact ratio is a selection rate divided by the highest group's selection rate. The four-fifths rule of thumb (29 CFR 1607.4(D)) and a working screening simulator live in the AI + HR course; deep-dive session 4 computed the ratio once on a constructed funnel. The habit carried here is narrower: whenever a ratio is printed, the two rates it divides are printed beside it.

Real world

The column nobody thought was health data. Constructed setting, real mechanism, on the Apex table itself. The export carries a free-text Resignation Reason typed by whoever processed the exit, and a reason_category derived from it. Fifteen of the 210 leavers fall in Personal/Health, and at least one of the free-text entries mentions maternity. Nobody designed a health field. It appeared because a person was asked why they left and answered honestly. A model fed "all the columns" would be fed that, and so would every dashboard that joins on it.

Part 2 · covers the tool that learned the past, and Goodhart

A model fitted to past decisions learns the decisions

5 min live

A people model is usually trained on what the organisation did before: who was hired, who was promoted, who was rated highly, who stayed. Whatever shaped those decisions is in the labels, and a model rewarded for reproducing the labels reproduces it. Removing the protected column does not remove it, because the pattern is carried by everything that correlates with the column. And once the model's score is used to choose, tomorrow's decisions are the model's, and they become the next training set.

A MODEL FITTED TO PAST DECISIONS LEARNS THE DECISIONS past decisions who was hired a model fitted to them a score per applicant women's REPORTED, 2018 a word it penalised hired by the score, then fed back as the next pile Goodhart, in Strathern's 1997 wording a measure made a target stops measuring Reported by Reuters, 10 October 2018 (Jeffrey Dastin); secondary, confirmed through a reproduction. The loop is the general mechanism, drawn schematic; nothing here describes how that tool was built.
🔍 Click to zoom - the moss loop is the part that makes it worse over time: the score chooses, and the chosen become the next lesson
LiveWhy removing the protected column is not enough3 min▶

Delete the sex column and a model trained on past hiring can still separate the groups, through anything that differs between them in the pile: a word on a resume, a society, a school, a gap in the dates, a part-time spell. The reported case is the cleanest illustration. Reuters reported on 10 October 2018 that Amazon had scrapped an experimental recruiting tool that penalised resumes containing the word "women's". The penalised item, as reported, was a word, not a demographic field. The report is secondary here, confirmed through a reproduction, and it is quoted as reported, not as a finding about any system now in use.

The consequence for practice is a split that looks odd at first. The model may not see the protected attribute, and the audit must. A proxy can only be found by someone who holds the attribute and checks whether the features predict it, and whether the model's scores differ by it. So the attribute is kept, held apart from the modelling table by someone other than the model builder, and used for exactly that. Local Law 144's impact ratios by sex and race/ethnicity cannot be computed any other way.

Self-studyGoodhart, and the score that becomes a target2 min▶

The usual wording of Goodhart's law is Marilyn Strathern's, from 1997: when a measure becomes a target, it ceases to be a good measure. People data is where it bites hardest, because the people being measured can see the measure. A time-to-fill target is met by filling the seat with whoever is available. An attrition target is met by moving an exit date across a quarter boundary. A model's risk score, once managers are judged on the number of high-risk people in their team, starts to measure how managers describe their teams.

The check is one question on the checklist: is the score, or the metric the model was trained to predict, also a target somebody is rewarded on? If yes, the score will drift from the thing it was built to measure, and the drift will look like improvement. Foundations session 6 asks the same question of every dashboard row.

Real world

The tool that was scrapped. As reported by Reuters on 10 October 2018 (Jeffrey Dastin), Amazon scrapped an experimental recruiting tool that penalised resumes containing "women's". The lesson most people take is about one company. The more useful one is about the method: any model fitted to past selection decisions inherits the reasons behind those decisions, stated or not, and the only way to know which reasons it inherited is an audit that holds the attributes the model was never given.

Part 3 · covers discretion versus the test

When the human overrides the score

5 min live

Article 22 makes a human in the loop sound like the whole answer. The best evidence on what humans in the loop actually do is more uncomfortable. Hoffman, Kahn and Li 2018, "Discretion in Hiring", Quarterly Journal of Economics 133(2) 765-800, studied firms that introduced a job test and let managers override it. Test-based hiring raised the completed tenure of hires by about 25 percent, 0.23 log points; and the hires managers made by overriding the test left sooner. Neither the law nor the paper says the other is wrong. They ask different questions, and the habit that serves both is to log every override and audit it.

DISCRETION VERSUS THE TEST, IN TWO FINDINGS the test a manager's call 1 · introducing the test before the test after the test about 25% longer tenure completed tenure of hires, 0.23 log points 2 · overriding the test as the test said test overridden LEFT SOONER bar lengths schematic Hoffman, Kahn and Li 2018, QJE 133(2) 765-800. About 25 percent (0.23 log points) is the paper's figure. Panel 2's bar lengths are schematic: the paper reports that hires made by overriding the test left sooner.
🔍 Click to zoom - the wine bar is the override; the paper measured it, and a people team can measure its own the same way if it logs the overrides
LiveWhat the study found, and what it does not license3 min▶

Two findings, both primary, from the full text. Introducing the test raised the completed tenure of hires by about 25 percent (0.23 log points). And among hires made once the test existed, those made by overriding it left sooner. On that outcome, managers' discretion was on average worse than the test.

What it does not license is "remove the humans". Tenure is one outcome, chosen by the study; it is not fairness, and a test can raise tenure while selecting unevenly across groups, which is what an impact ratio exists to catch. And Article 22 restricts decisions made solely by automated processing whatever their tenure. The two sources are not in conflict; they answer different questions. The practical synthesis is modest: keep the human, make the override visible, and record every one so that the organisation can ask of its own data what the paper asked of the firms it studied.

Self-studyThe override log, and the audit as a habit2 min▶

An override log has five columns: who was recommended, who was chosen, who chose, the reason in a sentence, and the date. That is enough to compare, a year later, the outcomes of hires made as recommended and hires made against the recommendation, and to compute both groups' selection rates by the audit attributes. It is also enough to see a reviewer who never overrides anything, which is the signature of a human in the loop in name only.

The audit is then a habit rather than an event: the same checklist re-run each year, the same may-not-see list re-applied whenever a column is added to the export, the same impact ratios computed with both rates printed. Local Law 144 makes the annual cadence a legal requirement for tools in its scope; for everything else it is simply the cadence at which a people model drifts.

Real world

The finding that cuts against the obvious rule. Hoffman, Kahn and Li 2018 compares a test with the people allowed to overrule it, inside the same firms. The result, that overrides left sooner, is the reverse of the intuition that a human always improves on a score. The tension is real, and the literature has not resolved it. What it offers is the one design that lets any employer find out which way it runs in its own hiring: a logged override, and an outcome measured later.

Build-along

The checklist and the may-not-see list, on the Apex columns

★ 22 min · everyone builds

Seven steps on materials/apex-staff.csv, the constructed Apex table, and not one of them trains a model. The use under review is invented: an attrition-risk list for managers. The code decides what that list may be fed, finds the columns that can carry a special category, keeps the model from its own answer, and writes a checklist that will not report ready while any question is open. Printed values are Apex's where the source map states them; everything else prints on your machine.

SEVEN STATIONS, NO MODEL 1 · columns 1,071 rows read the list 2 · may not Article 9 audit fields 3 · scan free text 15 health 4 · outcome the answer not an input 5 · checklist 7 questions all open 6 · audit() drop, allow with reasons 7 · record no model trained No station trains a model. Station 5 refuses to report ready while any answer, evidence or owner is empty. Keep the checklist beside the code it governs. Session 10 defends one number in public.
🔍 Click to zoom - the wine station is the gate; the moss one is where each proposed input gets a verdict and a reason in words

Read the columns before anything else. A people model is usually proposed as "use the export". The first step is to read what the export actually holds.

★ Step 1 · columnsimport json import pandas as pd d = pd.read_csv("materials/apex-staff.csv", parse_dates=["Date Join", "Last Day"]) print(len(d)) # 1071 print(list(d.columns)) # ['Company', 'Staff ID', 'Department', 'Service Year Date', 'Date Join', 'Last Day', # 'Resignation Reason', 'is_attrited', 'left_2026', 'company_tenure_years', 'group_tenure_years', # 'tenure_at_exit_years', 'is_transfer', 'pre_transfer_years', 'exit_month', 'tenure_band', 'reason_category']

The may-not-see list, with a reason on every line. Special categories first, then the audit attributes the model may not see and the audit must, then free text, then a line for your own jurisdiction.

★ Step 2 · may not seeMAY_NOT_SEE = { # GDPR Article 9 special categories: health and trade union membership among them; read the article for the full list "health": "GDPR Article 9 special category", "trade union": "GDPR Article 9 special category", # held apart for the audit: the audit may see them, the model may not "sex": "audit attribute (NYC Local Law 144 impact ratios): the audit may see it, the model may not", "race/ethnicity": "audit attribute (NYC Local Law 144 impact ratios): the audit may see it, the model may not", # anything that can carry the above "free text": "can carry any of the above in the writer's own words", # the line only your own law can fill "your local list": "fill in from your own law before use; the GDPR and PDPA courses start it", }

Scan the export for what can carry a special category. By shape (free text) and by content (a category value that is health).

★ Step 3 · scanFLAGGED = {} for c in d.columns: col = d[c] is_text = col.dtype == object and col.nunique() > 20 if is_text and c != "Staff ID" and not c.startswith(("Date", "Last", "Service")): FLAGGED[c] = MAY_NOT_SEE["free text"] if (d["reason_category"] == "Personal/Health").any(): FLAGGED["reason_category"] = "has a Personal/Health value: " + MAY_NOT_SEE["health"] print(list(FLAGGED)) # ['Resignation Reason', 'reason_category'] print(int((d["reason_category"] == "Personal/Health").sum())) # 15, of the 210 leavers HEALTH_WORDS = "health|medical|illness|sick|maternity|pregnan" print(int(d["Resignation Reason"].str.contains(HEALTH_WORDS, case=False, na=False).sum())) # a word search finds its own count; neither it nor the category is the full list, which is why the column goes

Keep the model from its own answer. For an attrition-risk list the outcome is leaving, and every column written at or after the exit is the answer in disguise.

★ Step 4 · outcome and identifiersOUTCOME = {"Last Day", "is_attrited", "left_2026", "tenure_at_exit_years", "exit_month", "Resignation Reason", "reason_category"} # the answer, or written after it IDENTIFIERS = {"Staff ID"} # the person, not a property of the person print(sorted(OUTCOME & set(d.columns)) == sorted(OUTCOME)) # True: all seven are in the export

The checklist, as a dict that knows it is unfinished. Seven questions, each with its source. Answer, evidence and owner start empty, and ready says no until all three are filled for every question.

★ Step 5 · the checklistCHECKLIST = { "art22_decision": {"ask": "Is any decision with legal or similarly significant effect made solely by the tool?", "source": "GDPR Article 22"}, "art9_data": {"ask": "Does any input carry a special category, directly or through free text?", "source": "GDPR Article 9"}, "annex_iii_use": {"ask": "Is the use recruitment, selection, promotion, termination, task allocation or monitoring?", "source": "EU AI Act, Regulation (EU) 2024/1689, Annex III point 4"}, "ll144_audit": {"ask": "Used for employment decisions in New York City? Then: annual independent bias audit, " "published summary, impact ratios by sex and race/ethnicity.", "source": "NYC Local Law 144 of 2021, enforced from 5 July 2023"}, "rates_printed": {"ask": "Are selection rates by group printed beside any impact ratio?", "source": "29 CFR 1607.4(D); the simulator lives in the AI + HR course"}, "override_log": {"ask": "Is every human override of the score logged with a reason, and compared on outcomes later?", "source": "Hoffman, Kahn and Li 2018, QJE 133(2) 765-800"}, "goodhart": {"ask": "Is the score, or the metric it optimises, also a target somebody is rewarded on?", "source": "Goodhart's law, in Strathern's 1997 wording"}, } for item in CHECKLIST.values(): item.update(answer=None, evidence=None, owner=None) def ready(checklist): open_items = [k for k, v in checklist.items() if v["answer"] is None or not v["evidence"] or not v["owner"]] return len(open_items) == 0, open_items print(ready(CHECKLIST)) # (False, [all seven keys]): nothing is ready until someone answers

Audit a proposed feature list. Every input gets a verdict and a reason in words. "Allowed" still means pending the proxy review, which needs the audit attributes that Apex, like most exports, does not hold.

★ Step 6 · audit()def audit(features): verdict = {} for f in features: reasons = [] if f in IDENTIFIERS: reasons.append("an identifier, not a feature") if f in FLAGGED: reasons.append(FLAGGED[f]) if f in OUTCOME: reasons.append("the outcome, or written after it") verdict[f] = ("drop: " + "; ".join(reasons)) if reasons else "allowed, pending the proxy review" return verdict proposed = ["Department", "Company", "group_tenure_years", "is_transfer", # invented proposal "Resignation Reason", "reason_category", "left_2026", "Staff ID"] for f, v in audit(proposed).items(): print(f"{f:20s} {v}") # Resignation Reason drop: can carry any of the above in the writer's own words; the outcome, or written after it # reason_category drop: has a Personal/Health value: GDPR Article 9 special category; the outcome, or written after it # left_2026 drop: the outcome, or written after it # Staff ID drop: an identifier, not a feature # (the four others print "allowed, pending the proxy review") allowed = [f for f, v in audit(proposed).items() if v.startswith("allowed")]

The record, and the sentence. What was dropped and why, what was allowed and on what condition, which questions are open, and the fact that no model was trained.

★ Step 7 · the recordok, open_items = ready(CHECKLIST) record = { "use": "attrition-risk list for managers, proposed", # invented use "inputs_allowed": allowed, "inputs_dropped": {f: v for f, v in audit(proposed).items() if v.startswith("drop")}, "may_not_see": list(MAY_NOT_SEE), "checklist_open": open_items, "proxy_review": "needs sex and race/ethnicity, held apart by someone other than the model builder; not in Apex", "model_trained": False, } sentence = (f"No model trained. {len(record['inputs_dropped'])} of {len(proposed)} proposed inputs dropped, each with a reason; " f"{len(allowed)} allowed pending a proxy review that needs attributes held elsewhere. " f"{len(open_items)} checklist questions open, so the tool is {'ready' if ok else 'not ready'} to build.") print(sentence) with open("apex_ai_checklist.json", "w") as fh: json.dump(record, fh, indent=2)

Answer one question and run step 5 again. Fill answer for Article 22 but leave owner empty, and ready still says no. That is deliberate: an answer nobody owns is an opinion. Then add a column called union_rep to a copy of the table and re-run step 3, and decide whether the scan should have caught it by name. It will not, which is why the may-not-see list is read by a person every time a column is added.

Homework

Before deep-dive session 10

30 min
  1. Run the seven steps as written, then add your own jurisdiction's protected characteristics to the last line of MAY_NOT_SEE, with the rule beside each.
  2. Answer the checklist for one real people tool you use or have been asked for: an answer, the evidence, and an owner for each of the seven questions. Count how many you could not fill.
  3. Design the override log for that tool: the five columns, where it lives, who reads it, and the outcome you would compare a year later.
  4. Find the free text. List every free-text field in your own HR export and write which of the four rules each one could touch.
Check yourself

Three questions

Clear all three and deep-dive session 9 gets stamped in your passport.

1 · A colleague proposes feeding Resignation Reason into a model that predicts who will leave, "because it is the most informative column". What is wrong with it?

It is informative because it is the answer. Step 4 drops it as an outcome and step 3 drops it as free text; either reason alone is enough.

2 · The model never sees sex or race/ethnicity. Why keep those attributes at all?

The model may not see them; the audit must. That split, with a different person holding the attributes, is the design.

3 · Hoffman, Kahn and Li found that hires made by overriding a job test left sooner. What follows for a people team?

The paper measured about 25 percent longer tenure from test-based hiring and shorter tenure for overrides. It did not measure fairness, and it does not change what the law requires of a solely automated decision.

Sources covered

What this session teaches, and where it came from

✓GDPR Article 22 (solely automated decisions with legal or similarly significant effects) and Article 9 (special categories, health and trade union membership among them)Primary; named, not taught in depth; the GDPR and PDPA courses own the law
✓EU AI Act, Regulation (EU) 2024/1689, Annex III point 4: recruitment, selection, promotion, termination, task allocation and monitoring are high-riskPrimary (EUR-Lex); the AI Governance course owns what the classification requires
✓New York City Local Law 144 of 2021, enforced from 5 July 2023: annual independent bias audit, published summary, impact ratios by sex and race/ethnicityPrimary; the four-fifths rule and the screening simulator stay in the AI + HR course
✓Hoffman, Kahn and Li 2018, "Discretion in Hiring", Quarterly Journal of Economics 133(2) 765-800: test-based hiring raised completed tenure by about 25 percent (0.23 log points); hires made by overriding the test left soonerPrimary (full text read by the checker)
◐Reuters, 10 October 2018 (Jeffrey Dastin): Amazon scrapped an experimental recruiting tool that penalised resumes containing "women's"Secondary, confirmed through a reproduction; reported, and nothing claimed about how the tool was built
◐Goodhart's law in Strathern's 1997 wordingNamed as a principle; no measured claim attached
✓The Apex columns; Personal/Health 15 of 210 leavers; the checklist, may-not-see list and audit functionComputed from the constructed Apex table; the proposed use and feature list are invented; standard practice, no single source, for the checklist form; no model trained

Every fact on this page, and its verification tier, is recorded in the course's source map.

Deep-dive session 9 cheat sheet · pin this

Four gatesArticle 22 the decision, Article 9 the data, Annex III point 4 the use, LL144 the audit.
Free text is special-category dataApex: Personal/Health holds 15 of 210 leavers, in a column nobody designed for health.
The model may not see it; the audit mustHold sex and race/ethnicity apart, with someone else, for proxy checks and impact ratios.
A model learns the decisionsFitted to past choices, it inherits their reasons. Reuters, 2018, reported.
Log the overrideHoffman, Kahn and Li 2018: overrides left sooner. Keep the human; record every call.
GoodhartA score that becomes a target stops measuring. Ask it on the checklist.