AI3D-382 · detection pass 7: ELM seed rejection — the last per-segment attempt, and it failed

6 Sep 2026 · segments 018 / 060 / 066 / 085 · roots: r5pr (pass-6 code, per record) | r6pr (pass-7 code, per record + hard-blob cell hysteresis) | r6nc (per-segment + ELM seeding, NO clamp) | r6 (per-segment + ELM seeding + clamp) · runs at wt-vs-382 @ 18c9d73, review fixes on top · previous rounds: passes 2–3 · pass 4 · pass 5 · pass 6 · background: what the DEM (Digital Elevation Model) bias was

  1. FINAL TCS VERDICT: per-segment ground does not ship. tcs_ground.per_segment = false, elm_enabled = false, segment_clamp_to_record = true (correct, but inert while per_segment is off). Four rounds of per-segment TCS have never once produced a metric that justifies it.
  2. Pass 7 was the retune pass 6 asked for: ELM-style neighbourhood low-outlier rejection on the seed grid — a cell minimum more than 0.5 m below the 11×11 median of its neighbours is treated as noise and either re-seeded from the histogram or emptied — plus hard-blob cell hysteresis.
  3. ELM made the no-clamp case WORSE than pass 6 on every axis. Against r5 (same config, no ELM): 066 union kept fraction 0.4002 → 0.3770, 066 truth-spot z_ground p5 −2.708 → −3.981 m with 25 clusters more than a metre low, 085 GT precision 0.4915 → 0.4691 with +21 298 hard FP, M3 38 294 → 40 419, churn 5.19 % → 5.91 %. Six of nine canaries fail.
  4. The mechanism is visible in the telemetry. A plain 11×11 median on a road corridor sits up on the verge or the barrier, so legitimate carriageway minima get rejected: ELM empties 15 % of populated cells on 066 and 085 — the two segments whose DEM was already worst — and hands them to SMRF interpolation, which sinks further than the raw min-Z it replaced.
  5. With the clamp (r6) it is canary-clean on ground, the sign and GT, and still not worth shipping. Zero truth-spot clusters below −0.5 m anywhere, the 018 sign back at ml 0.6653, 085 GT neutral — but the billboard cell still returns, the 018 west-edge n 41 953 tree is still rejected, a delineator on 085 is newly lost that pass 6 kept, and the gains are third-decimal (M1_hi +0.0029, M2 −0.0005) for +18 % runtime and a second DEM code path to maintain.
  6. The clean win: hard-blob cell hysteresis. In per-record mode it touches exactly two instances (066 and 085), unpaints 5 375 more structure points and re-paints zero, leaves the billboard instance bit-identical (9 cells / 109 697 points), changes zero detections on all four segments, and improves 085 GT on every axis. ship
  7. Review found a live major. The hysteresis cap fallback could remove an instance that hysteresis-off would have kept — it fell back to “no unpaint” instead of to the strict cell set. Fixed (18c9d73, b3dcc24) before the run.
  8. Handoff to the tablecloth repo: the union scope is right, but seeding needs road-aware / slope-corrected low-outlier rejection; the per-record clamp is the only mechanism that ever worked; and per-cell support fundamentally cannot separate isolated noise from sparse ground under canopy.

0. How to read the renders

Every render is one spot in the raw no-scan-angle-filter cloud, 6 columns left to right: true RGB | number_of_returns (grey = 1, orange = 2, red = ≥ 3) | r5pr (pass-6 code, per record) | r6pr (pass-7 code, per record) | r6nc (per-segment + ELM, no clamp) | r6 (per-segment + ELM + clamp). The two BEFORE columns come first; top row oblique, bottom row the same points top-down; each column is labelled in the image itself.

unmaskedtreemedium_vegetationsign-ish (sign / pole / delineator)guardrailother

Click any image for full resolution; ← / → (or swipe) step through the images of that card only; Esc closes.

1. What changed

