diff --git a/STATUS.md b/STATUS.md index 493d10c..ec177ad 100644 --- a/STATUS.md +++ b/STATUS.md @@ -72,7 +72,7 @@ Verteilung: M1 12 · M2 17 · M3 4 · M4 11 · M5 15 _none active_ -## ADRs (21) +## ADRs (22) | ADR | Status | Title | |---|---|---| @@ -97,6 +97,7 @@ _none active_ | [0019](docs/adr/0019-komponenten-issues-adoptiert.md) | accepted | ADR-0019: Komponenten-Issues in docs/issues/ adoptiert — eine Nummernwelt für die Gruppe | | [0020](docs/adr/0020-bekannte-befunde-quittieren.md) | accepted | ADR-0020: Bekannte Befunde werden quittiert, damit Rot wieder etwas bedeutet | | [0021](docs/adr/0021-foederation-geschlossen.md) | accepted | ADR-0021: Föderation wird geschlossen — leere Whitelist statt offener Tür | +| [0022](docs/adr/0022-upstream-anschluss-durch-einmaligen-merge.md) | accepted | ADR-0022: Anschluss an Upstream durch einen einmaligen Merge, nicht durch einen geteilten Graft | ## Open AARs (0) diff --git a/docs/adr/0022-upstream-anschluss-durch-einmaligen-merge.md b/docs/adr/0022-upstream-anschluss-durch-einmaligen-merge.md new file mode 100644 index 0000000..0140ea7 --- /dev/null +++ b/docs/adr/0022-upstream-anschluss-durch-einmaligen-merge.md @@ -0,0 +1,75 @@ +--- +type: adr +id: "0022" +status: accepted +date: 2026-08-19 +supersedes: null +superseded_by: null +related: + - "docs/issues/0099-threadnet-web-12-upstream-sicherheitsfixes-lassen-sich-nicht-m.md" +--- + +# ADR-0022: Anschluss an Upstream durch einen einmaligen Merge, nicht durch einen geteilten Graft + +## Kontext + +`ThreadNet-Web` enthält keine Upstream-Historie: Am 2026-05-10 kam ein kompletter +Element-Web-Baum in einem Commit herein. Ohne gemeinsamen Vorfahren ist +`git merge upstream/develop` unmöglich, und jedes Update bedeutet, zwölf eigene Patches +von Hand auf einen neuen Baum aufzutragen. Das ist nicht nur mühsam, sondern gefährlich: +Verschiebt Element eine Datei, verschwinden unsere Zeilen **ohne Konflikt** (#0099). + +Am 2026-08-19 wurde der tatsächliche Ursprung gemessen statt geraten: **`deadd548` +vom 2026-05-08** (nicht der Tag `v1.12.17`, wie zuvor angenommen). Der Beleg ist die +Baumdistanz — 43 abweichende Dateien, davon 31 reine Modus-Änderungen und der Rest +unser eigenes Feature. + +Im Wegwerf-Klon getestet: Mit gesetztem Vorfahren läuft ein Merge von drei Monaten +`develop` durch und erzeugt **32 konfliktbehaftete Dateien, davon nur vier Quellcode** — +genau unsere Patches. + +## Optionen + +**A: Geteilter Replace-Ref.** `git replace --graft` und `refs/replace/*` mitliefern. +Die Historie bleibt formal unverändert, Git *interpretiert* sie nur anders. Nachteil: +Jeder Klon braucht einen zusätzlichen Fetch, und wer ihn vergisst, sieht eine andere +Historie als alle anderen — ein stiller Unterschied, der sich erst im Konfliktfall +zeigt. + +**B: Einmaliger echter Merge**, danach normale Merges. + +⚠️ **Praezisierung nach dem Test:** `--allow-unrelated-histories` allein liefert +einen ZWEI-Wege-Vergleich und damit 1757 Konflikte — gemessen. Der Graft ist kein +Gegenentwurf zu B, sondern sein Werkzeug: lokal setzen, den Merge damit rechnen +lassen (32 Konflikte), committen. Der Merge-Commit traegt danach die echten Eltern, +der Graft kann weg, und die Abstammung laeuft ueber den Merge-Commit selbst. +Die Nahtstelle wird ein sichtbarer Merge-Commit. Kein Sonderwissen, kein Zusatzschritt, +kein Klon kann sie versehentlich übersehen. + +**C: So weiterarbeiten wie bisher** — Patches von Hand auftragen. Verworfen: Das ist der +Zustand, der die stille Klasse überhaupt erst erzeugt. + +## Entscheidung + +**Option B** (sorb, 2026-08-19). + +Ausschlaggebend ist nicht der Aufwand — beide Wege sind ähnlich billig — sondern die +Sichtbarkeit. A funktioniert nur, solange alle daran denken; B trägt sich selbst. Für +ein Repo, dessen Kernproblem „Git meldet nichts" ist, wäre ein Mechanismus, der +stillschweigend unterschiedlich wirkt, die falsche Wahl. + +`deadd548` bleibt trotzdem wichtig: Es ist der Stand, gegen den der Merge gefahren wird, +und ohne diese Messung wäre der Merge auf eine erfundene Grundlage gelaufen. + +## Konsequenzen + +- Der erste Merge ist ein einmaliger Kraftakt mit vier Quellcode-Konflikten; danach ist + ein Upstream-Update ein gewöhnlicher Merge. +- **Die stille Klasse verschwindet**: Verschiebt Upstream eine Datei, die wir angefasst + haben, meldet Git künftig einen Konflikt, statt unsere Zeilen wortlos fallen zu lassen. +- Die Nahtstelle bleibt als Merge-Commit dauerhaft sichtbar — gewollt, nicht geduldet. +- **Abnahme ist kein Build, sondern ein Funktionstest**: Die ClamAV-Patches liegen in der + Medien-Pipeline. Ohne den Test aus #0099 (verschlüsselte Datei senden, abgelehnte + empfangen) ist der Merge nicht abgenommen. +- Schritt 4 aus #0099 — ein Verfahren zum Auftragen der Patches — wird damit + gegenstandslos. diff --git a/docs/issues/0099-threadnet-web-12-upstream-sicherheitsfixes-lassen-sich-nicht-m.md b/docs/issues/0099-threadnet-web-12-upstream-sicherheitsfixes-lassen-sich-nicht-m.md index 29d4d80..a31d19d 100644 --- a/docs/issues/0099-threadnet-web-12-upstream-sicherheitsfixes-lassen-sich-nicht-m.md +++ b/docs/issues/0099-threadnet-web-12-upstream-sicherheitsfixes-lassen-sich-nicht-m.md @@ -229,3 +229,69 @@ Merge-Commit mit `--allow-unrelated-histories` bauen und ab dann normal weiterme Beides ändert die Historie-Wahrnehmung des Repos dauerhaft und ist damit **ADR-pflichtig**. Entscheidung sorb steht aus; Schritt 4 (Auftragsverfahren für die Patches) wird bei Weg 1 oder 2 weitgehend gegenstandslos. + +## Weg B belegt 2026-08-19 — mit einer wichtigen Präzisierung + +Entscheidung sorb: **Weg B** ([ADR-0022](../adr/0022-upstream-anschluss-durch-einmaligen-merge.md)). + +### `--allow-unrelated-histories` allein genügt NICHT + +Gemessen gegen `v1.12.26`, im selben Klon, nacheinander: + +| Vorgehen | Konflikte | +|---|---| +| nur `--allow-unrelated-histories`, ohne Vorfahren | **1757** | +| mit lokal gesetztem Graft auf `deadd548` | **32** | + +Ohne gemeinsamen Vorfahren macht Git einen Zwei-Wege-Vergleich — das ist die „praktisch +jede Datei konfliktet"-Lage aus der Fork-Doku. **Der Graft ist also kein Gegenentwurf zu +Weg B, sondern sein Werkzeug:** lokal setzen, den Merge damit rechnen lassen, committen — +der Merge-Commit trägt danach die echten Eltern, und der Graft kann weg. Ab dann läuft +die Abstammung über den Merge-Commit selbst. Das steht so nicht in ADR-0022s +Optionsbeschreibung und ist hier nachgetragen. + +⚠️ **Stolperstein auf dem Weg dahin:** Die mit `--depth=1` geholten Tags tragen eine +`.git/shallow`-Grenze. `v1.12.26` war dadurch auf **einen** Commit abgemauert, obwohl +derselbe Commit über `develop` vollständig vorlag — jeder Merge-Versuch scheiterte mit +„refusing to merge unrelated histories", was wie ein Grundproblem aussah und keines war. +`git fetch --unshallow upstream` löst es. + +### Die 32 Konflikte, vollständig aufgeschlüsselt + +| Menge | Was | Auflösung | +|---|---|---| +| 24 | `.github/workflows/*` | unsere Fassung behalten — eigene CI-Strecke | +| 1 | `pnpm-lock.yaml` | regenerieren | +| 1 | `apps/web/package.json` | **Produktentscheidung, siehe unten** | +| 6 | Quellcode, je 1–2 Konfliktblöcke | von Hand | + +**Der Fund, der die ganze Übung rechtfertigt:** Upstream hat +`RoomListItemAccessibilityWrapper` in `RoomListItemWrapper` **umbenannt**. Weil es jetzt +einen echten Vorfahren gibt, **meldet Git den Konflikt** — genau der Fall, den dieses +Issue als stille Gefahr beschreibt („unsere Zeilen sind schlicht weg, und Git meldet +nichts"). + +### Warum ich hier gestoppt habe + +`apps/web/package.json` enthält zwei Zeilen, die keine Konfliktauflösung sind, sondern +Entscheidungen: + +``` +ours: "@sorb/threadnet-call-embedded": "0.19.2-threadnet.12" +upstream: "@element-hq/element-call-embedded": "0.22.0" + +ours: "matrix-js-sdk": "github:matrix-org/matrix-js-sdk#d19cb751..." +upstream: "matrix-js-sdk": "42.2.0" +``` + +Die erste falsch aufgelöst, und die **gesamte KI-Geräuschunterdrückung (#0054) ist +stillschweigend weg**. Die zweite betrifft den Git-Ref-Pin, der seinerzeit ein Build-Fix +war (Abschnitt 3 der Fork-Doku) — ob Upstreams 42.2.0 ihn erübrigt, zeigt nur ein Build. + +Beides ist ohne Build und ohne den ClamAV-Funktionstest nicht absicherbar. Der Merge ist +damit **vorbereitet und vermessen, aber nicht ausgeführt**; das Experiment wurde +abgeräumt (kein Zweig, kein Replace-Ref, Arbeitsverzeichnis sauber). Die Upstream-Historie +bleibt im Klon liegen, damit der nächste Anlauf nicht wieder 600 MB holen muss. + +**Nächster Schritt:** den Merge als eigenes Vorhaben fahren, mit Build und +ClamAV-Abnahme als Voraussetzung — nicht als Nebenschritt.