Altlasten: Erneuerung und Inhaltsreview
Vertrag: ADR-0058 (Ergänzungen #556, #582, #602 und #640); Betrieb als Vercel-Cron seit 06.10.2026: ADR-0080. Wiederherstellung #556.
Auf einen Blick (seit ADR-0080)
| Was | Wo |
|---|---|
| Nachtlauf | Vercel-Cron /api/cron/renew-altlasten-snapshot, täglich 03:37 UTC (Funktionslimit 800 s, WFS-Deadline 600 s, 120 s je Abruf; der Skriptschritt brauchte auf GitHub Actions 40–73 s, Stichprobe 16.09.–06.10.2026) |
| Ergebnis eines Laufs | /admin/cron/renew-altlasten-snapshot/runs/<id> (vollständiges Ergebnis-JSON ohne Rohgeometrie, cron_runs.result_json) |
| Reviewpflicht | Mail an office@ostheimer.at: „[LandNutzen] Altlasten: Inhaltsreview erforderlich …“ mit Frist, Diff, fertigem Aktivierungsbefehl und Anhängen (Ergebnis-JSON, Quellinventar); dieselbe Anleitung im Admin-Lauf |
| Reviewpflicht entfallen | Mail „[LandNutzen] Altlasten: Reviewpflicht entfallen“ |
| Aktivierung | weiterhin Handarbeit: manueller Workflow publish-altlasten-release.yml oder lokales CLI (siehe „Kontrollierte Aktivierung“) |
| Manueller Lauf | /admin/cron → Zeile renew-altlasten-snapshot → „Jetzt triggern“, oder curl mit CRON_SECRET (siehe unten) |
Der GitHub-Workflow renew-altlasten-snapshot.yml hat seit #669 keinen
Zeitplan mehr (zuletzt Rückfall 06:37 UTC, ursprünglich 03:37 UTC).
workflow_dispatch und der geprüfte Codepfad bleiben erhalten. Der Workflow
ist gemäß #685 in GitHub deaktiviert (disabled_manually, Readback
13.10.2026); dieser Zustand verhindert auch einen manuellen Start. Ein
Notlauf über Actions braucht eine gesondert freigegebene Wiederaktivierung und verbraucht
Actions-Minuten. Der Vercel-Cron bleibt der reguläre Betriebsweg.
Erster belegter Vercel-Lauf: 07.10.2026, 03:37 UTC. Die öffentliche
Provenance nennt für den aktiven Release retrievedAt 03:37:22 und
activatedAt 03:37:23 UTC (Pointer-Version 21). Der Rückfall-Workflow
startete am selben Tag um 06:59 UTC und übersprang mit
active_snapshot_has_freshness_reserve. Das ist der Zeitpunkt des
Vercel-Zeitplans; ob vercel oder manual ausgelöst hat, zeigt die Lauf-Zeile
unter /admin/cron. Den Nachweis für Hochwasser und Brachflächen führen deren
Runbooks.
Aktueller Betriebsbeleg 13.10.2026: Vercel-Lauf
#2944
startete um 03:37:07 UTC und endete mit success (15.088 ms). Er erneuerte
Release aadac1bb-49b4-567f-a586-b650227069ea, Pointer 27, 383 veröffentlichte
Geometrien, frisch bis 15.10.2026 03:37:21 UTC. Der technische Abruf ist kein
neuer fachlicher Quellenstand (sourceVintage=null). Öffentliche Provenienz
und Coverage wurden lesend gegengeprüft. Betriebsbeleg #685.
Jeder WFS-Abruf darf seit 06.10.2026 bis zu 120 s dauern (vorher 60 s): Die erste Seite brauchte abends 63–71 s bis zum ersten Byte, die übrigen 1–4 s. Die Gesamtdeadline begrenzt weiterhin alles (Vercel-Route 600 s, Skript im GitHub-Workflow 15 min).
Manueller Lauf mit dem Produktions-Secret, ohne es anzuzeigen:
read -rs CRON_SECRET && export CRON_SECRET
curl -sS --max-time 900 -X POST \
-H "Authorization: Bearer $CRON_SECRET" \
-H "X-Cron-Triggered-By: manual" \
https://www.landnutzen.at/api/cron/renew-altlasten-snapshot
200 mit result = erneuert oder belegter Skip. 500 mit
ALTLASTEN_CONTENT_CHANGE_REVIEW_REQUIRED:<kandidat> = Reviewpflicht (Mail
folgt). Ein manueller Lauf ist ein normaler Lauf und schreibt wie der
Nachtlauf in die Produktionsdatenbank.
Aktuellen Zustand lesen
Maßgeblich ist die öffentliche Provenance,
insbesondere activeRelease.id, activationRef.pointerVersion und
freshness.state/freshUntil. Der Abrufzeitpunkt ist technisch, kein fachlicher
Datenstand. Ein historischer Produktionsnachweis garantiert keine heutige Frische.
Der Report zeigt bei gesperrter Quelle „Altlasten-Prüfung für diese Adresse nicht
verfügbar.“ Das ist kein Nullbefund. Persistierte Reports behalten ihren damaligen Zustand.
Täglicher Betrieb und rechtzeitige Warnung
Der Vercel-Cron renew-altlasten-snapshot läuft täglich um 03:37 UTC (bis
06.10.2026 der GitHub-Workflow renew-altlasten-snapshot.yml, dessen Start
GitHub um 6 bis 166 Minuten verzögerte, Stichprobe 28.08.–06.10.2026, ADR-0080).
Drei vollständig identische Abrufe
sind Pflicht. Die Frist beträgt unverändert höchstens 48 Stunden, die
Erneuerungsreserve seit #582 36 Stunden (zuvor 24 Stunden — bei Reserve
gleich Cron-Takt lief jede Erneuerung auf die Frist zu; belegt waren fünf
Erneuerungen mit unter drei Minuten Rest). Größer als der tägliche Takt zu
sein heißt: nach jeder Erneuerung (Rest 48 h) liegt der Rest in der
folgenden Nacht (~24 h) unter der Reserve und es wird wieder erneuert — jede
Nacht, nie mehr auf das Fristende hin. Der unabhängige Admin-/Drift-„due“-
Schwellwert (lib/data-sources/drift-policy.ts) bleibt eine eigene,
unveränderte Konstante und wird davon nicht berührt.
„Inhaltsgleich“ heißt seit #582 gleiche publishedManifestSha256,
excludedManifestSha256 und scopeManifestSha256 sowie gleiche Transform-
und Scope-Version — nicht mehr das Gesamt- oder das Quellmanifest der
amtlichen Quelle, das rund 1.434 Sätze außerhalb des Altlast-Scopes
einschließt. 7 von 10 Quelländerungen im September lagen ausschließlich
außerhalb des Scopes; solche Änderungen erneuern jetzt automatisch und
bleiben nur noch informativ als Außer-Scope-Drift im Delta sichtbar. Nur ein
in diesem Sinn vollständig inhalts- und vertragsgleicher Abruf bei offenem
Public-Gate darf ohne Feldreview automatisch erneuert werden. Ein bereits
abgelaufener Release braucht auch bei gleicher Quelle eine explizite
Aktivierung.
Seit #602: nur Ausschluss/Außer-Scope geändert. Am 24./25. September 2026 war die Altlasten-Prüfung rund sechs Stunden nicht
verfügbar, obwohl sich am Bericht nichts geändert hatte: neu war nur ein
ausgeschlossener Eintrag (UBA-ID 83984, Status „Altlast vorgeschlagen“)
plus zwei Sätze außerhalb des Scopes; publishedManifestSha256 und alle 383
veröffentlichten Geometrien waren byte-gleich. Weil sich damit Ausschluss- und
Scope-Manifest änderten, war trotzdem ein Review nötig
(#602). PM-Entscheidung
vom 25. September 2026: Änderungen, die nur ausgeschlossene oder
Out-of-Scope-Einträge betreffen, gehen ohne Review durch, solange
Veröffentlichtes und alle Geometrien byte-gleich sind.
Der Nachtlauf aktiviert einen Kandidaten mit geändertem Ausschluss- oder
Scope-Manifest deshalb nach dem feldweisen Review im selben Lauf automatisch
(Grund excluded_or_scope_only_change_renewed, Expected-Current-CAS wie bei
der inhaltsgleichen Erneuerung), wenn alle folgenden Punkte gelten —
sonst, auch bei jeder fehlenden oder ungültigen Angabe, bleibt es beim
Review wie bisher:
- aktiver Release vorhanden, öffentliches Gate offen;
- Transform- und Scope-Version bei aktivem Release und Kandidat gleich der laufenden Logik; Kandidat rechtlich zulässig und frisch; Rechte-Review-Digests (Datei und Zustand) unverändert;
- Feldreview fehlerfrei, für genau diesen aktiven Release (Pointer-Version) und genau diesen Kandidaten;
publishedManifestSha256bei aktivem Release, Snapshot und Kandidat ein gültiger SHA-256 und identisch;- veröffentlichte Zeilen ohne neue, entfernte, geänderte oder im Umriss geänderte Flächen;
- Geometrievergleich räumlich und binär gleich,
comparedgleich der veröffentlichten Anzahl; - Ausschluss- und Scope-Manifest auf beiden Seiten gültig; die feldweise Ausschluss-Delta erklärt die Manifeständerung.
Wandert ein Eintrag aus der Ausschlussmenge in die Veröffentlichung (oder
umgekehrt), ändert sich die veröffentlichte Menge — das bleibt ausnahmslos
reviewpflichtig. Das Ergebnis enthält bei automatischer Freigabe
automaticApproval mit kind: "excluded_or_scope_only", den neuen,
entfernten und geänderten Ausschluss-UBA-IDs sowie den Zählern
Ausschluss/Außer-Scope vorher → nachher; bei Reviewpflicht stehen die
Sperrgründe in automaticApprovalBlockers (etwa published_rows_changed
oder published_geometry_changed). Das Ergebnis-JSON des Laufs im Admin
nennt die automatische Freigabe mit denselben IDs, geometriefrei. War der
vorige Lauf noch reviewpflichtig, geht eine Entwarnungsmail mit Art und IDs
raus (bis 06.10.2026: Schließkommentar des Review-Issues); für eine
automatische Freigabe allein wird nichts gemailt. Nachweis ist das
Ergebnis-JSON des Laufs (/admin/cron/renew-altlasten-snapshot/runs/<id>,
90 Tage Aufbewahrung wie zuvor das Actions-Artefakt).
Bewusster Trade-off: Neue Ausschlüsse werden nicht mehr einzeln bewusst gesichtet. Da ausgeschlossene Einträge nie im Bericht erscheinen, zeigt der veröffentlichte Bericht dadurch nie mehr als vorher; übersehen werden kann nur, dass ein Vorschlag auftaucht oder verschwindet.
Seit #640: nur Geometrie-Rauschen an veröffentlichten Flächen. Am 3. und
4. Oktober 2026 meldete der Nachtlauf drei geänderte veröffentlichte Flächen
(#640). Zwei davon —
O19 „Spenglerei Aumayr“ (UBA-ID 72284) und O91 „Chemische Reinigung
Wozabal Katzbach“ (81730) — hatten nur einen neuen Umriss: größte
Grenzverschiebung je rund 5,8 mm, hinzugekommene plus weggefallene Fläche 0,19 m²
bzw. 0,02 m², kein Feld geändert. Die dritte, N86 „Teerablagerungen Kromag“,
hatte echte Feldänderungen (sanArt und sanStatus von leer auf
„Beobachtung“ bzw. „in Planung“). Freigabe von Andreas am 6. Oktober 2026:
Reines Geometrie-Rauschen geht ohne Review durch.
Der Nachtlauf aktiviert einen Kandidaten mit geändertem veröffentlichtem
Manifest deshalb nach dem feldweisen Review automatisch (Grund
published_geometry_noise_renewed, Expected-Current-CAS), wenn alle
folgenden Punkte gelten — sonst, auch bei jeder fehlenden oder ungültigen
Angabe, bleibt es beim Review:
- dieselben Vorbedingungen wie bei #602: aktiver Release, offenes Gate, gleiche Transform- und Scope-Version, Kandidat zulässig und frisch, Rechte-Review-Digests unverändert, Feldreview fehlerfrei für genau diesen aktiven Release und Kandidaten;
- keine neue und keine entfernte veröffentlichte Fläche, gleiche Anzahl auf allen Seiten;
- jede geänderte Fläche hat kein einziges geändertes Feld, nur einen neuen Geometrie-Hash;
- für jede dieser Flächen liegen vollständige Kennzahlen vor (höchstens 200 je Lauf), und Fläche nachher minus vorher stimmt mit hinzugekommener minus weggefallener Fläche überein;
- größte Grenzverschiebung (
ST_HausdorffDistance) unter 1 cm; - hinzugekommene plus weggefallene Fläche kleiner als ein 1 cm breiter Streifen entlang des kürzestmöglichen Umrisses dieser Fläche (Kreis gleicher Fläche, also 1 cm × 2·√(π·Fläche)) — für O19 sind das 2,57 m², für O91 0,53 m²;
- Ausschlussmenge unverändert, Scope-Manifest gültig und zum Snapshot passend.
Sobald auch nur ein Feld einer veröffentlichten Fläche geändert, eine Fläche neu oder entfernt ist oder eine Verschiebung die Schwelle erreicht, bleibt der Lauf rot und reviewpflichtig. Ändern sich Ausschlussmenge und Umrisse im selben Lauf, greift keine der beiden Ausnahmen — sie gelten nur einzeln. Der Lauf vom 4. Oktober wäre deshalb auch mit dieser Regel reviewpflichtig gewesen (N86; der aktive Stand war da zudem schon abgelaufen, weil schon der Lauf vom 3. Oktober an N86 hing). Ein Lauf nur mit O19 und O91 wäre am 3. Oktober automatisch durchgegangen.
Das Ergebnis enthält bei automatischer Freigabe automaticApproval mit
kind: "published_geometry_noise" und je Fläche UBA-ID, Altlast-Nr.,
Bezeichnung, Verschiebung, Fläche vorher und nachher, hinzugekommene und
weggefallene Fläche sowie die zulässige Grenze. Bei Reviewpflicht stehen die
Sperrgründe dieser Regel in geometryNoiseApprovalBlockers (etwa
published_fields_changed oder geometry_shift_above_threshold), die der
#602-Regel weiterhin in automaticApprovalBlockers. Ergebnis-JSON im Admin
und gegebenenfalls die Entwarnungsmail (nur UBA-IDs und Zahlen) nennen IDs
und Verschiebungen, ohne Rohgeometrie oder Koordinaten.
Bewusster Trade-off: Millimeterverschiebungen werden nicht mehr einzeln gesichtet. Eine Verschiebung unter 1 cm ändert das Ergebnis nur für einen Adresspunkt, der weniger als 1 cm vom Rand liegt; der Abstand im Bericht ist auf ganze Meter gerundet. Begründung der Schwellen und Restrisiko stehen in ADR-0058, Ergänzung #640.
Jede andere Änderung am veröffentlichten Inhalt bleibt gesperrt: qualifizierter Kandidat,
fehlgeschlagener Lauf (failed in /admin/cron), Review-Mail und Admin-Lauf mit
aktiver Frist, separater Kandidatenfrist, Public-Gate,
Published-/Excluded-/Scope-Delta und — neu seit #582 — dem im selben Lauf
sofort ausgeführten feldweisen Review (neu veröffentlichte Flächen mit
UBA-ID/Altlast-Nr./Bezeichnung/Status vorher-nachher, Attributänderungen,
Entfernungen, Geometrie-Gleichheit), ohne Rohgeometrie, Koordinaten oder
Zugangsdaten. Seit #587 zeigt eine Fläche mit geändertem Umriss die
Zeile explizit an, auch wenn kein ausgewertetes Attribut betroffen ist —
zuvor blieb die Änderungszeile in diesem Fall leer. Bei bis zu 200
gleichzeitig geänderten Umrissen je Lauf nennt die Zeile zusätzlich Fläche
vorher/nachher, hinzugekommene und weggefallene Fläche sowie die größte
Grenzverschiebung in Metern (ST_Area/ST_HausdorffDistance, EPSG:31287,
also direkt in m²/m ohne Umrechnung); darüber hinaus bleibt es beim reinen
Hinweis „Umriss geändert“ ohne Zahlen, die Gesamtzahl betroffener Flächen
steht weiterhin in der Geometriezeile. Seit #640 zeigt die Zeile Werte unter
0,5 mit zwei signifikanten Stellen (zuvor erschienen 5,8 mm als „Grenze bis
0 m verschoben“ und 0,12 m² als „+0 m²“); fehlt eine Kennzahl, bleibt es
beim Hinweis „Umriss geändert“ statt einer scheinbaren 0. Eine Flächen- oder Randänderung ist
kein inhaltlicher Befund für sich — sie kann eine Adresse neu innerhalb
oder in der Nähe eines Altlastenbereichs erscheinen lassen (oder umgekehrt
herausfallen lassen), auch wenn sich am Altlastenstatus selbst nichts
geändert hat; das gehört in die fachliche Prüfung vor einer Aktivierung.
Weiterhin ohne Rohgeometrie oder Koordinaten — nur Flächen- und
Distanzzahlen. Bei Reviewpflicht schickt der Lauf seit ADR-0080 eine Mail an
office@ostheimer.at mit Frist, Grund, Feldreview, der fertigen
Aktivierungsanleitung (beide Wege, mit den konkreten UUIDs) und dem Link auf
den Lauf im Admin; Anhänge sind Ergebnis-JSON und Quellinventar. Jeder
reviewpflichtige Lauf schickt eine eigene Mail, weil jeder Lauf einen neuen
Kandidaten mit neuer UUID erzeugt — maßgeblich ist immer die jüngste. Der
Lauf bleibt failed; der allgemeine Cron-Fehleralarm entfällt dann, außer
die Review-Mail scheitert (dann alarmiert der Fehlerpfad, und das Inventar
bleibt im Ledger dieses Laufs). Entfällt die Reviewpflicht in einem späteren
Lauf, folgt eine Entwarnungsmail. Das GitHub-Issue altlasten-review (#582
Baustein C) wird nicht mehr angelegt; der Code dafür bleibt nur für einen
manuellen Lauf des GitHub-Workflows aktiv. Der Admin zeigt bei einem neueren erfolgreichen, nicht aktiven
Altlastenimport ausdrücklich den offenen Kandidaten. Ein technischer
Importerfolg ist keine Inhaltsfreigabe, und nichts im Nachtlauf aktiviert
einen Kandidaten mit Änderung am veröffentlichten Inhalt automatisch
(Ausnahmen sind nur die engen Regeln oben: #602, bei der Veröffentlichtes und
alle Geometrien byte-gleich bleiben, und #640, bei der sich an
veröffentlichten Flächen nur Umrisse um weniger als 1 cm verschieben).
Statt der Actions-Artefakte altlasten-renewal-review-<run> (bis
06.10.2026) gilt: Das Ergebnis jedes Laufs steht geometriefrei in
cron_runs.result_json (Admin-Lauf, 90 Tage, cron-prune), dazu ein
Inventar-Nachweis sourceInventorySummary (Zeilenzahl, Klassifikation,
SHA-256). Das vollständige geometriefreie Quellinventar (UBAID,
Scopeklassifikation, Zeilen- und Geometriehash, ~0,4 MB) hängt nur an der
Review-Mail und bleibt damit im Postfach erhalten. Keine Rohgeometrie,
Report-ID oder Zugangsdaten hineinschreiben. Ein Abruffehler vor einem
vollständigen Snapshot erzeugt kein scheinbares Inventar.
Der stündliche Driftmonitor zeigt außerdem due ab 24 Stunden vor Ablauf und
stale nach Ablauf im Admin. Am 5. September war dessen damalige Mailzustellung
wegen einer unverifizierten Resend-Domain fehlgeschlagen. Seit 25.09.2026
versendet der Code Drift-Alarme als Tagesdigest und Cron-Fehler sofort über
world4you-SMTP an office@ostheimer.at (ADR-0048, Nachtrag); seit ADR-0080
ist diese Mail auch der Reviewkanal. Als abgenommen gilt sie erst nach dem
ersten belegten Empfang einer Review- oder Fehlermail in Produktion. Der
überprüfbare Ort bleibt /admin/cron/renew-altlasten-snapshot (roter Lauf
mit Ergebnis und Anleitung) — eine Mail, die SMTP annimmt, aber im Spam
landet, löst keinen Ersatzalarm aus. Die verantwortliche Projektbetreuung
prüft einen roten Lauf vor der genannten aktiven Frist.
Review ohne Mutation
Läuft automatisch im Nachtlauf, sobald ein Kandidat reviewpflichtig wird (mit dem dort bereits geladenen Snapshot, ohne zusätzlichen WFS-Abruf, und mit der Kandidaten-ID explizit übergeben — nicht erraten). Für einen manuellen Lauf mit bestehendem projektbezogenem DB-Zugang in der Prozessumgebung:
node scripts/review-altlasten-snapshot.mjs /privater/pfad/altlasten-review.json
Ohne Kandidaten-ID verhält sich das Script wie bisher: es sucht den
neuesten qualifizierten Kandidaten, vergleicht beide
Published-/Excluded-Bestände feldweise und liest die amtliche Quelle erneut
vollständig dreimal. Der Abbruch bei abweichender Quelle prüft seit #582
nur noch die berichtsrelevanten Manifeste (publishedManifestSha256,
excludedManifestSha256, scopeManifestSha256); eine reine
Außer-Scope-Änderung der Quelle lässt den Review durchlaufen und erscheint
stattdessen als informative Außer-Scope-Drift im Ergebnis. Ein
zwischenzeitlich geänderter Pointer stoppt den Review weiterhin. Die
Ausgabe enthält keine Rohgeometrien. automaticApproval: false im
Review-Ergebnis ist verbindlich: Auch unveränderte Geometrien erlauben keine
allgemeine Ausnahme für neue Attributänderungen. Automatische Freigaben
trifft nur der Nachtlauf selbst nach den Regeln #602 (nur
Ausschluss/Außer-Scope, Veröffentlichtes byte-gleich) und #640 (nur
Geometrie-Rauschen unter 1 cm, Felder unverändert); das Review-Script
entscheidet nichts.
Vor Aktivierung prüfen: exakter Release/Manifest, aktiver Pointer-CAS, aktuelle Uhrzeit und Frist, Rechte-/Scope-/Transformbindung, neun erforderliche Qualitätsprüfungen, gespeicherte Zeilen gegen den aktuellen WFS und konkreter Einfluss auf den Report. Gleiche Counts genügen nie. Fehlende historische Quellenzeilen ausdrücklich als Evidenzlücke behandeln. Eine neue unbekannte Änderung braucht eine neue Entscheidung.
Kontrollierte Aktivierung
Die Entscheidung dokumentiert Zielrelease, Gesamtmanifest, Expected-Current, Rechteentscheidung, Delta, Gültigkeit und Rückweg. Nach PM-Abnahme:
node scripts/publish-altlasten-release.mjs \
--activate-release=<geprüfter-release> \
--expected-current-release=<frisch-gelesener-aktiver-release> \
--confirmation='ACTIVATE altlasten public'
Alternativ über den Workflow (die exakten workflow_dispatch-Input-Namen aus
.github/workflows/publish-altlasten-release.yml; Review-Mail und Admin-Lauf
enthalten den fertigen Befehl mit den konkreten UUIDs):
gh workflow run publish-altlasten-release.yml --repo ostheimer/landnutzen \
-f action=activate \
-f candidate_release=<geprüfter-release> \
-f expected_current_release=<frisch-gelesener-aktiver-release> \
-f typed_confirmation='ACTIVATE altlasten public'
Entscheidung ADR-0080: Der Workflow publish-altlasten-release.yml bleibt
ein rein manueller GitHub-Workflow. Er läuft selten (nur nach einem Review)
und verbraucht Actions-Minuten nur, wenn er gestartet wird; das lokale CLI
oben ist gleichwertig, braucht aber den Produktions-DB-Zugang in der Shell.
Ein Umbau auf einen Vercel-Endpunkt würde eine schreibende Aktivierung über
HTTP öffnen und ist deshalb nicht vorgesehen.
Kein direktes UPDATE auf Fristen, Rechte oder Pointer. Danach öffentlichen Release/Pointer, neue anonyme öffentliche Referenzreports (Hit/No-Hit) und Web/API/PDF rücklesen. Keine bestehenden persönlichen Reports suchen oder ändern. Den normalen Renewal-Pfad erneut ausführen: Bei ausreichender Reserve ist ein belegter Skip korrekt; ein erzwungener Fristwechsel wäre es nicht. Einen kontrollierten Lauf nie als bereits erfolgten nächsten planmäßigen Lauf ausgeben.
Rollback und Wiederanlauf
Der generische Rollback verlangt einen früher aktivierten und weiterhin frischen und zulässigen Release, aktuellen CAS, Operation-ID und Grund:
node scripts/publish-altlasten-release.mjs \
--rollback-to=<zulässiger-früherer-release> \
--expected-current-release=<aktueller-release> \
--rollback-reason='<konkreter-grund>' \
--confirmation='ROLLBACK altlasten public'
Der Initialrelease vom 26. August ist seit 28. August stale und damit kein verwendbares Rollbackziel für #556. Ein Code-Rollback auf den vorherigen Main-Commit lässt das unveränderte DB-Schema und den freigegebenen Quellenpointer bestehen. Bei einem Quellenproblem gibt es ohne frischen früheren Release keinen zulässigen Datenrollback: Review stoppen, keine Folgeaktivierung, geschlossene Gates respektieren und nach frischem Drei-Pass-Abruf einen neuen Kandidaten qualifizieren und separat entscheiden. Kein Wiederbeleben alter Daten durch Fristverlängerung. Stale-/Rechte-/Rollback-Sperren werden lokal getestet, nicht absichtlich in Produktion ausgelöst.