Lehrling, and a field that stops being named after its values
Some checks failed
CI / Lint, Typen, Tests, Build (push) Successful in 10m51s
CI / Migrationen auf leerer Datenbank (push) Has been cancelled

worker_type had two values because the field was named after them:
"Angestellte:r / Arbeiter:in". Lehrlinge are the third social-insurance
category in Austria; until now they were filed as one of the other two,
which they are not -- and which skewed every report grouped by this
column by exactly those people.

Adding the value is one line. The label was the work: the field was
called after its two values in six places, and each of them becomes
wrong with a third. They now read "Beschaeftigtengruppe", the name the
import has used all along.

One label deliberately keeps the old wording: app_feld_karte() in the
database. That string is not a caption there but a key -- stored rows in
employee_history and pending_changes carry it, and the map is how
reverting or correcting a history entry finds the field again. Renaming
it without rewriting those rows would make every older entry for this
field unrevertable, and nobody would notice until they tried.

The migration's assertion reads pg_enum rather than comparing against
'Lehrling'::worker_type: migrations run inside a transaction, and
Postgres refuses to use a freshly added enum value in the transaction
that added it. This has not been run against a live database here -- the
CI migration job is the first real execution.

Three hand-kept lists of the same enum (reports, import, the form) now
have a test holding them to one another, each mutation-checked.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-10 17:28:49 +02:00
parent 2838919e42
commit f17d299045
12 changed files with 193 additions and 9 deletions

View File

@@ -0,0 +1,65 @@
-- Lehrling als dritte Beschäftigtengruppe.
--
-- worker_type kannte bisher zwei Werte, weil das Feld nach ihnen benannt war:
-- „Angestellte:r / Arbeiter:in". Lehrlinge sind in Österreich die dritte
-- sozialversicherungsrechtliche Gruppe daneben — bislang wurden sie als
-- Angestellte:r oder Arbeiter:in geführt, was sie nicht sind.
--
-- ═══ Warum das hier allein steht ═══════════════════════════════════
--
-- Ein Enum-Wert lässt sich nicht wieder entfernen. Ein Rückbau hiesse: neuen
-- Typ anlegen, die Spalte umhängen, den alten wegwerfen — bei Zeilen, die
-- daran hängen, ein eigener Vorgang. Deshalb steht hier nichts weiter drin,
-- was man gleichzeitig zurücknehmen wollen könnte.
--
-- ═══ Warum der Prüfblock über den Katalog geht ═════════════════════
--
-- scripts/migrate.mjs fährt jede Migration in einer Transaktion. Seit
-- PostgreSQL 12 darf `add value` darin stehen — **benutzen** lässt sich der
-- neue Wert in derselben Transaktion aber nicht: ein Vergleich gegen
-- 'Lehrling'::worker_type scheitert mit „unsafe use of new value". Die
-- Gegenprobe fragt deshalb pg_enum, wo die Beschriftung schlichter Text ist.
--
-- ═══ Was hier bewusst NICHT steht ══════════════════════════════════
--
-- Die Beschriftung in app_feld_karte() heisst weiter
-- 'Angestellte:r/Arbeiter:in', obwohl die Oberfläche das Feld ab jetzt
-- „Beschäftigtengruppe" nennt. Diese Zeichenkette ist dort kein Etikett,
-- sondern ein Schlüssel: employee_history.changes und pending_changes tragen
-- sie in bereits gespeicherten Zeilen, und app_feld_karte() ist die Karte,
-- über die das Zurücksetzen und Korrigieren eines Historieneintrags das Feld
-- wiederfindet. Wer sie umbenennt, ohne die gespeicherten Zeilen mitzuziehen,
-- macht jeden alten Eintrag zu diesem Feld unumkehrbar — ein stiller Verlust,
-- der erst auffällt, wenn jemand eine Änderung zurücknehmen will.
alter type worker_type add value if not exists 'Lehrling';
-- ═══ Gegenprobe ═══════════════════════════════════════════════════
do $$
declare
anzahl int;
begin
if not exists (
select 1
from pg_enum e
join pg_type t on t.oid = e.enumtypid
where t.typname = 'worker_type' and e.enumlabel = 'Lehrling'
) then
raise exception 'worker_type kennt Lehrling nicht.';
end if;
-- Die beiden alten Werte müssen stehen bleiben: ein Enum, das statt drei
-- Werten nur noch einen neuen trägt, hätte die Spalte unbrauchbar gemacht.
select count(*) into anzahl
from pg_enum e
join pg_type t on t.oid = e.enumtypid
where t.typname = 'worker_type';
if anzahl <> 3 then
raise exception 'worker_type hat % Werte, erwartet werden 3.', anzahl;
end if;
-- Die Beschriftung in der Feldkarte bleibt, wie sie war — siehe oben.
if not (app_feld_karte() ? 'Angestellte:r/Arbeiter:in') then
raise exception 'Die Feldkarte kennt worker_type nicht mehr unter der gespeicherten Beschriftung.';
end if;
end $$;