featureknobverdictreason (one line)
ELM neighbourhood low-outlier rejection on the seed gridelm_enabled, elm_radius_cells=5, elm_max_drop_m=0.5, elm_min_neighbors=4, elm_iterations=2default offMade clamp-off strictly worse than pass 6 on every axis. Inert while per_segment is false, but as a live true default it silently degrades the per-segment path for anyone who flips the switch.
ELM reference statistic (plain 11×11 median of neighbour minima)— (design fault)wrong statisticOn a road corridor the median sits on the verge or barrier, so carriageway minima look like outliers: 15 % of populated cells emptied on 066 and 085, then nearest-filled / SMRF-interpolated even lower.
per-segment TCS without the clampsegment_clamp_to_record = falserevert — stop iterating6 of 9 canaries fail and it is behind pass 6’s r5. The last idea for making clamp-off viable moved the needle backwards.
per-segment TCS with the clamptcs_ground.per_segmentship offCanary-clean on ground/sign/GT, but M3 +31.8 % over bar, the 42k west-edge tree still rejected, an 085 delineator newly lost, and every metric gain in the third decimal — for +18 % runtime.
clamp to the per-record surfacesegment_clamp_to_record default truekeep (inert)Still the only mechanism that ever worked: it takes 066 kept fraction 0.3770 → 0.5898, truth-spot p5 −3.981 → −0.151 m, churn 5.91 % → 0.398 %. Now inert because per_segment is off.
hard-blob cell hysteresistree_detection.hard_blob_cell_hysteresis = 0.5keep — shipTwo instances, +5 375 unpainted structure points, 0 re-painted, cid93 bit-identical, 0/0/0 detection churn on four segments, clusters.csv and rail_halfposts.csv md5-identical, 085 GT better on every axis.
hysteresis cap fallbackinstances_hysteresis_relaxedfixed, unexercisedReview caught a live major — on tripping the cap it fell back to no unpaint at all, which could remove an instance hysteresis-off kept; now falls back to the strict cell set. 0 hits in 12 logs: reviewed code, not validated code.
hard-blob membership, the actual problem— (open)still openHysteresis rescues cells that fail the point-count floor next to a qualifying neighbour; cid93’s 9th cell fails a different predicate under the shifted DEM, so the 0.5 relaxation never reaches it. Gate on DEM-relative height stability, not point count.
round-6/7 code with zero corpus coverageae988ba canopy ext, bf771a7 survivor test, bc15683/740854e pole guard, + the hysteresis fallbackknown-untestedFive commits byte-neutral on this corpus — unit-tested only. r6pr differs from r5pr in exactly the two hard-blob instances and nowhere else.

2. ELM without the clamp — worse than pass 6

Every pass-4 symptom is back, and deeper 6 of 9 canaries fail

Pass 6 established that seeding was not what was broken. Pass 7 tested the one remaining idea — that a cell cannot tell sparse ground under canopy from isolated noise, but its neighbourhood can. It can’t, at least not with a plain median: on a corridor the neighbourhood is the verge, not the carriageway.

BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · canary 1 · 018 (−3212.87, −2195.74), a real post with plate at the road edge in front of dense foliage · magenta in r5pr/r6pr and in r6 (ml 0.6653), absent in r6nc — the same loss as pass 4 and pass 6, now for the third round running
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; canary 1 &middot; 018 (&minus;3212.87, &minus;2195.74), a real post with plate at the road edge in front of dense foliage &middot; magenta in r5pr/r6pr and in <b>r6</b> (ml <b>0.6653</b>), <b>absent in r6nc</b> &mdash; the same loss as pass 4 and pass 6, now for the third round running
BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · canary 7 · 066, 68 m of carriageway with lane markings and a belt each side · r6nc’s green lane-marking line is thicker and a green band appears along the left road edge (293 738 tree pts in hard cells vs the 249 388 bar, +17.8 %); r6pr and r6 are visually indistinguishable
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; canary 7 &middot; 066, 68 m of carriageway with lane markings and a belt each side &middot; <b>r6nc&rsquo;s green lane-marking line is thicker and a green band appears along the left road edge</b> (293 738 tree pts in hard cells vs the 249 388 bar, +17.8 %); r6pr and r6 are visually indistinguishable

018 sign ABSENT in r6nc · kept-fraction max deviation 0.5194 — 066 Record071 keeps 0.0924 vs 0.6118 per record, 7 of 8 records off by more than 0.05 · 066 truth-spot z_ground p5 −3.981 m (min −6.452), 25 clusters below −1 m · 066 streak 293 738 vs the 249 388 bar (+17.8 %) · M3 40 419 vs 29 769 (+35.9 %) · paint churn 5.91 %, 16 removed / 25 added detections.

