PolyRenewal → UND-SLAB miscode guard (permit parser)

Date: 2026-08-05 · Commit: entirely-api 9ebeae9 (pushed)

What

The parse_sow_items prompt in services/permit_parser.py now carries an explicit rule: SettleStop PolyRenewal / polyurethane foam injection scope has no catalog product — never map it to UND-SLAB or any other code, mention it in notes only. UND-SLAB (Slab Pier) quantities are pier counts (units), never square footage.

Backed by a code post-filter is_miscoded_und_slab() in the validation loop: drops UND-SLAB lines whose own text (notes/dimensions/spacing) mentions PolyRenewal / polyurethane / foam injection, or whose quantity is >50 with an SF / sq-ft hint. Drops are logged at WARNING.

Why

BAL-9004 intake parse (2026-08-05) coded “PolyRenewal 2-part, 400 SF” as UND-SLAB qty=400; a same-day re-parse correctly declined — run-to-run variance. Opus 4.7+ rejects temperature=0 (400 error), so per the established convention (memory reference_llm_determinism_no_temperature) stability must come from prompt rules + code post-filters.

Tests

tests/test_sow_poly_filter.py — 10 tests, including a BAL-9004 scope-text mirror run through parse_sow_items with a mocked Vision call, plus negative cases (legit pier counts, large counts without SF hints, SUP-FLOOR sq-ft product untouched).

Deploy note

DEPLOYED 2026-08-05: once the parallel session committed its cert-tracking work (3868129, cc591c4) the tree was clean; suite 426 passed, api rebuilt, worker+scheduler restarted, filter verified live inside the container against the BAL-9004 item (returns True → line dropped).

Related: date-parser-consolidation, memory reference_brand_names (PolyRenewal row).