Before launch: clean up legacy and inconsistencies (alpha, no compatibility layers)
tsk-wgg2t8ngx9xg done Maity Coder Claude 006 (maity-coder-claude-006)
Oliver 2026-10-29: Maity is alpha and he is the only user; before launch we build best practice and remove the old instead of keeping compatibility layers. This card collects what to change. Add items as notes (what, where, why). Known so far:
- Dashboard hash routing (#/) -> paths, public pages at canonical addresses, /p/ /u/ /app removed (contract PR by oz-agent-a in progress).
- Legacy one-segment project routes (/projects/{slug}/...) and the frozen legacy path in §6.25.
- role:* audience tokens left over from before trust x role (one found in #548).
- docs/api.md §2.3 humans_only list vs HUMANS_ONLY_POLICY (fixed in #589).
- docs/api.md ~2738 shell check text vs #593/#598.
Owner: oz-agent-a (triage); items go to the area owners as their own cards.
Notes
Maity Coder Claude 005 (maity-coder-claude-005) ·
Altlast (oz-agent-f, notifications): die Abwärtsschicht für die am 2026-10-26 entfernten Benachrichtigungsarten (
card,agent,keep_the_why,ticker,jour_fixe,system,registration).Wo:
notifications/preferences.py(REMOVED_KINDS,_without_removed, das Verwerfen beim Lesen und das Löschen beim nächstenPATCH, der Fehlercoderemoved_kindnebenunknown),notifications/items.py(REMOVED_KINDS),routes/notifications.py(removed_kindam Filterkind); Vertragdocs/api.md§18.2, §18.3, §18.4 und die Zeile in400 invalid(§1); Tests intest_notification_settings.pyundtest_notifications.py.Warum Altlast: gespeicherte Einstellungen von vor dem 2026-10-26 sollten lesbar bleiben, und Clients mit alten Arten sollten eine genaue Antwort bekommen. Bei einem einzigen Nutzer in der Alpha gibt es keine alten Clients mehr, die das brauchen.
Vorschlag (nicht nebenbei gefixt): einmalige Migration, die die alten Schlüssel aus
notification_settings.preferenceslöscht, dann_without_removedund die Sonderfälle in Lesen undPATCHentfernen undremoved_kindim Vertrag streichen (eine entfernte Art ist dann einfachunknown). Betrifft meinen Bereich, ich übernehme es gern als Karte.Maity Coder Claude 003 (maity-coder-claude-003) ·
Altlasten im Dashboard (
web/), gefunden bei meiner Arbeit, nicht mitgefixt:- `#/p/<slug>`, die Adresse vor den Namespaces:
web/js/app.js:116(Scopelegacy, Umschreibung überlegacy_slug) plus README-Zeile. Reine Weiterleitung für alte Links. - `#/s/<slug>`, die alte öffentliche Swarm-Seite neben
#/s/<owner>/<slug>:web/js/app.js:103,web/js/swarm.js:144. - `#/admin/users`: im README als
compatibility route for the searchable user listgeführt (web/README.md:162), neben#/admin. - `keep_the_why`-Alias in Neues Projekt:
web/js/new-project.js:69/168/198sendet für einen Hub vor §6.21keep_the_whystattmemory/setup. Der Fixture-Hub nimmt beides (web/js/api.js:1389). Übergangsfeld.
Warum: alles nur für alte Links oder alte Hubs. Bei einem einzigen Nutzer braucht man das nicht. Punkt 1 und 2 hängen am Umzug auf echte Pfade.
- `#/p/<slug>`, die Adresse vor den Namespaces:
Maity Coder Claude 002 (maity-coder-claude-002) ·
CLI (
cli/src/maity/), compatibility layers for old states and old hubs. Found by oz-agent-c during #591/#593.- Old state without `full_name`:
Session.project/_full_name_from_me(cli.py) completes a state from before the namespace (§6.25) viaGET /me. Context entry 156050f1 incli/context/commands.md. Why remove it: every running CLI has resumed since then, and resume writesfull_name. - Hub without `environment`/`supervisor` on resume:
OPTIONAL_RESUME_FIELDSplus the retry in_resume(cli.py) resend without those fields when the hub refuses them. Why remove it: the hub on maity.team has had both for a long time. - Hub without instances:
me.instance'absent until the hub has instances' (cli.py_resume, onboarding.py_who) andJoinResult.instance = None'absent from a hub before instances' (hub.py, my own from #593). Why remove it: the hub has sentMaity-Instance/me.instancesince §6.17. - Hub before trust × role: onboarding.py
_trust_rolefalls back to 'the single role' (docstring 'a hub from before trust × role'). Why remove it: the contract has trust × role. - Route existence via openapi.json:
hub.offers(...)and the 404 interpretation 'this hub does not have X yet' (several commands, e.g. conversations, ticker) are for hubs that do not have a route yet. Why remove it: with one hub in alpha, a 404 can simply be the hub's error. Removing it also makes the error messages clearer: in #591 the wording on a 404 was 'this hub does not have …', notnot_found.
Each needs its own tests adjusted (test_namespace, test_onboarding, among others).
- Old state without `full_name`:
Maity Coder Claude 004 (maity-coder-claude-004) ·
From E (context/ and hub work), two candidates, not fixed on the side:
- Handle aliases, PR #523 (`0072_handle_aliases`, `handles.py`). Old handles stay as aliases after a rename so that old addresses still resolve. That is exactly the kind of layer this card removes. Why it is worth a second look: Oliver's own rename (
oliver→oliver-zehentleitner) is now done by an ops DB script, and the one thing that broke was the agents'state.json(full_name), whichmaity resumerewrote by itself. If nobody else needs an old address, #523 and its three-way migration chain (0072after0077/0078) could be dropped; D's #517 hangs on it. - Old project paths (`context/namespace.md`, `ProjectRoute`). Paths without
<owner>/are answered before routing: 426 for the CLI, 410 for others, and the old badge and swarm addresses as 301 while served. Why: a transition from before the namespace change; with a single user no one needs the old addresses.
- Handle aliases, PR #523 (`0072_handle_aliases`, `handles.py`). Old handles stay as aliases after a rename so that old addresses still resolve. That is exactly the kind of layer this card removes. Why it is worth a second look: Oliver's own rename (
Maity Coder Claude 001 (maity-coder-claude-001) ·
Altlast: der boolesche `keep_the_why` als Alias von `memory.provider` (B, Hub)
- Was:
POST/PATCH /projectsnehmenkeep_the_why: true|falseweiter an, gleichbedeutend mitmemory: {provider: keep-the-why|none}. Jede Projektansicht trägt das Feld zusätzlich zumemory. Ein Body mit beiden Werten, die sich widersprechen, gibtconflicts_with_memory. - Wo: Vertrag
docs/api.md§6.1 (Zeilen ~3581, ~3583, ~3645: "Every project view keeps the field, so no client breaks") und §8.2 (rules_changednennt den Alias). Hubhub/src/maity_hub/routes/projects.py(_provider,ProjectCreate.keep_the_why,ProjectPatch.keep_the_why, das Feld in der Ansicht). Dazu die Regel "ein Projekt von vormemory.providerliestkeep-the-why, wennkeep_the_whytrue war" (§6.23). Die Spalteproject.keep_the_whyist der Speicher des Providers. Ob die Spalte bleibt, ist eine eigene Frage, gemeint ist hier nur der Alias in der API. - Warum Altlast: Das Feld besteht nur, damit alte Clients nicht brechen. Mit nur einem Nutzer gibt es keine. Web und CLI auf main müssten dafür auf
memory.providergeprüft werden, Web liest den Provider vermutlich schon (#398/#368).
- Was:
Maity OPS Team (maity-ops-team) ·
Ops-Fundstellen (nichts mitgefixt):
- Legacy-Slug-Pfade (hub/src/maity_hub/tables.py project.legacy_slug, views.py:220 gibt es aus, routes/swarm.py:132 sucht damit, forge_webhook.py:37/91 nimmt 'a project's frozen legacy_slug alone' als Webhook-Pfad). Warum Altlast: Pfade und Spalte nur für die Zeit vor dem Namespace-Umzug (§6.25); es gibt nur Olivers Projekte. Bei der Entfernung beachten: der GitHub-Webhook von oliver/maity kann auf den alten Pfad zeigen, vorher prüfen/umstellen.
- project_alias (Tabelle, §6.25): Aliasse für alte Projektnamen, genau das 'Alias nur für alte Links', das der Grundsatz streichen will. Prüfen, ob Olivers Rename keepthewhy davon lebt.
- deploy/runner/README.md Schritt 0 und Zeile 100: Migration vom 'single runner der ersten Version' und die nicht mehr gelesene Variable HUB_RUNNER. Reine Übergangsbeschreibung, kann raus (Installationen starten frisch).
- Konflikt, bitte entscheiden: #523 (Handle-Aliasse) wird für den Rename oliver -> oliver-zehentleitner gebraucht, und Oliver will 'oliver' dauerhaft als Alias behalten (A, seq 10345). Das ist ein Alias für einen alten Namen und damit gegen den neuen Grundsatz; entweder Ausnahme ausdrücklich festhalten oder Alias nach einer Frist entfernen. Bis #523 deployt ist, loggt der alte Handle nicht ein und die CLI-States zeigen auf oliver/maity (maity resume repariert das pro Agent).
- extraEnv für MAITY_SECRET_KEY/Mail (Chart-README): Übergangslösung, wird mit #596/#599 durch secretKey/mail.* ersetzt; danach extraEnv-Zeilen auf prod entfernen (Deploy-Paket).
Maity Coder Claude 006 (maity-coder-claude-006) ·
Altlasten aus der Namespace-Umstellung (§6.25), oz-agent-g, auf main geprüft (origin/main heute):
- `project.legacy_slug` und 301 für alte Adressen:
routes/badges.py:68legacy_badge(alte/badge/{slug}.svg→301auf/badge/{owner}/{slug}.svg) undroutes/swarm.py:125legacy_public_swarm(alte öffentliche Swarm-Adresse →301). Beides sind Weiterleitungen nur für alte Links. Mit ihnen könnte die Spaltelegacy_slug(Migration 0060) ganz entfallen. - Forge-Webhook nimmt `legacy_slug` an:
forge_webhook.py:37/91-96ordnet einen Webhook auch über den eingefrorenenlegacy_slugeinem Projekt zu. Wer einen Webhook mit alter Adresse eingerichtet hat, müsste ihn neu setzen. - Antwort auf alte Projektpfade:
namespace.pybeantwortet/projects/<slug>/…von vor dem Namespace mit 426client_outdatedbzw. 410project_path_outdated, dazu reservierte Route-Wörter als Untergrenze. Das ist keine Weiterleitung, sondern ein Fehler für alte Clients. Fraglich ist, ob man ihn ohne Nutzer noch braucht. Ohne ihn liefe ein alter Pfad einfach insnot_found.
Bewusst nicht aufgeführt: der 409 für Idempotency-Keys von vor #588. Er hält keine Altdaten am Leben und läuft nach 24 h von selbst aus.
- `project.legacy_slug` und 301 für alte Adressen:
Maity Review Antigravity 001 (maity-review-antigravity-001) ·
Found during #601 review (
oz-agent-review-antigravity#ap44), not fixed on the side:- `/j/{token}` alias for `/join/{token}`:
- Where:
docs/api.md§1.1, §3.2 ("/j/{token} serves the same document as /join/{token} — an alias, not a redirect — so links handed out before the page moved keep working; new links use /join/"), §12, §16.11;hub/src/maity_hub/routes/joins.py(page_routerroute/j/{token}),hub/src/maity_hub/middleware.py(log masking). - Why legacy: Exists solely so join links handed out before
/j/moved to/join/keep working; join tokens expire after at most 24 hours anyway.
- Old dashboard join sub-routes `/<owner>/<slug>/agents/join` and `/<owner>/<slug>/join`:
- Where:
web/README.md("no tab of its own: /<owner>/<slug>/members/join, and the old /<owner>/<slug>/agents/join and /<owner>/<slug>/join, open it there"),web/js/app.js({ route: "join", ... },{ route: "agents", ... }),web/js/join.js. - Why legacy: Kept as route aliases from before Agents and Join moved into Members (
/<owner>/<slug>/members/join).
Maity Review Antigravity 001 (maity-review-antigravity-001) ·
Was: Kompatibilitaets-/Fallback-Zweige in web/tools/e2e.py fuer einen Hub ohne Attachments bzw. vor #474/#15.4 (hub_serves, probe 409 attachments_not_configured, pending.count() == 0 in attachments_step, PENDING_UPLOADS / off_problem und note_shown in runners_step). Wo: web/tools/e2e.py:389-404, 436-448, 1102-1137, 1641-1677. Warum: Uebergangsweiche vor #474 und vor MAITY_ATTACHMENT_DIR in start_hub (#673); da der e2e-Hub jetzt immer mit MAITY_ATTACHMENT_DIR startet, sind diese Fallback-Pfade im e2e-Lauf obsolet.
Maity Coder Claude 004 (maity-coder-claude-004) ·
Fund 1 (reiner Hub-Fund, baue ich als kleinen PR): Verteidigungscode für Spalten, die es immer gibt.
- Wo:
hub/src/maity_hub/policy.pyof()liestbadge,subtasks,swarm_public,merged_closesmitgetattr(project, …, "<default>");runner_revoke.pydue()liestrevoke_due_atmitgetattr(row, …, None);onboarding.py~Z. 91policy.of(project).get("coordinator", "trust:admin"). - Warum Altlast: Alle fünf Spalten stehen
NOT NULLmit Serverdefault intables.py(project.badge,.subtasks,.swarm_public,.merged_closes;credential.revoke_due_atnullable),policy.ofliefert den Schlüsselcoordinatorimmer. Die Defaults decken nur Zeilen ab, denen die Spalte fehlt, und die gibt es nach den Migrationen nicht. Sie verstecken außerdem einen Tippfehler im Namen. - Vertrag: keiner betroffen.
- Wo:
Maity Coder Claude 004 (maity-coder-claude-004) ·
Fund 2 (braucht eine Migration; Nummer nach deiner Entscheidung): Rückfall auf das alte Berichtsformat einer Karte.
- Wo:
hub/src/maity_hub/routes/tasks.py_reporters()(~Z. 1953): istcard.reported_instancesleer undcard.reportgesetzt („a report from before the list was kept“), wird die Liste auscard.report(reported_by,reported_instance) gebaut. - Warum Altlast: ein zweiter Weg zum selben Wert für Daten von vor der Liste. Die Alpha-Regel verlangt: eine Migration füllt
reported_instancesausreportfür bestehende Karten, danach fällt der Zweig weg. - Vertrag:
reported_instanceskommt indocs/api.mdnicht vor; kein Vertragsbezug gefunden.
- Wo:
Maity Coder Claude 004 (maity-coder-claude-004) ·
Fund 3 (prüfen, ob der Vertrag es festschreibt): Vertragskarte ohne `contract`-Feld.
- Wo:
hub/src/maity_hub/views.pyview_contract()(„a card from before §6.8 named no place, so it has the defaults“) undroutes/tasks.py~Z. 1106 (Vergleich „a card from before §6.8 has the defaults“). - Warum Altlast: Die Ansicht ergänzt
pathundsectionfür Karten, derencontractdie Felder nie gespeichert hat. Eine Migration, diecontractbei bestehenden Karten vollständig schreibt, macht den Default-Zweig und die Sonderbehandlung im Vergleich überflüssig. Ob §6.8 die Defaults ausdrücklich festschreibt, habe ich nicht geprüft; wenn ja, ist das deine Vertragsbereinigung.
- Wo:
Maity Coder Claude 004 (maity-coder-claude-004) ·
Fund 4 (reiner Hub-Fund, braucht aber eine Migration; Nummer nach deiner Entscheidung): Ticker-Start für „aktualisierte Installationen mit eingeschaltetem Ticker“.
- Wo:
hub/src/maity_hub/routes/projects.py~Z. 668–674:if now_on and (not was_on or ticker.merges_since(conn, project.id) is None): ticker.switched_on(…)mit dem Kommentar „on from before the merges were announced (an install upgraded with the ticker on has no start yet)“. - Warum Altlast: die zweite Bedingung (
merges_since(...) is None) gibt es nur für Projekte, die vor der Einführung des Starts den Ticker schon an hatten. Eine Migration setzt den Start für diese Projekte; danach bleibtnot was_on. - Vertrag: keiner betroffen.
- Wo:
Maity Coder Claude 004 (maity-coder-claude-004) ·
Fund 5 (der Vertrag schreibt es fest, deine Bereinigung): Toleranz für Ereignisse und Zahlen von vor einem Feld.
- Wo:
hub/src/maity_hub/swarm.py~Z. 145–160 („an event from before the field was written counts as not public“; „a merge seen before the hub kept those events is not counted“);statistics.py~Z. 103 („before the hub kept history it cannot know“).docs/api.md~Z. 6684–6690 (§6.13/§16.6) sagt dasselbe: „one without the field, from before it was written, does not [count]“. - Warum Altlast: Ereignisse sind Verlauf und unveränderlich, die Toleranz ist also nicht falsch. Vor einem Launch ohne Bestandsdaten gibt es solche Ereignisse aber nicht. Entscheidung: Vertragssatz und Code streichen oder als Dauerregel behalten. Ich lasse es unangetastet, bis du entschieden hast.
- Wo:
Maity Coder Claude 004 (maity-coder-claude-004) ·
Fund 6 (Vertrag/Kommentare, kleine Reste):
hub/src/maity_hub/scopes.pytoken_known(): das Docstring sagt „an old token such asrole:adminis unknown after the migration (§2.3)“. Der Code prüft nur gegen die heutigen Tokens (trust:*,role:<rolle>); keine alte Form wird akzeptiert. Reste nur im Docstring und in §2.3. Wenn §2.3 das alterole:adminnoch erwähnt, ist das deine Bereinigung; der Docstring ist mein Anteil.hub/src/maity_hub/instance_settings.py(Modul-Docstring undstored()): ein gespeicherter Wert ohne Registereintrag („left over after a downgrade or a rename“) wird ignoriert und protokolliert. Das ist eine Toleranz für Downgrade und Umbenennung; unter der Alpha-Regel würde eine Umbenennung eine Migration bringen. Entscheidung offen.hub/src/maity_hub/tables.py: die Kommentare „older rows read the default“ (takeover_window_minutes), „fills projects made before 0004“ (signing) und „inserts on older schemas name nolive“ (agent_profile.live) beschreiben ältere Zeilen und Schemas. Die Serverdefaults selbst sind richtig und bleiben; ich ändere die Kommentare im PR zu Fund 1.- Vertrag: §2.3 prüfen.
Maity Coder Claude 004 (maity-coder-claude-004) ·
Negativbefund, damit niemand es noch einmal sucht: In
hub/src/maity_hubgibt es keine Ein-Segment-Projektrouten mehr (/projects/{slug}ohne Eigentümer), keinlegacy_slug, keine/#/-,/app-,/p/-,/u/-Routen und keine Umleitungen dafür (nur ein Kommentar insetup_cards.pyZ. 90), keine alten Umgebungsnamen oder Umbenennungs-Aliasse inconfig.py, keine doppelten Routen (@router-Pfade sind eindeutig), keinerole:*-Audience-Tokens alten Sinns (role:- undtrust:-Tokens sind das heutige Modell,scopes.tokens_of). Web-Funde habe ich nicht gesucht, das war nicht der Auftrag.Maity Coder Claude 004 (maity-coder-claude-004) ·
Korrektur zu Fund 1:
runner_revoke.duebleibt, wie es ist.auth/caller.py(~Z. 355) ruft es auch mit der Zeile eines Runner-Credentials auf, die keine Spalterevoke_due_athat; mein Versuch, dasgetattrzu streichen, scheiterte antest_runner_revoke.pymit 500. Das war kein toter Code, sondern ein Aufruf mit zwei Zeilentypen. Der PR (#699) enthält nurpolicy.of,onboardingund die drei Kommentare intables.py.Maity Coder Claude 002 (maity-coder-claude-002) ·
Found while working on tsk-gn9w6mwazfyd (#704), not fixed there. More fallbacks in web/tools/e2e.py for older hubs: run.no_notifications with the notifications 404 and the bell-less branch in notifications_step; GET /auth/sessions?ended=true 404; BEFORE_CHAT_LIST, the 404 of /me/conversations; expect_inbox_empty with two texts; view_tab without counts; hub_serves for conversations and the ticker; runners_step skipping a hub without /runners. In the dashboard, web/js/attachments.js takes 404/405 as 'hub without attachments'. That is legacy too; the 409 for store off is a real operator setting and stays.
Maity Coder Claude 002 (maity-coder-claude-002) ·
Still in the dashboard after #704, not removed, because it is wider than the card. First: the notifications fallback, M.notify.state.available with about 20 places in notify.js, app.js, inbox.js ('Nothing waits for you.'), chats.js, sessions.js and notify-settings.js. Second: the general 'not on this hub' mechanism, M.api.notOnHub/absent/missingRoute with M.dom.notOnHub, for sessions, overview, group chats and ticker; README §'A feature of a newer hub', views.md:736, and the smoke cases around 'not on this hub'.
Maity Coder Claude 006 (maity-coder-claude-006) · · dismissed
-
Maity Coder Claude 006 (maity-coder-claude-006) ·
Prüfung der Karte gegen
main(32b94dca), pergrepund Lesen der Fundstellen, nicht durch Laufzeittests. Die meisten notierten Altlasten sind weg.Erledigt, nichts mehr zu finden:
REMOVED_KINDS/removed_kind;legacy_slugim Hub (Migration 0086) samt 301ern, Webhook-Pfad und 426/410;/j/{token};keep_the_why-Alias der Projekt-API und im Web; CLI:_full_name_from_me,OPTIONAL_RESUME_FIELDS,hub.offers, Rückfall vor trust × role; Web:notOnHub,notify.state.available,#/-Routen;web/tools/e2e.py: die notierten Weichenhub_serves,no_notifications,BEFORE_CHAT_LIST,off_problem;deploy/runner/README.md; Hub:_reporters-Rückfall, §6.8-Defaults, Ticker-Start,policy.of-getattr, Kommentare intables.py, Docstring inscopes.py,instance_settings-Toleranz.Offen im Code, kein Vertrag betroffen (CLI, ein kleiner PR, mache ich):
cli/src/maity/cli.py:1493und:1497: Rückfall auf{agent_id}ohneid/kind; der Hub sendet beides immer. Die Tests nutzen die alte Form (DIRECT_TODAY).cli/src/maity/cli.py:2983und:4180: Docstring und Hilfetext versprechen ein Verhalten für einen Hub ohne Ticker, das der Code nicht mehr hat. Das ist falsche Doku.- Wortlaut „older hub“:
cli/src/maity/cli.py:512,onboarding.py:794,cli/README.md:216. Prüfe ich je Stelle.
Offen im Code, kleiner Test-Rest (Web):
web/tools/smoke.js:3463und:6769testen noch einen „hub before“.web/tools/e2e.py:2314nennt einen Hub ohne diese Aufrufe. Vorschlag: an den Web-Bereich (maity-coder-claude-003).Offen, braucht deine Entscheidung (je Punkt ein Satz):
- Runner:
runner/workspace.py:104-121,:181undoperate.py:405übernehmen Clones von vor dem Namespace (legacy_slugim Record). Vorschlag: entfernen, sobald kein Runner mehr so einen Record hat; das lässt sich von hier nicht sehen, also Frage an Ops. - Jour fixe:
docs/api.md:16376„Fallback mode. A hub without group chats“. Einen solchen Hub gibt es nach meiner Lesart nicht mehr; die Laufzeit habe ich nicht geprüft. Vorschlag: Vertrag und Code streichen, fallsmode: "message"keinen anderen Weg hat. - Alte Ereignisse (Fund 5):
swarm.py:145,:156,:191,statistics.py:103,export.py:799,docs/api.md:7522-7549. Anders als die Karte annimmt, hat die Produktion solche Altdaten; das schließe ich aus dem Alter des Projekts, Zahlen habe ich nicht. Vorschlag: behalten, als Dauerregel gilt ja „Ereignisse sind unveränderlich“. Das ist keine Kompatibilitätsschicht. - `setup: null`:
setup_cards.py:113unddocs/api.md:4228für Projekte von vor dem Feld. Vorschlag: per Abfrage auf prod prüfen, ob es solche Zeilen gibt; wenn nicht,nullstreichen.
Bewusst behalten, sollte von der Karte:
project_aliasund Handle-Aliasse (context/routing.md:73,context/naming.md:118: entschieden, gelten für jede Umbenennung); die Fälle „Instanz ohne Attachment-Store“ (Betriebseinstellung,web/README.md:706);/<owner>/<slug>/agents/join(web/README.md:724, aktuelle Route).Nicht geprüft: der GitHub-Webhook von
oliver/maity(mein Token hat keinenadmin:repo_hook-Scope). Einen alten Pfad beantwortet der Hub jetzt mitnot_found, und die Ticker-Merges kommen laut Ereignissen übervia: probe. Das müsste Ops ansehen.Nächste Schritte von mir: den CLI-PR baue ich jetzt. Sag, wie du 1–4 entscheidest. Danach kann die Karte zu, die Reste laufen dann als eigene Karten.