# School staff rosters — what was read, and what a count means

**Generated by `scripts/build_staff_rosters.py`. Do not edit.**

## A count of roster lines is not a staffing level

Rule 7. The rosters carry **no FTE**, so a 0.4 music teacher and a full-timer are
one row each. They carry **no funding source**, so nothing here says whether a
post was paid by the town or by a grant — the question this project keeps
running into. They are **a point in time**, undated within the year.

A count here is a count of names the town printed. That is a real quantity and it
is not staffing.

## There is no total to check against

A roster prints no total, so the reconciliation that guards every other extract in
this project is unavailable. The check is **line accounting**: every non-blank
line on the page is claimed as an entry or a heading, and the leftovers are
counted. A page where a third of the lines vanished looks exactly like a smaller
school unless somebody counts.

**3721 of 3721 lines accounted for** across 100 pages, 3815 entries, 15 years.

| page | FY | school | lines | claimed | unaccounted | entries | misattributed |
|---|---|---|---:|---:|---:|---:|---:|
| FY2011-p032-unknown.json | 2011 | central-office | 31 | 31 | 0 | 22 | 0 |
| FY2011-p043-high.json | 2011 | high | 40 | 40 | 0 | 0 | 0 |
| FY2011-p044-high.json | 2011 | high | 37 | 37 | 0 | 10 | 0 |
| FY2011-p045-unknown.json | 2011 | high | 34 | 34 | 0 | 46 | 0 |
| FY2011-p039-unknown.json | 2011 | passios | 42 | 42 | 0 | 0 | 0 |
| FY2011-p040-passios.json | 2011 | passios | 39 | 39 | 0 | 42 | 0 |
| FY2011-p037-unknown.json | 2011 | primary | 43 | 43 | 0 | 36 | 0 |
| FY2011-p038-unknown.json | 2011 | primary | 43 | 43 | 0 | 16 | 0 |
| FY2011-p042-turkey-hill.json | 2011 | turkey-hill | 45 | 45 | 0 | 44 | 0 |
| FY2012-p031-unknown.json | 2012 | central-office | 34 | 34 | 0 | 25 | 0 |
| FY2012-p040-unknown.json | 2012 | high | 45 | 45 | 0 | 66 | 0 |
| FY2012-p035-unknown.json | 2012 | primary | 47 | 47 | 0 | 63 | 0 |
| FY2012-p037-turkey-hill.json | 2012 | turkey-hill | 41 | 41 | 0 | 36 | 0 |
| FY2012-p038-high.json | 2012 | turkey-hill | 36 | 36 | 0 | 12 | 0 |
| FY2013-p042-unknown.json | 2013 | high | 40 | 40 | 0 | 57 | 0 |
| FY2013-p043-unknown.json | 2013 | high | 3 | 3 | 0 | 2 | 0 |
| FY2013-p037-primary.json | 2013 | primary | 41 | 41 | 0 | 69 | 0 |
| FY2013-p039-turkey-hill.json | 2013 | turkey-hill | 38 | 38 | 0 | 40 | 0 |
| FY2013-p040-high.json | 2013 | turkey-hill | 29 | 29 | 0 | 4 | 0 |
| FY2014-p091-unknown.json | 2014 | central-office | 43 | 43 | 0 | 22 | 0 |
| FY2014-p109-high.json | 2014 | high | 38 | 38 | 0 | 52 | 0 |
| FY2014-p110-unknown.json | 2014 | high | 20 | 20 | 0 | 28 | 0 |
| FY2014-p102-primary.json | 2014 | primary | 38 | 38 | 0 | 69 | 0 |
| FY2014-p105-turkey-hill.json | 2014 | turkey-hill | 43 | 43 | 0 | 61 | 0 |
| FY2015-p099-unknown.json | 2015 | central-office | 43 | 43 | 0 | 22 | 0 |
| FY2015-p114-high.json | 2015 | high | 44 | 44 | 0 | 26 | 0 |
| FY2015-p115-unknown.json | 2015 | high | 43 | 43 | 0 | 55 | 0 |
| FY2015-p107-primary.json | 2015 | primary | 42 | 42 | 0 | 44 | 0 |
| FY2015-p108-unknown.json | 2015 | primary | 36 | 36 | 0 | 38 | 0 |
| FY2015-p110-unknown.json | 2015 | turkey-hill | 46 | 46 | 0 | 25 | 0 |
| FY2015-p111-unknown.json | 2015 | turkey-hill | 33 | 33 | 0 | 42 | 0 |
| FY2016-p100-unknown.json | 2016 | central-office | 44 | 44 | 0 | 24 | 0 |
| FY2016-p119-high.json | 2016 | high | 41 | 41 | 0 | 38 | 0 |
| FY2016-p120-unknown.json | 2016 | high | 27 | 27 | 0 | 40 | 0 |
| FY2016-p116-middle.json | 2016 | middle | 41 | 41 | 0 | 51 | 0 |
| FY2016-p110-central-office.json | 2016 | primary | 46 | 46 | 0 | 62 | 0 |
| FY2016-p113-turkey-hill.json | 2016 | turkey-hill | 43 | 43 | 0 | 61 | 0 |
| FY2017-p097-central-office.json | 2017 | central-office | 41 | 41 | 0 | 18 | 0 |
| FY2017-p119-high.json | 2017 | high | 37 | 37 | 0 | 42 | 0 |
| FY2017-p120-unknown.json | 2017 | high | 27 | 27 | 0 | 40 | 0 |
| FY2017-p115-middle.json | 2017 | middle | 39 | 39 | 0 | 47 | 0 |
| FY2017-p116-unknown.json | 2017 | middle | 43 | 43 | 0 | 19 | 0 |
| FY2017-p108-primary.json | 2017 | primary | 44 | 44 | 0 | 56 | 0 |
| FY2017-p109-turkey-hill.json | 2017 | primary | 33 | 33 | 0 | 14 | 0 |
| FY2017-p112-turkey-hill.json | 2017 | turkey-hill | 45 | 45 | 0 | 58 | 0 |
| FY2018-p132-high.json | 2018 | high | 30 | 30 | 0 | 41 | 0 |
| FY2018-p133-unknown.json | 2018 | high | 26 | 26 | 0 | 40 | 0 |
| FY2018-p128-middle.json | 2018 | middle | 44 | 44 | 0 | 67 | 0 |
| FY2018-p121-primary.json | 2018 | primary | 43 | 43 | 0 | 60 | 0 |
| FY2018-p122-turkey-hill.json | 2018 | primary | 40 | 40 | 0 | 11 | 0 |
| FY2018-p124-turkey-hill.json | 2018 | turkey-hill | 41 | 41 | 0 | 58 | 0 |
| FY2019-p135-high.json | 2019 | high | 28 | 28 | 0 | 40 | 0 |
| FY2019-p136-unknown.json | 2019 | high | 25 | 25 | 0 | 34 | 0 |
| FY2019-p131-middle.json | 2019 | middle | 35 | 35 | 0 | 54 | 0 |
| FY2019-p132-unknown.json | 2019 | middle | 9 | 9 | 0 | 7 | 0 |
| FY2019-p139-central-office.json | 2019 | monty-tech | 34 | 34 | 0 | 6 | 0 |
| FY2019-p140-unknown.json | 2019 | monty-tech | 36 | 36 | 0 | 0 | 0 |
| FY2019-p124-primary.json | 2019 | primary | 19 | 19 | 0 | 10 | 0 |
| FY2019-p125-unknown.json | 2019 | primary | 42 | 42 | 0 | 62 | 0 |
| FY2019-p128-unknown.json | 2019 | turkey-hill | 32 | 32 | 0 | 44 | 0 |
| FY2020-p127-unknown.json | 2020 | high | 45 | 45 | 0 | 70 | 0 |
| FY2020-p128-middle.json | 2020 | middle | 31 | 31 | 0 | 48 | 0 |
| FY2020-p119-primary.json | 2020 | primary | 49 | 49 | 0 | 69 | 0 |
| FY2020-p123-turkey-hill.json | 2020 | turkey-hill | 44 | 44 | 0 | 62 | 0 |
| FY2021-p110-unknown.json | 2021 | central-office | 33 | 33 | 0 | 12 | 0 |
| FY2021-p121-unknown.json | 2021 | high | 44 | 44 | 0 | 73 | 0 |
| FY2021-p118-middle.json | 2021 | middle | 38 | 38 | 0 | 46 | 0 |
| FY2021-p112-unknown.json | 2021 | primary | 42 | 42 | 0 | 55 | 0 |
| FY2021-p114-unknown.json | 2021 | turkey-hill | 29 | 29 | 0 | 21 | 0 |
| FY2021-p115-unknown.json | 2021 | turkey-hill | 32 | 32 | 0 | 38 | 0 |
| FY2022-p107-unknown.json | 2022 | central-office | 32 | 32 | 0 | 13 | 0 |
| FY2022-p116-middle.json | 2022 | high | 24 | 24 | 0 | 0 | 0 |
| FY2022-p117-middle.json | 2022 | high | 39 | 39 | 0 | 49 | 0 |
| FY2022-p118-high.json | 2022 | middle | 38 | 38 | 0 | 50 | 0 |
| FY2022-p119-unknown.json | 2022 | middle | 23 | 23 | 0 | 31 | 0 |
| FY2022-p109-central-office.json | 2022 | primary | 49 | 49 | 0 | 71 | 0 |
| FY2022-p112-unknown.json | 2022 | turkey-hill | 54 | 54 | 0 | 71 | 0 |
| FY2023-p138-high.json | 2023 | high | 31 | 31 | 0 | 43 | 0 |
| FY2023-p139-unknown.json | 2023 | high | 35 | 35 | 0 | 37 | 0 |
| FY2023-p134-middle.json | 2023 | middle | 33 | 33 | 0 | 42 | 0 |
| FY2023-p126-primary.json | 2023 | primary | 34 | 34 | 0 | 39 | 1 |
| FY2023-p127-unknown.json | 2023 | primary | 48 | 48 | 0 | 45 | 0 |
| FY2023-p130-unknown.json | 2023 | turkey-hill | 37 | 37 | 0 | 31 | 0 |
| FY2023-p131-unknown.json | 2023 | turkey-hill | 33 | 33 | 0 | 28 | 0 |
| FY2024-p114-unknown.json | 2024 | high | 37 | 37 | 0 | 47 | 0 |
| FY2024-p115-unknown.json | 2024 | high | 26 | 26 | 0 | 30 | 0 |
| FY2024-p110-middle.json | 2024 | middle | 37 | 37 | 0 | 33 | 0 |
| FY2024-p111-middle.json | 2024 | middle | 36 | 36 | 0 | 25 | 0 |
| FY2024-p104-primary.json | 2024 | primary | 32 | 32 | 0 | 48 | 0 |
| FY2024-p105-primary.json | 2024 | primary | 20 | 20 | 0 | 25 | 0 |
| FY2024-p107-turkey-hill.json | 2024 | turkey-hill | 57 | 57 | 0 | 64 | 0 |
| FY2024-p108-unknown.json | 2024 | turkey-hill | 54 | 54 | 0 | 71 | 0 |
| FY2025-p109-high.json | 2025 | high | 42 | 42 | 0 | 18 | 0 |
| FY2025-p110-unknown.json | 2025 | high | 41 | 41 | 0 | 46 | 0 |
| FY2025-p105-middle.json | 2025 | middle | 27 | 27 | 0 | 22 | 0 |
| FY2025-p106-middle.json | 2025 | middle | 22 | 22 | 0 | 27 | 0 |
| FY2025-p100-primary.json | 2025 | primary | 52 | 52 | 0 | 67 | 0 |
| FY2025-p101-turkey-hill.json | 2025 | primary | 44 | 44 | 0 | 6 | 0 |
| FY2025-p102-turkey-hill.json | 2025 | turkey-hill | 43 | 43 | 0 | 36 | 0 |
| FY2025-p103-unknown.json | 2025 | turkey-hill | 42 | 42 | 0 | 28 | 0 |