All of that is worse than pass 6’s r5, which had no ELM at all: 0.4002 → 0.3770 kept, −2.708 → −3.981 m, 38 294 → 40 419 M3, 5.19 % → 5.91 % churn.

Where the 15 % emptied cells go both directions wrong

Emptying a cell hands it to interpolation. Where the emptied cell was road, the interpolated floor drops and low ground gets painted as vegetation; where it was under a belt, the local surface shifts enough to drop real foliage. Both failure directions show up in the same run.

BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · 060, low scrub/hedge belt beside the carriageway · r6nc paints a large low band that r5pr / r6pr / r6 all leave grey. The added mass is grey (single-return) in the number_of_returns panel — ground leakage, the same failure as pass 6’s r5_060_38k_263
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; 060, low scrub/hedge belt beside the carriageway &middot; <b>r6nc paints a large low band</b> that r5pr / r6pr / r6 all leave grey. The added mass is grey (single-return) in the <code>number_of_returns</code> panel &mdash; ground leakage, the same failure as pass 6&rsquo;s <code>r5_060_38k_263</code>
BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · 066 belt, r6nc removes a tree of n 246 959 · r6nc leaves a grey hole in the lower-left of a strongly multi-return (orange) belt that every other root paints. ELM does not only over-paint road, it also drops real foliage
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; 066 belt, r6nc <b>removes</b> a tree of n 246 959 &middot; r6nc leaves a grey hole in the lower-left of a strongly multi-return (orange) belt that every other root paints. ELM does not only over-paint road, it also drops real foliage
BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · 018 (−3292.73, −2188.05), r6nc-only conic_rule tree n 172 468, ml 0.3075 — the biggest 018 paint delta, +127 224 pts · the band reaches down onto the low verge and the added part is grey in the nr panel, i.e. contamination. r6 matches r6pr here
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; 018 (&minus;3292.73, &minus;2188.05), r6nc-only <code>conic_rule</code> tree n <b>172 468</b>, ml 0.3075 &mdash; the biggest 018 paint delta, +127 224 pts &middot; the band reaches down onto the low verge and the added part is grey in the nr panel, i.e. contamination. r6 matches r6pr here

ELM tiers (share of populated cells): 018 raw 0.933 / reseeded 0.024 / emptied 0.042 · 060 0.860 / 0.071 / 0.069 · 066 0.778 / 0.069 / 0.153 · 085 0.813 / 0.036 / 0.151. 066 and 085 were already the two worst DEM segments.

The one genuine credit, and its bill +0.127 recall for +21 298 hard FP

As in pass 6, the union surface really does see foliage a per-record surface misses. And as in pass 6, the price is paid in road.

BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · 085, 30 m forest stand, strongly multi-return · r6nc is right here: r5pr/r6pr leave the left third grey and r6nc paints most of it (r6 some). This is the honest half of r6nc’s +0.127 GT recall — the other half is 21 109 GT road points painted tree
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; 085, 30 m forest stand, strongly multi-return &middot; <b>r6nc is right here</b>: r5pr/r6pr leave the left third grey and r6nc paints most of it (r6 some). This is the honest half of r6nc&rsquo;s +0.127 GT recall &mdash; the other half is 21 109 GT road points painted tree

085 GT tree recall 0.7547 → 0.8817 on 1 872 942 annotated points matched 100.000 % @ 5 cm.

Price: hard FP 52 311 → 73 609, precision 0.4927 → 0.4691, veg-tolerant 0.7491 → 0.7126. The FP mass is GT class c71 — 21 109 road points newly painted tree. Pass 6 bought +0.094 recall for +8 024 FP; this is a strictly worse trade.

3. ELM with the clamp — clean where it matters, and still not worth it

The clamp buys everything back except the three things that were always broken M3 39 222 vs a 29 769 bar

r6 restores the sign, collapses kept-fraction deviation to 0.0154 on real records, puts zero truth-spot clusters below −0.5 m on any segment, returns 085 GT to neutral and cuts churn to 0.398 %. What it does not fix is the same list as round 4, round 5 and round 6 — plus one new loss.

BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · 060 billboard panel + frame beside a real conifer, cid93 · r5pr/r6pr leave the panel grey; r6nc and r6 both speckle it green — the 10.9k-point hard cell at (296, −67). This is the cell the hysteresis was built for, and hysteresis did not catch it: cid93’s hard share slips 0.5815 → 0.5072 and the 9th cell falls out for a reason the point-count relaxation never reaches
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; 060 billboard panel + frame beside a real conifer, cid93 &middot; r5pr/r6pr leave the panel grey; <b>r6nc and r6 both speckle it green</b> &mdash; the 10.9k-point hard cell at (296, &minus;67). This is the cell the hysteresis was built for, and hysteresis <b>did not catch it</b>: cid93&rsquo;s hard share slips 0.5815 &rarr; 0.5072 and the 9th cell falls out for a reason the point-count relaxation never reaches
BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · 018 west segment-edge wood · r6nc fills the grey patch r5pr/r6pr leave; r6 bites a large grey hole out of the left/centre — the n 41 953 tree rejected as reject_rf_below_threshold, −19.5k paint at (−3356.2, −2177.2). Identical to r5c in pass 6: the union surface is thinnest where fewest records overlap, so the clamp has least to clamp against exactly there
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; 018 west <b>segment-edge</b> wood &middot; r6nc fills the grey patch r5pr/r6pr leave; <b>r6 bites a large grey hole out of the left/centre</b> &mdash; the n <b>41 953</b> tree rejected as <code>reject_rf_below_threshold</code>, &minus;19.5k paint at (&minus;3356.2, &minus;2177.2). Identical to r5c in pass 6: the union surface is thinnest where fewest records overlap, so the clamp has least to clamp against exactly there
BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · 085’s only rescue_stage delineator (2272.93, 1248.11) · present n 344 in r5pr/r6pr, n 385 in r6nc, ABSENT in r6 — a strict regression against pass 6’s r5c, which kept it. Visually inconclusive: no magenta post is resolvable in any root even at 6× zoom and the road-edge line is painted green (tree) everywhere, so the “delineator” is probably contamination rather than a post — but it is a JSON-real detection loss either way
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; 085&rsquo;s only <code>rescue_stage</code> delineator (2272.93, 1248.11) &middot; present n 344 in r5pr/r6pr, n 385 in r6nc, <b>ABSENT in r6</b> &mdash; a strict regression against pass 6&rsquo;s r5c, which kept it. <b>Visually inconclusive</b>: no magenta post is resolvable in any root even at 6&times; zoom and the road-edge line is painted green (tree) everywhere, so the &ldquo;delineator&rdquo; is probably contamination rather than a post &mdash; but it is a JSON-real detection loss either way

M3 39 222 (+31.8 %), almost all of it two cells: 060 (296, −67) 10 851 pts and 018 (−3306, −2188) 5 047 · 018 west-edge tree n 41 953 rejected, −19.5k / −7.4k / −6.6k paint · 085 delineator (2272.93, 1248.11) lost — r5c kept it · detection churn 3/3 → 4/6 · runtime +18 % on 018/060 (066/085 hit 522 / 518 s).

And what it buys: M1_hi 0.83264 → 0.83558, M1b 0.898 → 0.89879, M2 0.90608 → 0.90556 (worse), 085 GT recall +0.0010, hard FP +383. Third-decimal noise in both directions.

4. The one clean win — hard-blob cell hysteresis

Strictly monotone, two instances, zero detection churn ship it

Measured in per-record mode (r5pr → r6pr), so the ground surface is held constant and the hysteresis is the only variable. It unpaints more structure and never re-paints any — monotone by design, and the corpus confirms it. There is no dedicated render of either changed instance; the 066 one (701.40, 315.17) lies inside the canary-7 streak window above.

BEFORE = 3rd/4th panel (r5pr, r6pr — per record) · canary 3 · truth spot lowrej_018_c0_s2, canopy top 7.2 m · PASS in all four roots: no tile-shaped hole anywhere, r6nc/r6 crowns marginally fuller than r6pr. Hysteresis changes nothing on 018 or 060 — point_masks.npz is md5-SAME on both segments and M3 there is unchanged at 28 556, under the bar
BEFORE = 3rd/4th panel (r5pr, r6pr &mdash; per record) &middot; canary 3 &middot; truth spot <code>lowrej_018_c0_s2</code>, canopy top 7.2 m &middot; <b>PASS in all four roots</b>: no tile-shaped hole anywhere, r6nc/r6 crowns marginally fuller than r6pr. Hysteresis changes nothing on 018 or 060 &mdash; <code>point_masks.npz</code> is md5-SAME on both segments and M3 there is unchanged at <b>28 556</b>, under the bar

