The listing FAQ bot on a live product answers buyer questions about one property. Steering language is a legal risk under the Fair Housing Act, so the bot sits behind three layers: a deterministic pre-filter that stops guarded questions before they reach the model, a hard system prompt, and a deterministic post-filter on the model's output. The layers are pure functions, documented as unit-testable.
Documented as unit-testable. Not actually unit-tested. That gap is exactly where the bug lived.
Writing characterization tests for the guard, I pinned both directions of its documented intent: steering questions must block ("what are the demographics", "are the schools good", "is it safe at night"), and legitimate property facts must pass ("is there a family room", "does it have central air"). All green. Then the property-type cases:
Is this a single-family home?
Blocked. The familial-status pattern matches the "family" inside "single-family", and the marital-status pattern matches the "single". The single most common property-type question in US real estate was getting the canned redirect on a live product.
The sequence, straight from the repo history:
- Red commit: three failing tests proving the misfire, plus two passing tests proving the guard still blocks actual steering ("good home for a family with kids", "do mostly singles live in this building"). Committed failing, on purpose. The history is the proof the test came first.
- Green commit: property-type compounds (single-family, multi-family, two-family) collapse to a neutral token before pattern matching, the same trick the guard already used for "family room". All 44 tests pass.
Two footnotes that make the story honest:
- The repo's own dash lint then failed the build, because my regression test asserting "no em dashes in the redirect copy" contained a literal em dash in its regex. The gate caught the gatekeeper. Rewrote it with unicode escapes.
- The commit-gate hook went in the same day: every
git committhe agent runs now executes the lint and the full suite first, and red blocks the commit with the failure fed back. Both paths verified: green commits pass, a deliberately failing test blocks with exit code 2.
The lesson is not "regexes are hard." It is: a constraint that matters (here, a legal one) gets tests in both directions, blocked and allowed, because a guard that over-blocks quietly destroys the product's usefulness while looking safe.