The Doozer Brainlive from the knowledge bundle · v2.2.618 · 2026-09-13 17:17 ETall pages · one page

Context-city poisoning (never name a place after where you found it)

systems/context-city-poisoning.md · System · geo-anchor, accuracy, urls, par-create, prospector, lesson

unverified: no trust signals recorded yet

Two independent creation paths named businesses after the city they were DISCOVERED from rather than where they are, putting the wrong town in 239 URLs. The pattern, the fix, and the audit.

Context-city poisoning

The bug shape: a creation path knows two cities — the one it is looking from and the one the place is in — and uses the wrong one. It happened twice, independently, in two subsystems written months apart. Assume it will happen a third time.

Path Used Should have used
parCreateSkeleton() the ANCHOR business's city (the page the visitor was on) the place's own address
Prospector discovery the SWEEP CENTER's city ($resolvedCity = $center['city']) the place's own address

Results in the wild: a Brooklyn bowling alley at melody-lanes-morristown-nj.doozer.site, a Brentwood restaurant at blaze-pizza-nashville-tn, a New York restaurant at tao-downtown-restaurant-jersey-city-nj.

Why it is easy to miss

The context city is almost right. Most results of a Morristown sweep really are in Morristown, so the bug hides in the minority and every spot-check passes. It only shows up when you compare the slug against the address systematically. 239 of 3,439 domains (1,304 of which use the city-state slug shape) named the wrong town before anyone noticed.

It is also invisible in the product: the page content, title and schema were all correct, because those read businesses.formatted_address. Only the URL lied.

The rule

A city is a fact about the place, never about how you found it. Discovery context is
a hint for routing and a provenance note. It must never name anything.

Par-create records this correctly for provenance: custom_settings.discovered_on keeps where a skeleton was seen, while city comes from the address. That is the right split.

The fix

parCreateCityStateFromAddress($addr) in par-create.php parses the place's own city and state from the address we already hold, and returns ['',''] rather than guessing when it cannot parse confidently, so callers fall back rather than invent. Both paths call it now.

Watch the address shapes: Google returns both "912 Red River St, Austin, TX 78701" and "222 W 1st Ave, Plentywood, MT 59254, USA". Strip a trailing country, then take the part before the ST ZIP tail. Reject a candidate that starts with a digit, which means you grabbed a street line.

The audit

dz slugaudit — scans every active domain, extracts a trailing -city-state slug, and compares it to the address. Reports, dry-runs, repairs.

It splits the fix by risk, and that split is the important part:

Renaming a domain (the mechanism that was missing)

includes/domain-redirects.php. A retired host keeps its domains row with status='disabled' (already means "not serving", so no migration) plus custom_settings.redirect_to, and domainRetiredRedirect() 301s it.

Two properties make it safe to leave switched on:

Rename procedure: UPDATE the live row's domain (keeping id, page-view history and sitemap membership), then INSERT a disabled row for the old host carrying the redirect. Then push the new URL to IndexNow so Bing-backed search sees the move.

A correction worth keeping. The original justification for leaving indexed domains alone included "the orphan falls into the configure flow and offers a stranger the chance to configure somebody's business." That was wrong: runRootDomainGuard() already returned a 302 with x-doozer-lockdown: blocked-subdomain for unregistered subdomains. The real value of retirement is the permanent 301 telling a search engine the address moved, not protection that already existed. Verify the claim, not just the conclusion.

Transferable lesson

When a naming bug is found in one subsystem, grep for the same shape everywhere else before declaring it fixed. The instinct that caught this was simply asking whether the bug had happened before. Both paths had it; only one was found by working on it directly.

Related: [[the-observed-world]], [[fact-guard-identity-numbers]], [[dev-api]].

Content Generation Pipeline (providers, models, timeouts)Design Standards and the Design Mirror