117 lines
11 KiB
Markdown
117 lines
11 KiB
Markdown
# Agent-Checkliste — vor Commit / Push / Merge
|
|
|
|
> **Operative Ergänzung zu [`AGENTS.md`](../AGENTS.md).** AGENTS.md hat die Regeln/DoD/Scope —
|
|
> **hier** steht das praktische „bevor du pushst, mach es lokal grün" + die Footguns aus echten Vorfällen.
|
|
> Die DoD-/Scope-/Ticket-Regeln aus AGENTS.md gelten zusätzlich.
|
|
|
|
## 0. Jede mutierende Session isoliert starten
|
|
|
|
Aus einem vorhandenen Clone:
|
|
|
|
```bash
|
|
pnpm session:start -- <type>/<kurzer-slug>
|
|
cd <ausgegebener-worktree>
|
|
```
|
|
|
|
Der Befehl erstellt Branch und Geschwister-Worktree immer neu vom aktuellen `origin/main`, hydriert
|
|
`.env` atomar über den kanonischen SOPS-Age-Key und führt `pnpm install --frozen-lockfile` aus. Bereits
|
|
vorhandene lokale oder Remote-Branches und vorhandene Zielverzeichnisse werden verweigert.
|
|
|
|
- Nicht im dirty Haupt-Workspace arbeiten.
|
|
- Einen Session-Branch nicht für ein neues Ticket oder einen Folge-Fix wiederverwenden.
|
|
- Rein lesende Diagnose ist ausgenommen; vor der ersten Dateiänderung muss ein Session-Worktree stehen.
|
|
- Scheitert SOPS oder die Installation, muss der Start ohne leere `.env` und ohne halben Worktree
|
|
zurückrollen.
|
|
|
|
## 0.5 Atomare Checkpoints während der Umsetzung
|
|
|
|
Nicht bis zum Ende des Auftrags mit dem Committen warten. Nach jeder abgeschlossenen, separat
|
|
revertierbaren Änderung:
|
|
|
|
1. `git status --short` prüfen und nur die Dateien des aktuellen fachlichen Checkpoints stagen.
|
|
2. `git diff --cached --name-only` und `git diff --cached --stat` lesen.
|
|
3. Bei mindestens 25 Dateien oder 800 geänderten Zeilen ohne reine Generierung, Migration oder
|
|
Massendeletion den Commit vor dem Fortfahren fachlich aufteilen.
|
|
4. `git diff --cached --check`, fokussierte Tests und den Typecheck der betroffenen Pakete ausführen.
|
|
5. Den Checkpoint sofort committen, bevor ein unabhängiger Bug, Refactor, Tooling-/Test-Fix oder der nächste
|
|
Plan-/DoD-Punkt begonnen wird.
|
|
|
|
Tests, Typen, Übersetzungen, Redirects und generierte Artefakte bleiben bei der Änderung, die sie
|
|
erforderlich macht. Änderungen eines anderen Checkpoints bleiben unstaged. `git add -A` ist nur zulässig,
|
|
wenn `git status --short` nachweislich genau einen Checkpoint enthält.
|
|
|
|
## 1. Vor JEDEM Push: lokal grün machen
|
|
|
|
CI läuft auf node1 mit begrenzten Slots (~7 Min/Lauf). Fang Fehler **lokal** ab, nicht im CI.
|
|
|
|
```bash
|
|
pnpm typecheck # tsc (@hivegrid/web). Andere Pakete: pnpm --filter <pkg> typecheck
|
|
pnpm lint # eslint --max-warnings=0 ← WARNINGS FAILEN CI, nicht ignorieren
|
|
pnpm test # Core-Tests; bei breiteren Änderungen die betroffenen Pakete mit-testen
|
|
```
|
|
|
|
**Merksätze:**
|
|
- **`esbuild`/`vitest` grün ≠ typecheck grün.** esbuild transpiliert ohne Typprüfung; `tsc` prüft Typen. Beide laufen lassen.
|
|
- **Lint-Warnings = CI-rot.** `--max-warnings=0` ist hart. Kein `// eslint-disable` ohne Grund (wenn nötig: file-level + begründet).
|
|
- **Coverage-Gate** (falls dein Modul ein Coverage-Target in `scripts/coverage-targets.json` hat): `pnpm run verify:test-coverage` — läuft vom **Repo-Root** (jsdom-Config!), siehe Footgun §3.
|
|
|
|
## 2. Passende `verify:*`-Checks vor Push
|
|
|
|
Je nach Änderung die relevanten Validatoren laufen — CI bricht sonst:
|
|
|
|
| Geändert | Check(s) |
|
|
|---|---|
|
|
| `.gitea/workflows/*.yml` | `pnpm run verify:gitea-ci-workflow` · `verify:deploy-workflow` |
|
|
| **Neues `packages/<x>`** | `pnpm run verify:docker-baseline` ← **Dockerfile deps-Target braucht `COPY packages/<x>/package.json`** (sonst Deploy rot, §3) |
|
|
| **Neues Prisma-Modell mit `tenantId`** | `TENANT_SCOPED_MODELS` in `packages/cli/src/commands/tenant/models.ts` ergänzen (Eltern vor Cascade-Kindern) + RLS-Policy in `prisma/rls/<modul>-isolation.sql`. Test: `packages/cli/.../tenant/models.test.ts` (§3) |
|
|
| **Neue Default-Permission** | In **alle vier** Registries: `packages/db/.../permissions-seed.server.ts` (Seed + Rollen-Grant) · `apps/web/app/application/dtos/shared/DefaultPermissions.ts` (Enum) · `apps/web/app/components/core/roles/roleDisplay.ts` (Scope- + Action-Map) · `translations.json` unter `models.permission.defaultPermissions.{scopes,actions}` (de **und** en). Tests: `rolesAndPermissionsService.role-matrix` + `roleDisplay` (§3) |
|
|
| **`prisma/schema/**` geändert** | **Beide** Gates, nicht nur das erste: `pnpm run verify:migrations-parity` ← Schema ohne Merge-Migration = CI rot (AD-21-Gate; braucht Docker) · `HIVEGRID_RLS_REQUIRE_MIGRATION_CHAIN_PARITY=1 pnpm run verify:rls-live` ← spielt die Kette als **Nicht-Superuser** durch. Auf dem Branch mit `db push` arbeiten ist ok, aber **vor dem Merge** muss die Migration existieren |
|
|
| **FK auf eine Tabelle mit FORCE RLS** | Der Constraint wird mit einem internen Join über die referenzierte Tabelle validiert, und FORCE gilt auch für den Owner → `ALTER TABLE "<Ziel>" NO FORCE ROW LEVEL SECURITY;` … FK … `FORCE` wieder an (Policies bleiben ENABLED, kein DML im Fenster). **Eine leere referenzierende Tabelle hilft nicht** — die Anweisung wird abgelehnt, bevor eine Zeile gelesen wird. Ein lokaler Replay als Superuser sieht das nicht; nur `verify:rls-live` und die CI-Shadow-DB fangen es |
|
|
| Dockerfile / Runtime | `verify:docker-baseline` · `verify:docker-non-root` |
|
|
| UI-Texte | `pnpm run verify:i18n` (keine hartkodierten Strings) |
|
|
| Allgemein | `verify:ci-baseline` · `verify:source-health` |
|
|
|
|
## 3. Footguns aus echten Vorfällen
|
|
|
|
- **Neues Workspace-Paket → Dockerfile-COPY-Zeile.** Jedes `packages/<x>` braucht `COPY packages/<x>/package.json packages/<x>/package.json` im Dockerfile deps-Target (alphabetisch, vor `pnpm install`). `verify:docker-baseline` prüft das. Vergessen = **Deploy bricht erst NACH dem Merge** im Preflight (2026-06-28: `packages/integrations`, Hotfix PR #8). Der Docker-Build selbst + ci.yml tolerierten es früher — jetzt prüft ci.yml es mit.
|
|
- **Neues `tenantId`-Modell lebt in mehreren Registries.** Modell + RLS-SQL reicht NICHT: `TENANT_SCOPED_MODELS` (Backup/Restore, `packages/cli/.../tenant/models.ts`) muss es kennen, sonst `tenant/models.test.ts` rot. Eltern **vor** Cascade-Kindern listen (Restore-Reihenfolge). (AK-P17b, CI-Fund 2026-06-28)
|
|
- **Default-Permission lebt in 4 Registries.** Nur in den Seed schreiben reicht NICHT (siehe §2): `role-matrix`-Test verlangt den Eintrag im `DefaultPermissions`-Enum, `roleDisplay`-Test verlangt Scope- **und** Action-Mapping in `roleDisplay.ts` **plus** Übersetzungen unter `models.permission.defaultPermissions.{scopes,actions}` (de+en). Bei mehrstufigem Scope **flache** Keys (`hr.leave` → `hrLeave`), sonst Pfad-Kollision mit dem `hr`-String-Leaf. (AK-P17b)
|
|
- **Kein `"…"` (doppelte Anführungszeichen) in Kommentaren im `defaultPermissionSeeds`-Array.** Der `roleDisplay`-Test **regex-extrahiert jedes doppelt-gequotete Literal im Array** als Permission-Namen — ein zitiertes Wort im Kommentar wird zur Phantom-Permission und bricht den Test (`… is not valid JSON`). Im Kommentar einfache Anführungszeichen / Backticks nutzen. (AK-P17b)
|
|
- **Coverage-Gate läuft vom Repo-Root (jsdom).** Tests, die Node-Kontext brauchen (`fs`, `process`), mit `// @vitest-environment node` pinnen. **Kein `process.chdir`** in parallelen Tests (race). `vi.mock` **leakt** zwischen Files in shared Workers → Mocks pro File isolieren / `vi.restoreAllMocks`.
|
|
- **RLS ist lokal AUS und in Staging/Prod AN.** Ein grüner lokaler Lauf beweist **nichts** über RLS. Greifst du in einer Route/einem Service direkt auf `db.<model>` zu, binde den Kontext (`runWithRlsContext` / `withTenantRLS`) — sonst liefert die Query dort **null Zeilen**, ohne Fehler und ohne Log (2026-07-14: eine neue Route hätte in Prod jedes Profilbild als 404 ausgeliefert). Db-Mocks, die auf jede Query antworten, verstecken genau das. Details: `AGENTS.md` §Row-Level-Security.
|
|
- **Kein Laufzeit-Flag mit `SEED_`-Präfix.** Der Deploy-Vertrag (`assert-runtime-db-env`) weist jeden `SEED_*`-Schlüssel auf Runtime-Ressourcen ab. Ein Feature-Schalter, der zufällig nach Seed klingt, wird beim Deploy stillschweigend entfernt — genau daran sind die Staging-Demo-Logins gestorben (2026-07-14).
|
|
- **`.server.ts`-Re-Export ist verboten** (RR7-Client-Build bricht). Stattdessen Component-Extraktion.
|
|
- **pre-push-Hook blockt?** Erst die Checks **manuell** laufen + Ursache fixen — nicht blind `git push --no-verify`. `--no-verify` nur, wenn der Hook-Fehler nachweislich irrelevant ist (z.B. Hook-Timeout, kein echter Lint-/Typ-Fehler).
|
|
|
|
## 4. Branch / PR / Merge
|
|
|
|
- **Gitea-Identität fail-closed prüfen:** `git config --local hivegrid.giteaUser` muss den persönlichen
|
|
Dev-Login dieses Clones enthalten. Die effektive Git-/API-Credential muss vor jedem Push und jedem
|
|
Gitea-Write via `GET /api/v1/user` exakt diesen Login + `active=true` ergeben. `gitea-admin`, `Sudo`
|
|
und andere Impersonation sind für Routinearbeit verboten. Nur CI-/Deploy-Bots sind als explizite
|
|
Servicekonto-Ausnahme zulässig.
|
|
- **Nie direkt auf `main` pushen** → Branch + PR + normaler Merge-Commit. **Squash ist verboten.**
|
|
- **Commit-Historie erhalten:** Vor dem Merge erwartete PR-Head-SHA prüfen und Gitea ausschließlich mit
|
|
der normalen Merge-Strategie (`Do=merge`, nie `Do=squash`) aufrufen. Nach dem Merge muss
|
|
`git merge-base --is-ancestor <feature-head> origin/main` erfolgreich sein; die einzelnen
|
|
Feature-Commits behalten ihre ursprünglichen SHAs.
|
|
- **Versehentlichen Squash append-only reparieren:** Geteiltes `main` niemals umschreiben oder
|
|
force-pushen. Stattdessen einen bytegleichen History-Repair-PR erstellen, der den ursprünglichen
|
|
Feature-Head per normalem Merge-Commit anbindet, CI vollständig abwarten und die erhaltene Ancestry
|
|
nachweisen.
|
|
- **Session nach normalem Merge aufräumen:** Sobald der PR per normalem Merge-Commit in `main` liegt:
|
|
`pnpm session:finish -- <branch>`. Der Helfer prüft dirty State, aktuelle Main-Ancestry, den
|
|
Merge-Commit, identische lokale/Remote-Heads, geschlossene PRs und persönliche Gitea-Identität. Erst
|
|
danach löscht er Remote-Branch, Worktree und lokalen Branch. Bei Squash, Fast-Forward, offenem PR,
|
|
weitergelaufenem Branch oder lokalen Änderungen stoppt er. Nicht durch `rm -rf` oder `git branch -D`
|
|
umgehen.
|
|
- **Parallel-Schema (AD-21):** Modul = eigene `prisma/schema/<modul>.prisma`; am Branch `prisma db push`, **Migration erst beim Merge** (forward-only + Inverse-SQL als Kommentar, aus dem Nichts reproduzierbar — `DO $$ … IF [NOT] EXISTS … $$`-Guards).
|
|
- **Deploy-Path-Filter:** test-/doc-/workflow-only-Merges (`**/*.test.*`, `docs/**`, `.planning/**`, `.gitea/workflows/**`, `*.md`) skippen den Staging-Deploy automatisch. Code-Änderungen triggern ihn.
|
|
- **Abhängige nicht brechen:** bei Contract-/`core.prisma`-/Querschnitt-Änderungen `blocked-by` UND `blocks` lesen, Konsumenten nachziehen, Auswirkung dokumentieren.
|
|
|
|
## 5. Secrets & Ticket-Abschluss
|
|
|
|
- **Secrets** nie ins Repo/Chat/CI-Log. Per-User-Token in `~/.cli-tokens/` (chmod 600); geteilte Dev-`.env` via `pnpm env:pull` (SOPS).
|
|
- **Strikt im Ticket-Scope.** Verbesserungen nur als **„💡 Vorschlag (außerhalb Ticket-Scope)"** ausweisen, nie still einbauen. Fortschritt als **% der DoD** melden; Done erst bei 100 %.
|
|
- **Abschluss-Reihenfolge:** Umsetzungs-Notiz (Datum + Proof) in der Ticket-Doc → Plane-Kommentar (1. Person, kein AI-Sprech, keine Em-Dashes) → Ticket auf Done.
|