docs(spec): per-list base branch and fetch before unit branch
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Unit-Branch + Draft-PR — Design
|
||||
|
||||
**Datum:** 2026-10-01 · **Status:** Entwurf, Review durch Mika ausstehend
|
||||
**Datum:** 2026-10-01 · **Status:** abgenommen (mit Basis-Branch pro Liste + Fetch)
|
||||
**Diagramme:** Obsidian `07 - Plattform & Technik/ClaudeDo/ClaudeDo - Branch und PR Ablauf.md`
|
||||
**Ersetzt:** die offene Entscheidung aus `2026-08-06-planning-chain-fork-base-design.md`
|
||||
|
||||
@@ -33,6 +33,8 @@ Vorgängers.
|
||||
| PR-Automatik | Kein Auto-PR bei einem Statuswechsel. Automatisiert wird über den Merge-Helper, dessen `approve` dann den PR erzeugt. |
|
||||
| ADO-Zugang | Eigener PAT (Scope Code Read & Write). Er wird per `DpapiTokenStore` in `~/.claudeDo/azdo.pat` gespeichert, ohne Abhängigkeit auf das work-conventions-Plugin. |
|
||||
| dependsOn über Units | Wartet bewusst auf den echten Merge. Abhängige Arbeit gehört in eine Unit mit einem PR. |
|
||||
| Basis-Branch | Pro Liste einstellbar (`list_config.base_branch`, z.B. `dev` für die LagerApp). Leer heißt: privat der gerade ausgecheckte Branch des Main-Checkouts (wie heute), Firma der Default-Branch des ADO-Repos. Gilt als Basis des Unit-Branches, als PR-Ziel und als Vorauswahl des privaten Merge-Ziels. |
|
||||
| Basis aktualisieren | Firmen-Repo: `git fetch origin <basis>`, bevor der Unit-Branch angelegt wird. Der Unit-Branch startet von `origin/<basis>`, der lokale Basis-Branch wird best-effort per fast-forward nachgezogen. |
|
||||
|
||||
## 1. Branch-Naming (`WorktreeManager`)
|
||||
|
||||
@@ -69,6 +71,37 @@ Vorgängers.
|
||||
**Basis eines Childs** (`ResolveBaseCommitAsync`): Das ist immer der aktuelle Head des
|
||||
Unit-Branches (`rev-parse <unitBranch>`). Der Sonderfall „nur bei `PlanningPhase.None`“ fällt weg.
|
||||
|
||||
**Basis eines Unit-Roots** (Einzeltask, Parent):
|
||||
- **Privat:** `list_config.base_branch`, sonst der ausgecheckte Branch des Main-Checkouts. Heute
|
||||
ist es `RevParseHeadAsync`. Ist `base_branch` gesetzt, wird es `rev-parse <base_branch>`, auch
|
||||
wenn gerade ein anderer Branch ausgecheckt ist.
|
||||
- **Firma:**
|
||||
- Zuerst `git fetch origin <basis>`. `<basis>` ist `base_branch`, sonst der Default-Branch des
|
||||
Repos per ADO-API, ersatzweise `git symbolic-ref refs/remotes/origin/HEAD`.
|
||||
- Der Unit-Branch startet von `origin/<basis>`.
|
||||
- Dann wird der lokale `<basis>` best-effort nachgezogen:
|
||||
- nicht ausgecheckt: `git fetch origin <basis>:<basis>` (lehnt einen nicht-fast-forward
|
||||
selbst ab)
|
||||
- ausgecheckt und sauber: `git -C <workingDir> merge --ff-only origin/<basis>`
|
||||
- schmutzig oder divergiert: Warnung ins Log, kein Eingriff in den Checkout
|
||||
- Schlägt der Fetch fehl (offline, keine Credentials), wird gewarnt und es geht mit dem
|
||||
lokalen `<basis>` weiter. Der Task scheitert daran nicht.
|
||||
- Der Fetch nutzt dieselbe PAT-Übergabe wie der Push (Abschnitt 3).
|
||||
- Der Fetch läuft einmal pro Unit-Root, nicht pro Child. Children starten vom Unit-Branch.
|
||||
|
||||
**Spalte `list_config.base_branch`** (nullable string, Migration):
|
||||
- Sie wird im Listeneinstellungs-Modal gepflegt, als Freitext mit Vorschlägen aus
|
||||
`ListLocalBranchesAsync`, und in `get_list_config` mitgeliefert.
|
||||
- ⚠️ `ListRepository.SetConfigAsync` kopiert verbatim (siehe `TicketProjectId`). Jeder Schreiber
|
||||
muss den Wert durchreichen, sonst setzt ihn z.B. `set_list_config` still zurück:
|
||||
`WorkerHub.UpdateListConfig`, `ConfigMcpTools`, alle Stellen, die eine frische
|
||||
`ListConfigEntity` bauen.
|
||||
- `UpdateListConfigDto` braucht ihn tri-state wie `TicketProjectId`, damit ein Aufrufer, der das
|
||||
Feld nicht kennt, es nicht löscht.
|
||||
- **Merge-Ziel privat:** `TaskMergeService.GetTargetsAsync` setzt `DefaultBranch` auf
|
||||
`base_branch`, falls gesetzt. Das leere Ziel (`ApproveAndMergeAsync:1077`, `PreviewAsync:910`)
|
||||
löst ebenfalls auf `base_branch` auf, sonst wie heute.
|
||||
|
||||
**Absorbieren eines Childs:** Neu ist `UnitBranchService.AbsorbChildAsync(childId)`, das in
|
||||
`git -C <parentWorktree> merge --ff-only <childBranch>` mündet.
|
||||
- Die Kette ist seriell (`BlockedByTaskId`), und das Child startet vom Head des Unit-Branches.
|
||||
@@ -119,8 +152,8 @@ einem Folge-Task, sobald keine solchen Units mehr offen sind.
|
||||
- `GET …/pullrequests?searchCriteria.sourceRefName=refs/heads/<branch>&searchCriteria.status=active`.
|
||||
Gibt es schon einen PR, wird er wiederverwendet (idempotent, auch wenn der Skill in der
|
||||
Session schon einen angelegt hat).
|
||||
- Sonst `POST …/pullrequests` mit `isDraft: true` und
|
||||
`targetRefName = <defaultBranch des Repos>` (`GET …/repositories/<repo>`).
|
||||
- Sonst `POST …/pullrequests` mit `isDraft: true` und `targetRefName = <basis>`. Das ist
|
||||
`list_config.base_branch`, sonst `defaultBranch` aus `GET …/repositories/<repo>`.
|
||||
- Die API-Version fällt auf die zurück, die der Server in seiner Fehlermeldung nennt, wie im
|
||||
Skript.
|
||||
4. Die **PR-URL** wird gespeichert, in der neuen nullable Spalte `worktrees.pull_request_url`
|
||||
@@ -181,8 +214,7 @@ Die Prompts in `PromptFiles` (merge und merge_final) bekommen einen Firmen-Repo-
|
||||
PR-API ist ADO-spezifisch.
|
||||
- Aufräumen von Worktree und lokalem Branch, wenn ein Firmen-Task auf `Done` gesetzt wird. Das
|
||||
geht über die bestehende Worktree-Übersicht.
|
||||
- `git fetch` vor dem Anlegen des Unit-Branches. Die Basis ist der lokale `main`-HEAD wie heute,
|
||||
siehe offene Frage.
|
||||
- `git fetch` in privaten Repos. Die Basis bleibt dort lokal.
|
||||
- Eine UI für `company_remote_pattern`.
|
||||
|
||||
## 7. Tests
|
||||
@@ -204,12 +236,14 @@ Keine Tests mit der echten Claude-CLI und keine gegen das echte ADO.
|
||||
- `AzureDevOpsClient` wird gefakt: PR anlegen, vorhandenen PR wiederverwenden, Verify rot
|
||||
heißt kein Push, PR-Fehler nach dem Push.
|
||||
- **Remote-Parsing:** die Fälle aus dem `-SelfTest` des Skripts.
|
||||
- **Basis:**
|
||||
- `base_branch` gesetzt: Der Unit-Root startet davon, auch wenn ein anderer Branch ausgecheckt
|
||||
ist.
|
||||
- Firma: Nach dem Fetch startet der Unit-Root von `origin/<basis>`. Das testet ein Bare-Repo,
|
||||
das einen Commit voraus ist.
|
||||
- Der lokale Basis-Branch wird nachgezogen, ein schmutziger Checkout bleibt unangetastet.
|
||||
- Ein Fetch-Fehler bricht den Task nicht.
|
||||
- `SetConfigAsync`, `set_list_config` und `UpdateListConfig` erhalten `base_branch`.
|
||||
- **Manueller Smoke-Test (Mika):** PAT eintragen, Test-Button. Ein Ticket-Task in einem echten
|
||||
Firmen-Repo bis zum Draft-PR durchspielen, danach eine Planning-Unit mit 2 Children.
|
||||
|
||||
## Offene Frage
|
||||
|
||||
- **Basis im Firmen-Repo:** Der lokale `main` ist in Firmen-Repos oft veraltet. Vorschlag für
|
||||
später: `git fetch origin <default>` und dann `origin/<default>` als Basis des Unit-Branches.
|
||||
In v1 ist das draußen. Wenn es dich jetzt schon stört, ist es ein kleiner Zusatz in
|
||||
`ResolveBaseCommitAsync`.
|
||||
|
||||
Reference in New Issue
Block a user