066 (701.40, 315.17): 435 494 → 438 864 unpainted, 196 → 213 cells · 085 (2314.18, 1228.12): 50 570 → 52 575, 42 → 51 cells · that is the complete list: +5 375 unpainted, 0 re-painted · cid93 208780n / 109697up / 9c / 0.5815 bit-identical · detections 0 REMOVED / 0 ADDED / 0 MOVED on all four segments · clusters.csv + rail_halfposts.csv md5 SAME · 085 GT hard FP −227, precision +0.0003, veg-tolerant +0.0008 · 066 streak −1 606 · M3 on 018+060 unchanged at 28 556.

Two honest caveats: the cap fallback is unexercised (0 hits in 12 logs) after the review fix, and hysteresis does not close the hard-blob membership issue — the billboard cell it was aimed at still leaks in r6nc/r6.

5. Results per segment

segmentcanopy recall > 10 m (M1 hi)
r6pr / r6
M3 hard points
(018+060, bar 29 769)
085 GT precision / recalldetections
r6pr / r6nc / r6
runtime s
r6pr / r6nc / r6
TCS union kept fraction
r6pr / r6nc / r6
ELM tiers
raw / reseeded / emptied
0180.10735 / 0.15817 (11 924 base pts)r6 brings back (−3306, −2188) at 5 047 pts75 / 79 (5 out / 9 in) / 76 (2/3)327 / 347 / 3180.7845 / 0.7495 / 0.77970.933 / 0.024 / 0.042
060billboard cell (296, −67): 0 / 10 963 / 10 85180 / 84 (4/8) / 80 (0/0)332 / 362 / 3480.6758 / 0.6302 / 0.66980.860 / 0.071 / 0.069
066n/a (no truth spots)road-streak proxy 249 388 / 293 738 / 252 55671 / 71 (6/6) / 72 (0/1)388 / 492 / 5220.5988 / 0.3770 / 0.58980.778 / 0.069 / 0.153
085n/a (human-GT segment)hard fp 52 311 / 73 609 / 52 6940.4927 / 0.7547 · 0.4691 / 0.8817 · 0.4905 / 0.75579 / 10 (1/2) / 9 (2/2)393 / 482 / 5180.5907 / 0.5224 / 0.58890.813 / 0.036 / 0.151
pooledM1 hi 0.83264 / 0.83558
M1b 0.898 / 0.89879 · M2 0.90608 / 0.90556
28 556 / 40 419 (+35.9 %) / 39 222 (+31.8 %)veg-tolerant precision 0.7491 / 0.7126 / 0.7480235 / 244 (16/25) / 237 (4/6)1 440 / 1 683 / 1 706paint churn 5.91 % / 0.398 % of 44.6 M066+085 empty 15 % of populated cells

M3 is defined on 018+060 only (the segments with truth spots). Detections are 1 m, type-matched; the bracketed pair is REMOVED / ADDED against r6pr. “TCS union kept fraction” is the share of input points classified ground over the whole segment; the maximum per-record deviation from r6pr is 0.5194 for r6nc (066 Record071) and 0.0154 for r6 on real records (0.0843 on a 178-point record). ELM tiers are shares of populated cells and are identical for r6nc and r6; r6pr is per-record and emits none. The three variants shared one tcs_cache_dir in the order r6nc → r6 → r6pr, so runtimes are not cleanly comparable — the safe reading is that the worst (522 s = 8.7 min) is well inside the 20 min/segment budget. M6 truth spots are 1.000 recall / 0 FP in every root; no traceback in any of the 12 logs.

085 human GT (1 872 942 annotated points, 100.000 % matched @ 5 cm)

metricbaser5prr6prr6ncr6
tree precision vs GT tree(5)0.48930.49240.49270.46910.4905
tree recall0.75470.75470.75470.88170.7557
veg-tolerant precision (74/75 not FP)0.74130.74830.74910.71260.7480
hard fp (not class 5/74/75)54 52052 53852 31173 60952 694

085 GT precision is stuck at 0.49 in every root including base — that is its own open problem, and it is a detection problem, not a ground problem.

6. Next steps