Autocorrelation scale
shipped
Works
Fused rafts and repeating layouts — reads the pill pitch off the photo itself, immune to a mask that merged everything.
Fails
Small crops (needs many repeats), rings (reads chord not arc), single pills.
Lesson
The DT ridge is only as good as the mask; the photo carries an independent scale witness. Search from lag 4 and take the first interior peak only when the ridge over-reads (peak < ridge) — a peak above the ridge is a pair spacing.
Hexrafts 1→19/19, 1→37/37. Blanket first-peak cost 2 real photos; ridge-comparison discriminator recovered both.
Photo seeding
shipped
Works
Starved single-layer sheets: luminance maxima + Hough votes give one seed per pill where the DT has no signal.
Fails
Needs singleLayer detection to admit the blob first; seeds ~7% high on 120-pill boards.
Lesson
When the mask is one lump, the photo still shows every pill. Seed from the image, not the mask.
19 clean markers on the hex raft; dense per-pill 38/120→120/120 after the sheet test was widened.
Sheet test: one pill THICK, not disc-shaped
shipped
Works
Wide single-layer boards that are nothing like a disc.
Lesson
Compactness asked the wrong question. A wide sheet has a deep medial axis because it is wide.
Dense board 41→142 counted, 0 missed; adversarial per-pill 314→427, biggest single jump.
Cluster solver (set-level search)
shipped
Works
Overlapping/duplicated placements: delete, merge, separate — moves a per-pill refiner cannot make.
Fails
Cannot invent counts; needs obstacles or it shoves pills into neighbours.
Lesson
Overlap is a hard constraint, not a penalty. Validity is a destination: escaping moves must be legal from an illegal start. Deletion must be judged on score, not overlap-reduction.
Geometry 197→80 pairs, 59→16 duplicates, measured three ways on one build. Self-test 6/6.
Rescue stand-down on shattered masks
shipped
Works
Noise boards where "confirmed pills" are grain and medA poisons every bound.
Fails
Needs the count arm too — a dense board of small pills has no big blob for the ratio arm.
Lesson
A stage that calibrates on the mask must first ask whether the mask is credible.
cross-noise 261→13 EXACT; spurious 1929→536→170.
Fill overlap (IoU) per placement
shipped
Works
Sees what cover cannot: a stamp straddling two pills scores cover 1.0 and IoU 0.44.
Fails
Cannot separate dense-board phantoms (a phantom between two pills still covers material, IoU identical).
Lesson
cover charges only for stamp-on-background, never for mask the stamp missed. Symmetric measures or nothing. And EVERY placement must be scored — an unscored one escapes all quality control.
r-7ff7fd99: cover flat 0.93, IoU spreads 0.36–0.92 matching the visibly bad outlines.
Courtyard guard on hole filling
shipped
Works
Ring layouts: a hole that is 78% of the foreground is a courtyard, not an engraving.
Lesson
The two classes are 52× apart (engravings ≤1.5% of fg). Scale-free bound, since it runs before any radius exists.
Ring 1→12/12 EXACT, 0 spurious.
Unit ceiling from the correlation pitch
shipped
Works
Dense rafts where 3 crease fragments set the unit 17.5× too big.
Lesson
A floor without a ceiling is half a guard. There were TWO identical unit=unit2 sites; the first edit landed on the dead copy.
Dense massFrac 8.72→153 (truth 120); count 20→41 at the time.
Greedy overlap peel
reverted — measured
Works
In isolation: dense 142→124 with all 120 pills kept — no threshold can do this (real pills reach 24.7px penetration).
Fails
Costs 20 corpus images unscoped; 2 even when scoped by packed-fraction — genuinely dense boards look identical to phantom-filled ones.
Lesson
The greedy re-measure beats any fixed cut, but the trigger does not exist yet. Three traps recorded: run before out-capture; single-pill regions carry no pills array; regions may legally empty.
guard: dense-board-overlap-peel
Prefer watershed on photo-seeded blobs
reverted — measured
Works
The counts: ws closer than base on 6/6 such blobs (error 22 vs 70); adversarial 35→36.
Fails
The picture: lowering k does not re-place the region — dense fell from 120/120 found to 7/120.
Lesson
Count and placements are computed in different places; moving one without the other is the CANCELLING failure. Fix must re-place at the new k.
guard: dense-board-count-vs-picture
Bright-percentile cue for wood
reverted — measured
Works
Diagnosis solid: wood histogram is trimodal, Otsu splits grain-vs-grain; a p99 cut recovers 9/9, 19/19, 8/8.
Fails
Binary broke the gradient pipeline (rafts 19→15); graded cost 10 corpus images — coherence let it win where the default was fine.
Lesson
A mask can be right and still unusable if downstream reads gradient. Needs a texture-specific trigger.
guard: bright-percentile-cue-costs-ten-images
Gloss exemption from the darkness cull
reverted — measured
Works
Diagnosis solid: a shiny pill is a mirror; discarded blobs were 2773px/2064px vs median 1435 — plainly pills.
Fails
Size exemption cost 7 images, size+length still 3: dark smudges are frequently pill-sized AND pill-long.
Lesson
Whatever separates a dark pill from a dark smudge, it is not size or shape. Likely colour.
commit 9ba7bc9, chain recorded in place
Small-raft capacity floor
reverted — measured
Works
Fixes all three 7-pill rafts (capacity 6.8 vs floor 8).
Fails
Costs r-cc7a2ada 19→21; the raft and the real clump are identical on every field the stage has.
Lesson
1 corpus image outweighs 2 adversarial. No discriminator yet.
commit 063edda
LoG blob detection
dead end — do not retry
Works
Highest recall of anything tried (97–100%), only technique to find pills on lined paper.
Fails
The ranking is noise: worst true pill ranks #4412 of 115,328 peaks. Top-34 recovers 3/34. Shape re-ranking scored WORSE (0/34).
Lesson
Recall from 115k candidates for 34 pills means nothing. Do not revisit without a fundamentally different candidate reduction.
guard: log-blob-is-not-a-detector
Lone-witness panel override
dead end — do not retry
Works
Tempting on every image where one method is right (mass:14 on lined, truth 14).
Fails
Measured over 128 disagreeing blobs: base closest 72, mass 13, ws 5. Reached three times from different directions.
Lesson
One vivid example is not a rule. The panel exists to stop exactly this.
guard: lone-witness-cannot-win-the-panel
IoU / penetration threshold for phantoms
dead end — do not retry
Fails
Dense phantoms have IDENTICAL IoU to real pills (0.509 both); penetration separates 4× at the median but overlaps at the tails (cut at 4px drops 50 real pills).
Lesson
A phantom between two real pills covers real material. Only set-level reasoning (greedy peel, solver) can see it.
guard: dense-board-count-vs-picture
Glare fill by brightness
dead end — do not retry
Fails
The lost material is the SHADOW flank, not the highlight: missed pixels median 75 vs board 77 — indistinguishable by luminance. Adding bright pixels changed nothing (59%→59%).
Lesson
Specular pills need a COLOUR cue. Matte pills keep 93% of their footprint; shiny 74–79%, worst 37%.
commit 17fffaa
Separation sweep (method, kept)
shipped
Works
Answered the central question: matte caplets never break down to 1.7× spacing; speckled fail at 3.0× fully separated; two curves non-monotonic.
Lesson
Proximity is NOT the failure driver. The open cases are surface/board problems wearing a clustering costume.
tools/gen-separation.mjs, commit ef6747d