Where we start
Apex is constructed: a seeded table of 1,071 invented people in four invented entities. What is not invented is the arithmetic. The four bridge numbers and the attrition rate come out of that table by the same code as deep-dive session 1, so they are inputs a planner would actually have. Everything a planner would have to decide, how much to grow, how many will move between entities, whether the second half of the year looks like the first, is invented here and says so. That split, measured inputs on one side and chosen inputs on the other, is the whole discipline of workforce planning.
★ What you walk out with tonight. A hiring-need function that returns growth and replacement separately and asserts the identity every half, a projection loop that runs it forwards from 861, three scenarios whose output is a low and a high and never a middle, a four-entity transition matrix whose rows sum to one, and a plan sentence that names every measured input and flags every invented one.
The tank, and the line a plan draws on it
5 min liveA workforce is a stock with two pipes: joiners in, leavers out. The history is a bridge; a plan is the same bridge with the end number chosen first. Pick the target stock, estimate the leavers from a rate, and the joiners are what is left over. Nothing more elaborate is going on in any planning tool, and every elaboration is a way of splitting the stock into smaller tanks or the rate into smaller pieces.
LiveThe model is the identity, run forwards3 min▶
Deep-dive session 1 asserted start + joiners - leavers == end on history. A plan rearranges it: joiners = end - start + leavers. The end is the target, chosen. The start is measured. The leavers are not known yet, so they are a rate times a base, and that is the first place a plan can go quietly wrong. For Apex the measured half is H1 2026: 210 leavers over an average base of 941.5, which is 22.3 percent per half. Written that way, with the base named, it is a statement about one half-year of one constructed table and nothing more.
The shape of the code follows the shape of the identity. One function takes the stock at the start of a half, the planned growth and the rate, and returns the target, the growth, the expected leavers and the hires, separately. Then it asserts that start plus hires minus leavers equals the target. The assert cannot fail on a correct function, which is the point: the day someone edits the function and it does fail, the plan has stopped reconciling and the number on the slide is not a headcount any more.
Self-studyThe rate and its base travel together2 min▶
The 22.3 percent was measured on the average of the start and end stocks. Apply it to the start stock alone and it predicts more leavers than the 210 that actually left; apply it to the end stock and it predicts fewer. Neither is a mistake in arithmetic. Both are a rate used on a base it was not measured on. The hiring-need function therefore applies the rate to the average of the start and the target, the same base it came from, and the comment above it says so.
The annual figure has the same problem one level up. Doubling 22.3 gives 44.6 percent a year, which assumes the second half repeats the first and that the base stays where it was. Compounding the half-year survival gives a different annual figure under a different assumption. A plan that steps in halves needs neither: it uses the rate at the grain it was measured and never converts it. When a leader asks for the annual number, print 44.6 with the words "annualised by doubling H1, which assumes H2 repeats" beside it, every time.
The annual rate that became a hiring budget. Constructed setting, common mechanism. A planning deck carried "attrition: 44.6 percent" in a box, and a finance partner multiplied it by the year-end headcount to size the recruiting budget. The 44.6 was a doubled half-year, measured in a half that included a restructuring; the year-end headcount was a target, not a stock. Two assumptions, each reasonable in isolation, multiplied into one number nobody had chosen. The fix was not a better rate. It was a half-year model with the rate, its base and its measurement window printed in the same row.
Most hiring is replacement
5 min liveSplit the hires a plan needs into two parts and the conversation changes. Growth is the change in the stock, and it is what leaders argue about. Replacement is the leavers the plan expects at the measured rate, and at Apex's rate it is most of the number, in every scenario, including the one where the company shrinks. A flat plan is not a plan that hires nobody. It is a plan that hires everybody who leaves.
LiveGrowth plus replacement, and a flat plan still hires3 min▶
Write the target as T = H x (1 + g), with g the planned growth for the half. Then growth = T - H and replacement = a x (H + T) / 2, the expected leavers at the measured rate on the average base. Hires are the sum. At g of zero the growth term vanishes and the hires equal the replacement, which at Apex's measured rate is more than a fifth of the stock every half. At a negative g the growth term is negative, and the plan still hires unless the planned shrinkage exceeds the expected leavers.
Two consequences follow. First, the attrition rate is the biggest input to the hiring number, bigger than the growth target in any plausible range, so it deserves more scrutiny than it gets. Second, a hiring freeze is a growth decision, not a replacement decision: it sets hires to zero and lets the stock fall at the rate, and the code can print exactly how far, half by half, before anybody signs it.
Self-studyOne company rate, eight department rates, and the small tank2 min▶
A company plan built on one rate assumes every department leaves at it. Apex's departments, on the start base, ran from Sales at 50.0 percent (54 of 108) to R&D at 7.4 (7 of 94) in the same half. A plan that grows Sales and holds R&D flat needs far more hires than one that does the reverse, at the same company-level growth, and the company rate cannot see the difference. Split the tank by department and run the same function per department with its own rate.
Then watch the small tanks. HR's 10.7 percent is 8 leavers of 75; one more leaver moves it by more than a point. A department rate on a base that small is a very noisy estimate, and a plan built on it inherits the noise. The usual compromise is to use the department rate where the base is large and a pooled rate where it is not, and to say which departments got which. Deep-dive session 2's survival curves are the more careful version of the same question, asked per person rather than per tank.
The same flat plan in two industries. The BLS JOLTS survey put the 2025 mean monthly quits rate at 3.92 percent in US leisure and hospitality and 1.39 percent in manufacturing, computed from the public series in deep-dive session 3. Hold both headcounts flat and the hospitality plan needs nearly three times the voluntary replacement per head, before a single growth hire. Monthly is not annual and neither figure is a target for any one employer; the point is only that "flat" means very different recruiting loads, and the difference is entirely in the replacement term.
Three bands, and a plan on one page
5 min liveA plan with one growth rate and one attrition rate produces one number, and the number is wrong in a way nobody can see. Give each scenario a band for each rate instead, run the model across every combination in the band, and report the lowest and the highest hires. Three scenarios become three ranges; where they overlap, the scenario label matters less than the attrition assumption underneath it. Then split the tank by entity and let people move between the tanks: that is a transition-rate plan, and it fits in a four-by-five matrix.
LiveScenarios as ranges, not points3 min▶
A scenario is a named set of bands: the attrition rate somewhere between a low and a high, the growth somewhere between a low and a high. Run the model on a grid across both bands and keep the lowest and the highest total hires, and the lowest and highest end stock. Three scenarios give three ranges. That is the output. The middle of a range is not a forecast; it is the average of two guesses, and quoting it discards the only honest part of the work.
Two things become visible that a point plan hides. Overlap: if the flat range and the grow range overlap, the recruiting team cannot tell from the plan which world it is in, and the plan should say so. Which band is doing the work: narrow the growth band to a single value and see how much the range shrinks, then do the same for attrition. At Apex's rates the attrition band moves the hires more than the growth band does, which is Part 2's finding said again as a sensitivity.
Self-studyThe transition-rate (Markov) plan in one page3 min▶
Split the stock into states, here Apex's four entities, and add one more state, left. A transition matrix says, for a person in each state at the start of a half, the probability of being in each state at the end: stay, move to another entity, or leave. Each row sums to one. Multiply the start stock vector by the matrix and you get where everyone is at the end of the half, plus a count of leavers; add the hires vector and step again. That is the whole of a Markov workforce plan, and deep-dive session 1's identity holds inside it, row by row.
What is measured and what is invented must be kept apart. The exit column comes from Apex: every H1 leaver over the 1 January stock, by entity, Digital 25.0, Logistics 23.5, Manufacturing 19.3 and Retail 17.7 percent. Those rates count every leaver, including anyone who joined during the half and left before it ended, so as transition probabilities they are an approximation, and the code can split the two. The between-entity moves are invented: 291 Apex rows carry a transfer flag, but the snapshot does not say when most of them moved, so there is no measured half-year transfer rate to use. The hires vector is invented. Run the first half from 1 January and it is a back-test: the leavers must come out at 210, because the exit column was measured on that half.
The rate that doubled while the plan was in its binder. The US total nonfarm quits rate in the BLS JOLTS series averaged 2.32 percent a month in 2019, fell to 1.5 in April 2020 and reached 3.0 in November 2021, computed from the public series in deep-dive session 3. A plan built in 2019 on the 2019 rate, as a point, was overtaken in both directions inside two years: the rate fell a third below it, then rose nearly a third above it. A plan built on a band would not have contained 3.0 either, unless someone had been willing to write down a band that wide, and that willingness is most of the skill.
A plan from 861, in pandas and numpy
★ 22 min · everyone buildsSeven steps on materials/apex-staff.csv, the constructed Apex table. Steps 1 and 2 print Apex's computed counts and rate, and those numbers are printed here because the table produces them. From step 3 on, every result depends on an invented input, so no output is printed: your numbers will differ, and the comment on each invented input says so.
The measured inputs. The same headcount function as deep-dive session 1, the same window, the same assert. These four numbers are the only ones in the plan that a planner did not choose.
The rate, at the grain it was measured. One half, average base. The annual figure is printed with its assumption and then never used again.
Hiring need as a function. Growth and replacement returned separately, the rate applied to the base it was measured on.
Run it forwards, and assert the identity every half. The target of one half is the start of the next.
Three scenarios, each a pair of bands. Every combination on a five-by-five grid, and only the lowest and highest results are kept.
The transition-rate plan, four entities and an exit. The exit column is measured; the moves and the hires are invented. The first half, run from 1 January, is a back-test.
The sentence. Measured inputs with their base and window, the range and not its middle, and the word invented on everything chosen.
Narrow the attrition band to 0.223 exactly and run step 5 again. The three ranges shrink to the width the growth band alone produces, and you can see how much of the plan's uncertainty was the rate. Then widen it to the full swing the JOLTS inset showed, a rate that fell to 1.5 and then rose to 3.0, and write down honestly whether your recruiting budget could absorb the high end.
Before deep-dive session 9
30 min- Run the seven steps as written. Check that steps 1 and 2 print Apex's numbers exactly and that the back-test half in step 6 prints 210 leavers.
- Split the tank by department. Run
projectper department with its own start-base rate, and write which departments carry most of the replacement need and whether any base is too small to trust. - Find the band doing the work. In step 5, fix growth at a single value and record the width of each range; then fix attrition instead. Write one sentence on which input deserves more scrutiny.
- For a team you plan for, write the measured inputs with their base and window on one line and the invented ones on the next, and bring both lines to session 9.
Three questions
Clear all three and deep-dive session 8 gets stamped in your passport.
1 · A leader says the headcount plan for next half is flat, so recruiting can pause. What does the model say?
Growth is the part leaders argue about and replacement is the part recruiting spends the half on. A pause is a freeze, a growth decision, and the stock then falls at the rate.
2 · The model steps in half-years. Why does it use 22.3 percent per half rather than 44.6 percent a year divided by two?
Every conversion adds an assumption. A model that steps at the grain of the measurement needs none of them, and the rate keeps its base and window attached.
3 · Why does each scenario report a low and a high for total hires rather than one number?
A point plan is wrong in a way nobody can see. The US quits rate went from 1.5 to 3.0 inside two years; a band is how a plan admits that before it happens.
What this session teaches, and where it came from
Every fact on this page, and its verification tier, is recorded in the course's source map.
Deep-dive session 8 cheat sheet · pin this
Eight sessions have fed people data into code. Deep-dive session 9 asks what the code may not be fed, and what the law says about the decision it produces: GDPR Article 22 on solely automated decisions and Article 9 on special categories such as health, the EU AI Act's Annex III point 4, which lists recruitment and promotion among high-risk uses, and New York City's Local Law 144 bias audit. Then the tool Reuters reported Amazon had scrapped, a study of what happens when managers override a hiring test, and Goodhart. No model is trained. The build-along writes the checklist and the list of what a model may not see.