## The second check: is a name on the line it was attributed to

Line accounting proves every line was **claimed**. It cannot prove a name was
claimed by the **right** line — a column read one row out of step accounts for
every line perfectly and pairs every person with their neighbour. So every
entry's name and role tokens are checked back against the printed line.

**1 entries fail this check.** 28 more have a token on
an adjacent line, which is a title printed across a line break rather than an
error — listed separately so the distinction rests on evidence.

| page | line | field | token | entry | printed |
|---|---:|---|---|---|---|
| FY2023-p126-primary.json | 7 | name | `Bastien` | Tara Bastien / Teachers: | `Teachers:                                               Kirsten Snape, Kara Slat` |

## Titles the taxonomy does not recognise

Stored with an empty `position`, never bucketed as `Other` — a title that
silently becomes `Other` makes the aggregate look complete while hiding
that the taxonomy is wrong.

| times | printed as |
|---:|---|
| 489 | `` |
| 32 | `Dept. Liaison` |
| 17 | `General workers` |
| 14 | `COTA` |
| 13 | `Social Worker` |
| 11 | `Parents` |
| 9 | `Member` |
| 9 | `Café Manager` |
| 8 | `7th` |
| 7 | `Greenhouse Asst.` |
| 7 | `AD` |
| 6 | `Manager` |
| 6 | `Dept Liaison` |
| 6 | `Phys. Therap` |
| 6 | `Parents:` |
| 6 | `Cook/Managers` |
| 6 | `Café` |
| 5 | `Chairperson` |
| 5 | `Vice-Chairperson` |
| 5 | `Department Liaison` |
| 5 | `School Psych.` |
| 5 | `Grades 6 & 7` |
| 5 | `District-wide` |
| 5 | `8th` |
| 5 | `IT Dept.` |
| 5 | `School Psych` |
| 5 | `Occup Therap.` |
| 5 | `(Tech) MS` |
| 5 | `STEM` |
| 4 | `Occup. Therap.` |
| 4 | `Dean of Students` |
| 4 | `Accounting/Data Reporting` |
| 4 | `Lunenburg Primary School Café Manager` |
| 4 | `Grades 4 & 5` |
| 4 | `Technician` |
| 4 | `2nd/grade` |
| 4 | `ID` |
| 4 | `(LMS Social Worker)` |
| 4 | `Café Employee` |
| 3 | `Clerk` |
| 3 | `Teaching Asst.` |
| 3 | `Network Administrator` |
| 3 | `Red` |
| 3 | `1st Grade` |
| 3 | `6th` |
| 3 | `Wilson Reading` |
| 3 | `202/White` |
| 3 | `205/Red` |
| 3 | `207/Red` |
| 3 | `107/White` |
| 3 | `102/Red` |
| 3 | `Grades 7 & 8` |
| 3 | `*` |
| 3 | `Cafe` |
| 2 | `School Committee Rep` |
| 2 | `Teaching Assist.` |
| 2 | `Coordinator` |
| 2 | `Technician (part-time)` |
| 2 | `Lunenburg High School Café Manager` |
| 2 | `A` |

## Two things a count here must not be read as

**FY2024 Turkey Hill is 135 entries against a typical ~60.** The FY2024 report
prints TWO complete Turkey Hill rosters, on pages 107 and 108, with different
principals — Norman Yvon and Heidi Champagne — and different staff in many
posts. Nothing on either page says which year each describes. Summing them
doubles that school for that year.

**Sixteen people appear on two rosters in a single year** — district-wide or
shared staff. That is the source, not a duplication bug. A naive dedupe
undercounts and a naive sum double-counts; the choice has to be made
deliberately and stated.

And `monty-tech` is a seventh school value covering six administrators of the
regional vocational school Lunenburg SENDS students to. They are not Lunenburg
staff and must be excluded from any district headcount.

## Names

Kept. The town publishes them annually in a public document. They also make
the aggregate checkable: a name persisting across years separates a post that
was renamed from one that turned over, and a real vacancy from a title the
report stopped printing.

