Candidate sites ranked, every score broken into its weighted criteria, and between each adjacent pair the smallest change in one of your own weights that would reverse them. Every incumbent ships a score. Not one ships the score's stability.
Defended at an expansion committee, by a team that has already qualified the sites. A multi-unit operator, a franchisor's expansion group, a grocery or convenience banner, a restaurant group.
The published promise in this category is always open, expand or close. Close is the verb no vendor makes first-class, because no vendor wants to sell software that recommends shutting a store. It is the same score with the candidate set replaced by the customer's own sites — so it ships here, as a page, and it costs almost nothing to build.
Lower transit access by 1.1 points of weight, renormalise the rest, and the order reverses.
The committee does not need to be told which site scored highest. It needs to know whether the answer survives the argument it is about to have.
One incumbent relaunched its whole platform as a conversational product in May 2026. Another moved its business-analyst AI assistant to general availability in June 2026. A third wired plain-language querying in 2025. A fourth no longer exists as a brand.
A funded entrant sells five reshapeable weighted lenses with traceable inputs from $200 per month. "We show the arithmetic" stopped being a differentiator while we were writing it down.
Across every vendor page and every comparison page read in the study, not one reports how far an assumption would have to move before the ranking changed.
That is the best argument in this whole solution, and it is not a marketing line. It is why the gap has stayed open while four platforms rebuilt their front ends.
We can publish it, because we sell nothing inside the model. The arithmetic is a thirty-year-old published method, the inputs are keyless open data, and the weights are the customer's.
The method has a name and a citation. Triantaphyllou & Sánchez (1997) give the unified sensitivity treatment of the weighted sum model; Jaini & Utyuzhnikov (2016) define the object exactly.
The incumbent's documentation describes suitability analysis as preprocessing, weighting, combination and a final score scale — and says of the weights:
That is the weighted sum model, renormalised to 100. It is exactly the arithmetic this app runs. The assumption rail is not an invention — it is the industry norm made visible, and then measured.
Every row's bar is broken into its weighted criterion contributions, read left to right. Between each adjacent pair sits a chip carrying the smallest single-weight change that would reverse that pair, and a two-state verdict against a threshold the reader sets.
A missing input is flagged and excluded from that site's weight base — never scored zero. A blank traffic count coerced to zero would score a site at the worst possible exposure instead of no reading. That is how a screening tool quietly kills a good site, and it is a measured risk: 30 rows on the state's own AADT layer carry a blank ahead count, and 49 a blank back count.
For every adjacent pair, solve for the minimum move in one criterion's weight — renormalising the rest so the set still sums to 100 — that puts the lower site above the higher one. Print it. Call the pair robust or fragile against a stated threshold.
The suite applies every predicted flip and checks that it actually reverses the pair. Four of four do. And half the predicted change reverses none of them — which is what makes the printed margin a threshold rather than a label.
It converts "the model picked site 3" into "site 3 wins unless you believe traffic exposure is eight points more important than you said, in which case site 2 wins." That is a sentence a committee can argue with.
Solving for score_b ≥ score_a is the published form of the method, and the solver's own unit tests passed.
Two candidates that share a nearest count station carry the identical normalised exposure. Drive that weight to its limit and both scores land on exactly the same number. The pair ties. It does not reverse — and the chip was promising a reversal the user would never observe.
Caught at 3 of 4, by the assertion that applies the app's own printed promise rather than checking that the solver satisfied its inequality. The predicate is now a strict inequality, and where no strict reversal exists the pair is reported ROBUST.
So the app prints the second sentence nobody else prints: how far the stated band would have to move before a pair reverses, and whether that move stays inside the standard's own range.
A flip that requires leaving the standard's range is a strong result. A flip that happens inside it means the slate was never decided by the data. This is a sensitivity reading of one stated definition — never a bench of rival catchment definitions to pick from. Bands are rings, labelled straight-line buffers on screen and in every export, because one community routing engine was down on six consecutive attempts and the other publishes no data vintage.
| Criterion | Source | The trap, reproduced on the wire |
|---|---|---|
| Household demand & spending power | Census ACS 5-year summary file, joined to TIGERweb tract geometry | Keyless and reachable, and the host sends no CORS header at all — so the spine is baked at build time. 9,129 = 9,129 tracts, zero orphans, asserted as a build gate. |
| Traffic exposure | State highway AADT + its truck-volume sibling | Every count is a String. The naive maximum is 99,000; a server-side cast returns 386,600. A blank is missing, never zero. |
| The competitive set | State points-of-interest register | The object id is OBJECTID_1 and the column literally named OBJECTID is a decoy holding unrelated values. The whole register is one snapshot dated 2020-05-06. |
| Transit access | State high-quality transit areas and stops | A modelled planning product with no vintage field, whose counts moved by +481 and −550 in five weeks. Re-read at load, never hard-coded. |
| Jurisdiction | Incorporated city boundaries | 483 cities, and unincorporated territory is in no city layer — so a non-match renders unincorporated — county jurisdiction, never a blank. |
Catchment figures are areally apportioned. A tract that straddles the band contributes the fraction of its households its area fraction implies. Counting straddling tracts whole overstated demand by +41.7 % at the reference slate's leading site — 43 tracts touched, 22 of them partial. It is the single most consequential operation in the pipeline and the one most often skipped.
It is a finding we report. The industry's canonical retail-gap output is in mature status, frozen at 2017 vintage, retired by its own vendor because its sources "cannot adequately differentiate e-commerce sales from store-front sales". Its 2026 replacement is demand only — no supply side, therefore no leakage.
We are not behind the incumbent on this number. There is no incumbent number.
The register's 21 visit columns run Visits04_19_2020 to Visits5_9_2020. The bound-field allow-list contains none of them, so nothing can arrive and be charted by accident — asserted on the wire, not promised in a comment.
Live against the real services, offline against the shipped module, and a real headless browser. The browser suite found five defects the other two reported green — including a theme switch that permanently lost every operational layer.
The suite inverts each one deliberately, so the day a service fixes itself the build goes red rather than quietly stale. A numeric predicate on the string column must still throw.
Each basemap is probed as a style, then two different tiles are fetched and required to differ — and one is looked at. One raster host passes every automated check and is still watermarked "API KEY REQUIRED". It is not in the gallery.
Reading the figures: every service, count, field and vintage above was probed live and is reproduced in the recipe with its literal terminal output. The five candidate sites and four estate sites are GENERATED demo inputs, labelled as such on every screen and in every export — in a deployment they arrive by upload, pin or address search. No measured figure is ever mixed with them.
Every one of these is written into the delivered application's own README. A tool that hides its edges costs you the project it cannot finish.
Your candidate sites with their coordinates, the centre type you are building, and the weights your committee actually argues about. Two weeks, and this slate ranks your shortlist instead of a generated one — and tells you which pairs will not survive the meeting.
Swappable by configuration, not by code: the criterion list is data-driven, so a firm that already licenses a commercial extract pushes it in as an additional criterion. The model is open, so their data stays theirs. That is the coexistence story, and it is the same one either way.