Internal · method record · Lear Body 2 pre-study · 26–27 Aug 2026
What was tried, what was measured, what was discarded and why — the audit trail behind the work-content findings.
yolo11n-pose on CPU · region = the hand-drawn box with its bottom extended to the frame
edge · engaged = wrist depth below shoulder > 0.6 × torso · 15 s sampling for levels, 1 s for events.
Engagement MAE 0.28, presence 0.39, within one operator on 97% of frames.
chronological · every branch that changed the answer
SAM2 person count, --interval 5 --confidence 0.9, region boxes drawn by hand on 12 cameras.
✗ Frames scored 0 operators visibly contained 2–4. Confidence sweep on B2C12: mean 0.84 at conf 0.9, 1.49 at 0.7, 2.28 at 0.5 — a 2.7× swing on identical footage, and 43% of frames read zero at the shipped default.
Recovered the missed operators — and started counting people across the aisle.
✗ Ground truth on 4 frames: at conf 0.5 a station with 3 real operators read 9. The two errors partially cancelled at conf 0.9, which is what made the original settings look plausible.
Chosen by eye from the crops; validated on 2 cameras against manual counts.
✗ Applied to only half the cameras, which introduced a systematic bias: the six untrimmed read 3.13 mean against 1.91 for the six trimmed, on the same plan of 2.
Auto-detected the stripe per camera, set the top edge 5% of frame height above it.
✗ 4–5× too tight on all twelve. Measured apparent person height per camera: 62–450 px, against a margin of only 24–97 px. B2C11 read 0.84 operators because its people were outside the box entirely.
Swept each top edge to maximise "capture" — the share of engaged detections falling inside the box — capped at ≤1 extra aisle person.
✗ Circular. Capture was scored against pose's own detections, which include people who are not that station's operators, so maximising it maximised admitting bodies. Six-way test: tuned tops scored worst of all variants (engaged MAE 0.61).
Six-way comparison against 36 hand-scored frames settled it.
✓ Best of six: bodies 0.39, engaged 0.28, 97% within one. Extending down adds board and no people; raising the top adds people who should not count. An independent person-height calculation reproduced the original y1 to within 4 px on two cameras and 40 px on five.
Triggered by the question "would hands be more robust than whole bodies?" — the answer turned out to be a model swap, not a rule change.
✓ A pose model must fit a whole skeleton, so it rejects the partial far-aisle bodies that inflated every detector. At B2C17: SAM2 11, yolo11n 7, pose 2, truth 2. This solved the region problem that steps 03–05 had been attacking from the wrong side.
Board zone taken as everything below the yellow stripe.
✗ Returned 0 on frames with operators plainly working. Keypoints were found at 0.74–0.98 confidence but sat 56–187 px above the line. The stripe is painted on the floor; the board is an elevated bench, so hands appear above a floor marking in image space.
(wrist_y − shoulder_y) / torso_length > 0.6, computed per person.
✓ Self-normalising, so immune to camera height, resolution and the floor-versus-bench geometry that broke step 08. Needs no board polygon at all, which removes a calibration step. MAE 0.28 — better than any method's error on presence.
36 frames hand-scored across 9 stations · same regions, same frames
| Model | Runs on | MAE | Bias | Exact | ±1 | Latency | |
|---|---|---|---|---|---|---|---|
| SAM2 persons | remote GPU | 2.03 | +1.92 | 27% | 52% | ~12,400 ms | dropped |
| yolov8n persons | CPU | — | +0.20 | — | — | 68.6 ms | not pursued |
| yolo11n persons | CPU | 1.28 | +0.78 | 33% | 75% | 15.7 ms | dropped |
| yolo11n-pose persons | CPU | 0.39 | +0.11 | 69% | 94% | 53–246 ms | shipped |
| yolo11n-pose reach>0.6 | CPU | 0.28 | +0.06 | 75% | 97% | same call | shipped |
six definitions · same 36 frames · same model
| Region definition | Bodies MAE | Bias | Engaged MAE | Bias | ±1 | |
|---|---|---|---|---|---|---|
| Original hand-drawn, bottom extended | 0.39 | +0.11 | 0.28 | +0.06 | 97% | shipped |
| Second redraw, as drawn | 0.42 | −0.14 | 0.42 | −0.25 | 91% | clips heads |
| Original hand-drawn, as drawn | 0.67 | +0.28 | 0.44 | +0.00 | 94% | |
| Second redraw, bottom extended | 0.64 | −0.31 | 0.58 | −0.25 | 88% | |
| Tuned tops, bottom extended | 0.61 | +0.22 | 0.61 | +0.17 | 86% | |
| Tuned tops, as drawn | 0.81 | +0.47 | 0.61 | +0.22 | 83% | worst |
The two redraws sit either side of the original: the second redraw under-counts (bias −0.25, clipping heads to keep the aisle out), the tuned tops over-count (+0.22, admitting bench workers). Aisle discipline in the redraw was excellent on its own terms — 6 aisle admissions out of 230, 98% purity — but purity was bought with capture.
not enforced by the service · chosen from the excursion-duration distribution
Excursions away from a station's own baseline, measured at 5 s and at 1 s. The distribution decides the interval, not the compute budget.
| Excursion length | 5 s sampling | 1 s raw | 1 s median-3 | 1 s median-5 |
|---|---|---|---|---|
| 1 sample | 34% | 4,368 | 933 | 553 |
| 2 samples | 19% | 2,134 | 796 | 408 |
| 20–39 s | — | 314 | 436 | 434 |
| 40–79 s | — | 65 | 163 | 217 |
| 80 s+ | — | 10 | 30 | 49 |
reached a conclusion, then failed a check
| Claim | What killed it |
|---|---|
| Extra operators stand significantly upstream | The null pooled all normal-frame positions into one distribution. Stations have multiple standard work positions (B2C17 shows 3 modes, IQR 0.560) — a second person simply occupies the other one. Also an order-statistic artifact inflated the first estimate ~3×. |
| Entry edge identifies work-ahead behaviour | Attributes to the wrong station. A person entering station N from downstream most likely belongs to N+1. Replaced by exit direction for people who first appear mid-frame — those were demonstrably working there. |
| Staffing is phase-locked to the cycle (R² 45%) | Held at Station 1, does not generalise. Tested at each station's own period on 1 s data: median R² 4.2%, only 2 of 23 station-hours above 15%. The period generalises; the rhythm does not. |
| Chase rate as "% of boards chased" | Exceeded 100% everywhere. ByteTrack fragments an occluded person into several tracks, inflating absolute counts by an unknown factor. Replaced by share of the station's own appearances, where fragmentation largely cancels — which reorders the ranking (rank correlation 0.62). |
| B2C17/B2C13 idle time means operators waiting | They also have the highest chase rates. Much of that "idle" is likely operators walking downstream after boards, not standing. Unresolved — needs a walking-versus-standing classifier, and it inverts the recommended intervention. |
each confirmed by an independent method
| Finding | Value | Independent confirmation |
|---|---|---|
| Pitch | 175 / 176 / 179 s | Board QR tracking · occupancy autocorrelation at 15 s · same at 1 s. Three methods within 4 s. |
| Cameras do not overlap | 0 collisions | ORB matching (4–9 RANSAC inliers of 6,000 keypoints) · visual inspection · no board ID in two cameras at the same instant. |
| Exit direction is behaviour | r = −0.01 | Against mean working position. Net drift agrees: all six chasing stations drift downstream, B2C12 drifts upstream. |
| No cascade between stations | +0.14 / +0.02 | Lag 0 and lag +1 across 9 adjacent pairs. Spatial pattern is build-then-absorb, never accumulate. |
| Work content ≠ chase index | r = +0.30 | Weak by design — they measure work done versus work that did not fit. Both are needed to classify a station. |
| Line runs faster than takt | 179 s vs 211 s | Takt supplied by Lear; pitch measured. Yields ~82 min/shift of downtime cushion. |
measured on an M-series laptop, 10 cores
all retained · ~/Downloads/Lear
| Directory | Rows | Configuration | |
|---|---|---|---|
| results_pose_v2 | 5,381 | pose, present + engaged, 15 s, final regions | authoritative |
| results_tracks | 14,023 | ByteTrack over yolo11n at 12 fps, entry/exit edges | authoritative |
| results_local_1s_orig | 80,497 | yolo11n persons at 1 s — event structure, period detection | supporting |
| results | 5,381 | SAM2 at 15 s, final regions — method comparison | supporting |
| results_tracks_t | in progress | as above plus per-track timestamps, for the sub-block cascade test | running |
| results_stripe_anchored | 16,101 | SAM2 5 s, stripe regions — superseded, kept for audit | superseded |
| results_trimmed35 | 16,101 | SAM2 5 s, 35% trim on 6 cameras — superseded | superseded |
| results_preview | 1,362 | SAM2 60 s scoping pass at conf 0.9 | superseded |
Eight region definitions are on disk as boxes_*.json,
every one reproducible via draw_all_boxes.py --configs-only. All batch runners are resumable —
row-level for counting, chunk-level for tracking — and resume was verified by SIGKILL rather than
assumed.
known limits of this record