Thank you both — every one of these held up when I went and checked, and three are now fixed.
The map scale. You were right and the cause was not the scale logic. The map container is height: 100%, so at the moment the script initialises it the box can still be zero, and Leaflet fits the bounds against that: the centre was correct and the zoom was not. It now measures the container before fitting and refits once the container is actually laid out.
Visit durations. 1.5 hours for the Roman Forum was short, and reading the rest of the data showed the shape of the mistake: 268 of 289 editorially set “activity” durations were exactly 120 minutes, so every public square was a two-hour visit — Piazza Mattei, which is a fountain and a few façades, the same as Piazza Navona. Eleven squares are now 30 minutes and the Forum is 150. Thank you for that one; I would not have found it from a passing glance at Rome alone.
Restaurants. This is the one I am most grateful for, because the cause was mine and recent. Two days ago I tightened which places get a published page — an advertising review had flagged thin pages — and the rule keeps a place only if it has a Wikidata item, editorial standing or written text. The planner drew its meal candidates from that same published set. Among restaurants, “has a Wikidata item” means famous, so Dublin’s pool collapsed to six venues, all of them among the city’s most expensive. That is exactly why @alan_gr was offered a €95 set menu and why Babington’s turned up in Rome.
A restaurant can be a fair place to eat without deserving an indexed page of its own, so meal candidates no longer require that. Dublin goes from 6 venues to 58.
On price and cuisine specifically: OSM carries no price tag on any of the 1780 food POIs I hold, and only 254 carry cuisine, so I have nothing real to filter on. Rather than invent a price band, the meal stop now says plainly what it is — nearby, open at that hour, and not a recommendation, with no price or menu recorded. If there is a tagging practice for price that I have simply missed, I would like to know.
Rome is a separate problem I found while checking this: I hold 5 food POIs for Rome against 181 for London and 190 for Tokyo, so the ingest for that city is plainly incomplete and the planner was choosing from almost nothing. I am re-running it.
Queues. Not modelled, and you are right that it matters. I have not found a source for it in OSM or Wikidata, and a made-up average would quietly break the day’s time budget rather than admit the gap, so for now the plan simply does not know about queues. If anyone knows of a usable open source for typical waiting times, I would use it.
@alan_gr — fair point on my question, it was too vague to act on. What I actually want is narrower: I parse opening_hours myself rather than using an existing library, and the case I keep getting wrong is a day written as two intervals around a midday break, Tu-Su 09:00-13:00,15:00-19:00. I render that as one span with the break named separately rather than showing only the first interval, but I am not confident about the messier real-world variants — off, PH, seasonal ranges, and values where the separator or ordering is unusual. If it is useful I can post the specific strings my parser rejects, from real objects, rather than asking anyone to cross-check attractions by hand.