#0055 is done: ThreadNet-Web be323ed checks in an .npmrc binding @sorb to rohana. The bump that mattered was not the file but what upstream's .gitignore does with it - it ignores /.npmrc, so the naive fix would have stayed local while CI kept resolving against npmjs. Measured in an isolated tree: without the file pnpm goes to npmjs and fails, with it the scope resolves to rohana at the integrity hash the lockfile already carries, and with rohana unreachable the install fails instead of falling back. threadnet-call only publishes and already sets the scope in its own CI; gitops never touches it. ThreadNet-Web was the only consumer. Four issues no longer describe reality, each verified rather than assumed: - #0091 (gitops#61) was fixed when it was written - on_conflict: fail shipped in ef04d86 and the MAS pod has run that config since 2026-08-11T14:08:41Z. Its one deliberate remainder became #0043, which is closed and verified live. - #0079 (gitops#46) asked for the Gitea migration and a central view. The migration ran; the central view was decided the other way round - repo canonical, GitLab mirrored (ADR-0012/0019) - which also answers the reachability trade-off it left open, and better than its three options did. - #0075 (gitops#40) is rejected, not done: it wanted new issues to appear in the Gitea kanban automatically. Issues no longer live in Gitea and the board is script-written. Nothing was accomplished; the question dissolved. - #0098 is a rollout record whose only remainder, the macOS build, is #0022. Three AARs move to harvested - every open item in them is tracked as an issue. Checked and still accurate, so left alone: the wiki branch still exists on both remotes (#0019), docs/TASKS.md and oldwiki/ are still there (#0085), element-web-docs still names live resources (#0086), res/themes/element persists (#0100), only WIKI_CANONIZE_TOKEN is set so TURN rotation still lacks its token (#0084), gameserver still has zero push mirrors (#0032), the broken .6 package is still published (#0101), and options.ts still builds simulcast layers regardless of codec, which is what blocks VP9 (#0057). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
113 lines
6.5 KiB
Markdown
113 lines
6.5 KiB
Markdown
---
|
|
type: aar
|
|
status: harvested
|
|
date: 2026-08-11
|
|
related: []
|
|
---
|
|
|
|
# AAR — `@apo` konnte nicht telefonieren: fehlende Synapse-`profiles`-Zeile
|
|
|
|
**Datum:** 2026-08-11 · **Beteiligt:** sorb + Mac-Session · **Stack:** Synapse,
|
|
MAS, Authentik, Element Web / Element Call, MatrixRTC (K3s-Cluster)
|
|
**Auftrag:** `@apo` kann sich anmelden und schreiben, aber **kein Call kommt
|
|
zustande** — Grundursache finden und beheben, ohne weiter zu raten.
|
|
|
|
## 1. Ergebnis
|
|
|
|
**Behoben und verifiziert:**
|
|
- `@apo` telefoniert wieder. Grundursache belegt: dem Konto fehlte die Zeile in
|
|
Synapses `profiles`-Tabelle. Fix war ein einzelnes `INSERT` der
|
|
Registrierungs-Default-Zeile, an zwei gesunden Konten (`clark`,
|
|
`calltest01`) gegengeprüft.
|
|
- Gegenprobe nach dem Fix: `displayname` gesetzt (vorher keine Zeile),
|
|
`open_id_tokens` **0 → 6**, aktives `org.matrix.msc3401.call.member` im Raum.
|
|
- Dokumentiert: Runbook `docs/troubleshooting/CALLS-FEHLEN-PROFILE-ZEILE.md` im
|
|
gitops-Repo (inkl. Index-Eintrag), Merksatz im Session-Gedächtnis.
|
|
|
|
**Nebenbefund, separat behoben:**
|
|
- **Kontoübernahme-Lücke:** Der MAS-Upstream-Provider stand auf
|
|
`claims_imports.localpart.on_conflict: add` — bei Localpart-Kollision verknüpfte
|
|
MAS die neue Upstream-Identität mit einem **bestehenden** Konto (inkl.
|
|
Dienstkonten ohne Upstream-Link). Auf `on_conflict: fail` umgestellt
|
|
(gitops `ef04d86`, nach git.lab gepusht), dokumentiert als
|
|
[gitops#61](https://git.lab/axion1337.chat/axion1337.chat-gitops/-/issues/61),
|
|
`priority:high`. Ausgelöst durch die live reproduzierte case-sensitive Dublette
|
|
`boje`/`Boje`; das Zweitkonto `boje` (Authentik-ID 11) wurde gelöscht.
|
|
**Deployment verifiziert:** Das SOPS-Values-Secret aktualisierte Flux, aber MAS
|
|
lief noch mit der alten Config im Speicher (Pod älter als die Änderung) — erst
|
|
ein `rollout restart` machte `fail` aktiv. „Committet" ≠ „deployed" ≠ „aktiv".
|
|
|
|
## 2. Die Kausalkette (belegt, nicht vermutet)
|
|
|
|
| Glied | Beleg |
|
|
|---|---|
|
|
| `@apo` hat **keine `profiles`-Zeile** | `SELECT count(*) … = 0`, während `clark`/`sorb`/`calltest01` je eine haben |
|
|
| Displayname-Setzen crasht | `PUT …/displayname → 500`, `TypeError: 'NoneType' object is not subscriptable` in `_check_profile_size` (`storage/databases/main/profile.py:354`) — `txn.fetchone()` liefert `None`, `row[0]` fliegt |
|
|
| kein Displayname → Widget-Init bricht ab | Call-Klick erzeugte **null** Server-Aktivität: kein `openid/request_token`, kein `call.member`; Browser-Log damals „Messaging present but not yet started" (iframe meldet nie `ContentLoaded`) |
|
|
| kein Widget → kein Token → keine SFU | `@apo` als einziger aktiver Nutzer mit **0** Einträgen in `open_id_tokens` (die nicht geprunt werden) |
|
|
|
|
Herkunft der fehlenden Zeile: `@apo` ist ein **Vor-Authentik-Konto**, das durch
|
|
sechs Identitäts-Resets ging. Deaktivieren löscht in Synapse das Profil,
|
|
Reaktivieren legt es nicht neu an. `frank` (noch älter, nie zurückgesetzt) behielt
|
|
seine Zeile. Ob einer der früheren manuellen Eingriffe der auslösende Reset war,
|
|
ist nicht mehr zweifelsfrei zu klären — die Zeile ist jetzt wieder da.
|
|
|
|
## 3. Was ausgeschlossen wurde (gemessen)
|
|
|
|
| Verdacht | Warum entkräftet |
|
|
|---|---|
|
|
| Krypto / Cross-Signing (18 Pseudo-Geräte aus 6 Resets) | Testraum ist **unverschlüsselt** → Call braucht keine Krypto; `clark` telefoniert mit ebenfalls zurückgesetzten Schlüsseln |
|
|
| Server-Call-Pfad (SFU, RTC-Auth, OpenID-Endpoint) | `calltest01`/`sorb` bekommen sauber 200 auf `openid/request_token` und die Federation-Auflösung |
|
|
| `@apo`s Token / Session | `/sync` läuft durchgehend mit 200, Messaging intakt |
|
|
| Login-Verknüpfung MAS↔Authentik | `subject` = Authentik-`uid` `2fafe38b…`, korrekt |
|
|
|
|
## 4. Was zur Lösung geführt hat
|
|
|
|
- **Der Sprung von „welcher Nutzer telefoniert nicht" zu „welche *Tabelle* ist
|
|
anders".** Der Durchbruch war die `open_id_tokens`-Abfrage über *alle* aktiven
|
|
Nutzer: `@apo` = 0, alle anderen zweistellig+. Ein Vergleich statt einer
|
|
Einzelbetrachtung.
|
|
- **Ein unverschlüsselter Testraum** hat das größte Ablenkungsfeld
|
|
(Cross-Signing) in einem Schritt geschlossen.
|
|
- **Der Live-Mitschnitt beim echten Call-Klick** zeigte die Abwesenheit jeder
|
|
Aktivität — nicht ein Fehler, sondern *nichts* war der Befund.
|
|
- **Der Nutzer-Hinweis „Anzeigename konnte nicht gesetzt werden"** lieferte den
|
|
500er mit vollständigem Stacktrace — die letzte Meile von Korrelation zu
|
|
Ursache.
|
|
- **Der entscheidende Kontext kam von sorb:** „`apo` ist ein Alt-Konto von vor
|
|
der Authentik-Integration." Das lenkte die Suche von „angesammelter Müll" auf
|
|
„Migrations-/Provisionierungs-Lücke".
|
|
|
|
## 5. Lehren für die Zukunft
|
|
|
|
1. **Bei Call-Problemen zuerst `open_id_tokens` je Nutzer vergleichen.** 0 bei
|
|
einem sonst aktiven Konto ist das schnellste, eindeutigste Alarmsignal und
|
|
trennt Client- von Server-Ursache in einer Abfrage.
|
|
2. **Immer im unverschlüsselten Raum reproduzieren, bevor man Krypto verdächtigt.**
|
|
Das schließt einen ganzen Ursachenblock kostenlos aus.
|
|
3. **„Nichts passiert" ist ein Messergebnis, kein Sackgassen-Signal.** Die
|
|
Abwesenheit eines `openid`-Aufrufs hat den Fehler lokalisiert, nicht ein
|
|
Fehlercode.
|
|
4. **Alt-/mehrfach-zurückgesetzte Konten gegen frisch provisionierte diffen,
|
|
nicht nur gegen die Erwartung.** Der Unterschied war eine *fehlende* Zeile —
|
|
sichtbar nur im direkten Vergleich mit `clark`/`calltest01`.
|
|
5. **Jeder DB-Schreib strukturiert: betroffene Zeile vorher anzeigen, an einem
|
|
gesunden Konto gegenprüfen, per `INSERT … ON CONFLICT DO NOTHING` statt
|
|
Überschreiben.** Das ist die direkte Konsequenz aus den früheren
|
|
unstrukturierten MAS-Eingriffen dieses Vorgangs — und diesmal eingehalten.
|
|
6. **Beiläufige Symptome ernst nehmen:** die Dublette `boje`/`Boje` beim
|
|
Testkonto-Anlegen war der Faden, der die Kontoübernahme-Lücke (gitops#61)
|
|
aufdeckte — ein Sicherheitsfund, der ohne den `@apo`-Vorgang unentdeckt
|
|
geblieben wäre.
|
|
|
|
## 6. Offen / Folgetodos
|
|
|
|
- **gitops#61** (`on_conflict`-Härtung) ist gepusht und rollt über Flux; der
|
|
case-insensitive Eindeutigkeits-Check im `matrix-invitation`-Prompt-Stage
|
|
(damit der Nutzer schon bei der Registrierung statt erst beim Login scheitert)
|
|
ist dort als bewusst offener Rest vermerkt.
|
|
- Verwaiste Altlasten bei `@apo` (10 `local_notification_settings` für längst
|
|
gelöschte Geräte, 18 Cross-Signing-Pseudoeinträge) sind **kosmetisch** und
|
|
wurden bewusst **nicht** angefasst — sie haben mit dem Call-Problem nichts zu
|
|
tun, und ein weiterer Eingriff widerspräche der Lehre oben.
|