R94 casing: initcap capitalises every word, so multi-word register names come back wrong #113

Closed
opened 2026-08-13 05:16:01 +00:00 by art-bot · 1 comment
Collaborator

Scope: the shared R94 casing-normalisation idiom, and the three layers that use it.

MML's registers store most rows in capitals, so places, railways (#86) and
stations (#81) all normalise on the way in with the same expression:

CASE WHEN teksti = upper(teksti) THEN initcap(teksti) ELSE teksti END

Postgres initcap starts a new word at every non-alphanumeric character, so it
capitalises the second word of a multi-word name as well as the first. Finnish does not:
a place name whose second element is a common noun keeps it lower-case.

What was measured (live DB, fi_paikannimi, 2026-08-13):

  • 47 of the 14201 traffic-site register's distinct all-caps labels are multi-word,
    and so exposed to this.
  • Visible on the map today at two Helsinki metro stations, both drawn from the register
    since the #81 review: AALTO-YLIOPISTO → "Aalto-Yliopisto" (Finnish wants
    Aalto-yliopisto) and HELSINGIN YLIOPISTO → "Helsingin Yliopisto" (Helsingin
    yliopisto
    ).
  • Not every case is wrong: PASILA, TAVARA → "Pasila, Tavara" is fine, because there
    the second element is being used as a name part.

A second shape of the same bug, from #92: the break can happen inside a word.
initcap starts a new word after a colon as readily as after a space, so
S:T MICHEL → "S:T Michel" — the abbreviation for Sankt comes back with its
second letter capitalised, where Swedish/Finnish usage is S:t Michel. This is worth
keeping separate from the multi-word cases when picking a rule: "capitalise only the
first word" (option 1 below) does not fix it, because S:T is the first word. It
needs the tokeniser to stop treating : as a word boundary at all.

Scope note, measured after #81 merged: the 14201 traffic-site series carries no
S:-prefixed rows today (0 Finnish station names begin S:, and 0 mixed-case 14201
rows contain a run of capitals), so this shape is currently latent for stations. #92
recorded it against the places series, where conf/fimap.yaml's places comment
documents it. It is the same expression in both, so any fix has to cover it.

Why the obvious fixes are each partial:

  1. Capitalise only the first word. Correct for the two visible cases, but wrong for
    genuine two-part proper names, and the register does not mark which is which.
  2. Borrow the casing from a cased twin elsewhere in the register. Measured: only
    15 of the 47 have a cased variant anywhere in fi_paikannimi. Concretely,
    Aalto-yliopisto does exist cased (under kohdeluokka 42101), but HELSINGIN YLIOPISTO has no cased row at all — so this fixes under a third of them and leaves
    the more visible one broken.
  3. Exception list for known lower-case second elements (yliopisto, asema, tavara, …).
    Cheap and targeted, but it is a word list that has to be maintained, and it is the
    kind of per-country special-casing the project usually pushes back on.

Decision needed: which rule, and whether it lives in one shared SQL helper rather
than being copy-pasted into three configs — right now the same CASE expression is
written out separately in conf/fimap.yaml (twice, rail and metro branches), and in
the places and railways queries. Whatever the rule turns out to be, it should be in
one place, because the stations principal-station match depends on the station name
and the town name being normalised identically (#81) — two copies that drift apart
would silently empty the importance-3 rung.

Note this is not Finland-only in principle: any register that ships all-caps names hits
it. Finland is just where it is measurable today.

From the #81 review — the limitation is documented in docs/country-finland.md ("Names
are register names, casing-normalised on the way in") and was accepted there as a known
limit rather than patched per-layer. #92 (closed by #81, which applied the idiom to
stations) flagged and accepted the same limit from the other end; this issue is the
one that actually fixes it.

Scope: the shared R94 casing-normalisation idiom, and the three layers that use it. MML's registers store most rows in capitals, so `places`, `railways` (#86) and `stations` (#81) all normalise on the way in with the same expression: ```sql CASE WHEN teksti = upper(teksti) THEN initcap(teksti) ELSE teksti END ``` Postgres `initcap` starts a new word at **every** non-alphanumeric character, so it capitalises the second word of a multi-word name as well as the first. Finnish does not: a place name whose second element is a common noun keeps it lower-case. **What was measured** (live DB, `fi_paikannimi`, 2026-08-13): - **47** of the 14201 traffic-site register's distinct all-caps labels are multi-word, and so exposed to this. - Visible on the map today at two Helsinki metro stations, both drawn from the register since the #81 review: `AALTO-YLIOPISTO` → **"Aalto-Yliopisto"** (Finnish wants *Aalto-yliopisto*) and `HELSINGIN YLIOPISTO` → **"Helsingin Yliopisto"** (*Helsingin yliopisto*). - Not every case is wrong: `PASILA, TAVARA` → "Pasila, Tavara" is fine, because there the second element is being used as a name part. **A second shape of the same bug, from #92: the break can happen *inside* a word.** `initcap` starts a new word after a colon as readily as after a space, so `S:T MICHEL` → **"S:T Michel"** — the abbreviation for *Sankt* comes back with its second letter capitalised, where Swedish/Finnish usage is *S:t Michel*. This is worth keeping separate from the multi-word cases when picking a rule: "capitalise only the first word" (option 1 below) does **not** fix it, because `S:T` *is* the first word. It needs the tokeniser to stop treating `:` as a word boundary at all. Scope note, measured after #81 merged: the 14201 traffic-site series carries **no** `S:`-prefixed rows today (0 Finnish station names begin `S:`, and 0 mixed-case 14201 rows contain a run of capitals), so this shape is currently latent for `stations`. #92 recorded it against the **places** series, where `conf/fimap.yaml`'s places comment documents it. It is the same expression in both, so any fix has to cover it. **Why the obvious fixes are each partial:** 1. *Capitalise only the first word.* Correct for the two visible cases, but wrong for genuine two-part proper names, and the register does not mark which is which. 2. *Borrow the casing from a cased twin elsewhere in the register.* Measured: only **15 of the 47** have a cased variant anywhere in `fi_paikannimi`. Concretely, `Aalto-yliopisto` does exist cased (under kohdeluokka 42101), but `HELSINGIN YLIOPISTO` has no cased row at all — so this fixes under a third of them and leaves the more visible one broken. 3. *Exception list for known lower-case second elements* (yliopisto, asema, tavara, …). Cheap and targeted, but it is a word list that has to be maintained, and it is the kind of per-country special-casing the project usually pushes back on. **Decision needed:** which rule, and whether it lives in one shared SQL helper rather than being copy-pasted into three configs — right now the same `CASE` expression is written out separately in `conf/fimap.yaml` (twice, rail and metro branches), and in the `places` and `railways` queries. Whatever the rule turns out to be, it should be in one place, because the `stations` principal-station match depends on the station name and the town name being normalised **identically** (#81) — two copies that drift apart would silently empty the importance-3 rung. Note this is not Finland-only in principle: any register that ships all-caps names hits it. Finland is just where it is measurable today. From the #81 review — the limitation is documented in docs/country-finland.md ("Names are register names, casing-normalised on the way in") and was accepted there as a known limit rather than patched per-layer. **#92** (closed by #81, which applied the idiom to `stations`) flagged and accepted the same limit from the other end; this issue is the one that actually fixes it.
Owner

Result is in #130 — #130; the review note is the PR description.

Result is in #130 — https://git.blahonga.org/art/ismap/pulls/130; the review note is the PR description.
art closed this issue 2026-08-16 05:17:33 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
art/ismap#113
No description provided.