Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018N9CD3ebPKm1b32bPpBknY
13 KiB
phase, verified, status, score, covered_files, covered_digest, behavior_unverified, overrides_applied
| phase | verified | status | score | covered_files | covered_digest | behavior_unverified | overrides_applied | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| quick-260914-ku1 | 2026-09-14T13:59:19Z | passed | 8/8 must-haves verified |
|
v1:sha256:3cc012949ab9484c9c9821c7dea15392439adc9224bd2f9e3025991c0eba6062 | 0 | 0 |
Quick-Task 260914-ku1: Zwei Auslieferungskanaele (Beta/Live) — Verifikationsbericht
Ziel: Zwei Auslieferungskanaele (main -> beta+latest; Tag v* -> live+vX.Y.Z; Zweig live ohne Tag nur geprueft), Versionsstempel per Build-Args in beide Container-Abbilder, GET /health/version, Versionsabzeichen in der Seitenleiste, IMAGE_TAG in docker-compose.prod.yml, Publish-Skript mit --print-plan, Betriebshandbuch Kapitel „Zwei Kanaele" inkl. Hotfix-Rezept und Live-Server-Einrichtung, ci-cd-setup.md aktualisiert, gepusht, echter CI-Lauf gruen.
Verifiziert: 2026-09-14T13:59:19Z Status: passed Re-Verifikation: Nein — Erstverifikation
Alle Pruefungen wurden selbst erneut ausgefuehrt (nicht aus dem SUMMARY uebernommen). Wo die eigene Messung von der SUMMARY-Behauptung abweicht, ist das unten vermerkt — es gab keine Abweichung.
Pruefung 1 — Commits, Diff-Umfang, unangetastete Dateien
| Befehl | Erwartet | Gemessen |
|---|---|---|
git log --oneline 1cd4212..HEAD |
3 Commits | ea6aa99, 9731501, cdb571c — 3 Commits |
git diff --stat 6c19451 -- . ':!.planning' (letzte Zeile) |
20 files changed |
20 files changed, 851 insertions(+), 49 deletions(-) |
git diff --name-only 6c19451 -- '.env*' apps/api/prisma/schema.prisma apps/api/prisma/migrations package.json pnpm-lock.yaml biome.json apps/web/src/components/layout/sidebar-footer.tsx |
leer | leer (keine Ausgabe) |
git status --porcelain (vor jeder Aenderung durch die Verifikation) |
nur die zwei erwarteten offenen Dateien | M .planning/STATE.md, ?? .../260914-ku1-SUMMARY.md — beides die dem Orchestrator gehoerenden, unberuehrt gelassenen Dateien |
git fetch -q && git status -sb | head -1 |
kein [ahead |
## main...origin/main |
Status: ✓ VERIFIED
Pruefung 2 — Testsuiten und Typpruefung
| Befehl | Erwartet | Gemessen |
|---|---|---|
cd apps/api && npx vitest run |
65 Dateien / 1060 Tests | Test Files 65 passed (65) / Tests 1060 passed (1060) |
cd apps/web && npx vitest run |
40 Dateien / 243 Tests | Test Files 40 passed (40) / Tests 243 passed (243) |
pnpm -C packages/shared exec tsc --noEmit |
Exit 0 | Exit 0 |
pnpm -C apps/api exec tsc --noEmit |
Exit 0 | Exit 0 |
pnpm -C apps/web exec tsc --noEmit |
Exit 0 | Exit 0 |
Status: ✓ VERIFIED
Pruefung 3 — Versionsstempel im Code (API und Web)
Quelldateien gelesen (nicht nur gegrept):
apps/api/src/health/health.controller.ts:getVersion()delegiert angetAppVersion()aus./app-version,@Public()und@Get('version')gesetzt, kein Zugriff mehr aufnpm_package_version. Kommentar begruendet T-KU1-03.apps/api/src/health/app-version.ts:getAppVersion()liestprocess.env.APP_VERSION/APP_CHANNEL/APP_COMMIT/APP_BUILD_TIMEmit||-Vorgabendev/dev//,name: 'tessera'.formatAppVersionLine()bautTessera API <version> (<channel>) <commit>, ohne Commit ohne Leerzeichen am Ende.apps/api/src/health/health.controller.spec.ts: 6 Tests wie im Plan beschrieben (check(), Vorgaben, Durchreichen, Compose-Leerstring-Semantik,formatAppVersionLine,@Public()-Metadatenpruefung perReflect.getMetadata). Alle 6 gruen (siehe Pruefung 2).apps/api/src/main.ts:console.log(formatAppVersionLine())direkt nach der bestehenden Port-Zeile (Zeile 35, nach Zeile 34).apps/web/src/lib/app-version.ts:appVersionliestprocess.env.NEXT_PUBLIC_APP_VERSION/_CHANNEL/_COMMITje mit vollem Literalnamen (keine Destrukturierung, keinprocess.env[name]);normalizeChannelfaellt bei unbekanntem Kanal auf'dev'zurueck;loadApiVersion()memoisiert ein Modul-Promise gegen${API_URL}/health/versionmitcredentials: 'include', still bei Fehler (.catch(() => null)).apps/web/src/components/layout/app-version-badge.tsx:data-testid="app-version", Text${appVersion.version} · ${t('channel.'+channel)},titleausCommit <commit>undAPI <version> (<channel>),undefinedwenn beides fehlt.apps/web/src/components/layout/sidebar.tsx: Badge-Block liegt NACH dem Einklapp-Block (derhidden md:blocktraegt) und OHNE dieses Attribut — dadurch auch in der mobilen Schublade sichtbar;!isCollapsedblendet ihn eingeklappt aus (Zeilen ~201-206).apps/web/src/messages/de.json/en.json:sidebar.channel = { beta: "Beta", live: "Live", dev: "Entwicklung"/"Development" }— in beiden Dateien vorhanden, per Node geprueft.sidebar.test.tsx: Modul-Mock fuerAppVersionBadgeund ein sechster Testrenders the version badge below the navigation, derscreen.getByTestId('app-version-badge')prueft.
Status: ✓ VERIFIED
Pruefung 4 — Dockerfile-Falsifizierung (unabhaengig wiederholt)
Beide Dockerfiles gelesen: globales ARG APP_VERSION=dev (und die drei weiteren) vor dem ersten FROM; im Web-builder ARG-Wiederholung + ENV NEXT_PUBLIC_APP_* unmittelbar VOR RUN pnpm --filter=@tessera/web build; im runner beider Images ARG-Wiederholung + ENV APP_VERSION=... nach ENV NODE_ENV=production.
Eigener Bau (nicht aus dem SUMMARY uebernommen):
docker build -f apps/api/Dockerfile --build-arg APP_VERSION=v7.7.7-verify --build-arg APP_CHANNEL=live -t tessera-api-verify:tmp .
docker run --rm --entrypoint node tessera-api-verify:tmp -e 'console.log(process.env.APP_VERSION, process.env.APP_CHANNEL)'
-> v7.7.7-verify live
Erwartung erfuellt. Danach docker rmi tessera-api-verify:tmp ausgefuehrt — kein Rueckstand (docker images | grep -c tessera-api-verify -> 0).
Status: ✓ VERIFIED
Pruefung 5 — CI-Workflow-Struktur und Publish-Skript
.gitea/workflows/ci.yml per js-yaml geparst:
branches=["main","live"] tags=["v*"] jobs=quality,test,publish fetchDepth=0 script=true needs=test
.gitea/scripts/publish-images.sh --print-plan in drei Lagen (eigene Ausfuehrung):
| GITHUB_REF | Ergebnis |
|---|---|
refs/heads/main |
Kanal beta, Push-Zeilen fuer web:beta, web:latest, api:beta, api:latest (main-Fall enthaelt BEIDE, beta und latest) |
refs/heads/live |
„Kein Veroeffentlichungs-Anlass ... nichts zu tun." — keine push-Zeile |
refs/tags/v1.0.0 |
Kanal live, Push-Zeilen fuer web:live, web:v1.0.0, api:live, api:v1.0.0 |
Status: ✓ VERIFIED
Pruefung 6 — CI-gebaute Abbilder und echter Gitea-Lauf
docker images | grep tessera-ctl zeigt localhost:3002/schalli/tessera-ctl/{api,web}:{beta,latest} (zusaetzlich git.vicolab.de/... als Fetch-Alias und lokale tessera-ctl-{api,web}:latest aus fruehreren lokalen Bauten — nicht Teil dieser Pruefung).
docker run --rm --entrypoint node localhost:3002/schalli/tessera-ctl/api:beta -e 'console.log(process.env.APP_VERSION, process.env.APP_CHANNEL, process.env.APP_COMMIT)'
-> ea6aa99 beta ea6aa99
docker run --rm --entrypoint sh localhost:3002/schalli/tessera-ctl/web:beta -c 'grep -rl "ea6aa99" apps/web/.next/static | wc -l'
-> 1
ea6aa99 ist der zuletzt gepushte Commit (siehe Pruefung 1) — Uebereinstimmung.
Gitea-API (GET /api/v1/repos/schalli/tessera-ctl/actions/runs?limit=5, Token aus git remote get-url --push origin, nicht ausgegeben):
297 ea6aa995b27de1dfa9b557c06df9fa3bbcdd8ea3 completed success push
296 6c19451be9a25feb227af075076a839a968c5366 completed success push
...
Lauf 297 entspricht head_sha = ea6aa99..., status: completed, conclusion: success — deckt sich mit der SUMMARY-Angabe.
Status: ✓ VERIFIED
Pruefung 7 — docker-compose.prod.yml / IMAGE_TAG
docker compose -f docker-compose.prod.yml config --images
-> git.vicolab.de/schalli/tessera-ctl/web:beta, .../api:beta, postgres:16-alpine
IMAGE_TAG=live docker compose -f docker-compose.prod.yml config --images
-> .../api:live, postgres:16-alpine, .../web:live
Ohne Variable Vorgabe beta, mit IMAGE_TAG=live live fuer beide Images. Kein :latest mehr in der Datei (per grep unabhaengig bestaetigt: 0 Treffer).
Status: ✓ VERIFIED
Pruefung 8 — Betriebshandbuch und ci-cd-setup.md
docs/anleitung-betrieb.md, Abschnitt ## 9. Zwei Kanäle: Live und Beta (Zeile 355) gelesen (nicht nur gegreppt): erklaert den Kanalbegriff, die eine .env-Zeile je Server (IMAGE_TAG=beta/IMAGE_TAG=live), die Server-Compose-Anpassung, pull + up -d --force-recreate, das Freigabe-Rezept, den vollstaendigen Hotfix-Ablauf mit der fett gesetzten Regel „Keine Datenbankänderung als Hotfix" samt Alltagssprache-Begruendung (Migrations-Zeitstempel-Reihenfolge), die drei Erkennungswege (Oberflaeche/curl/Log) und die Einrichtung des neuen Live-Servers (eigene Secrets, eigene leere Datenbank, APP_URL, Reihenfolge Erstfreigabe vor erstem Pull). Echte Umlaute durchgaengig (Zwei Kanäle, änderungen, möglicherweise, größeren etc.) — Ton der Datei gehalten, keine ASCII-Umschrift in diesem Kapitel.
docs/ci-cd-setup.md: Abschnitt „Gitea Secrets" beschreibt REGISTRY_TOKEN und den Login (kein „keine Secrets" mehr); Abschnitt „Pipeline-Ueberblick" beschreibt Trigger (main/live/Tags v*), Etiketten-Tabelle, Build-Args-Tabelle, laengere Web-Bauzeit und markiert D-13 als ueberholt. grep -c "Kein Registry-Push\|build-deploy" -> 0.
| Grep | Erwartet | Gemessen |
|---|---|---|
^## 9\. Zwei Kanäle: Live und Beta in anleitung-betrieb.md |
1 | 1 |
IMAGE_TAG in anleitung-betrieb.md |
>= 6 | 11 |
Keine Datenbankänderung als Hotfix |
1 | 1 |
Kein Registry-Push|build-deploy in ci-cd-setup.md |
0 | 0 |
[äöüÄÖÜß] in ci-cd-setup.md (ASCII-Konvention) |
0 | 0 |
Status: ✓ VERIFIED
Anti-Pattern-Scan
Alle 13 durch die Fingerprint-Liste erfassten Code-/Config-Dateien auf TBD, FIXME, XXX, TODO, HACK, PLACEHOLDER, „not yet implemented" u. ae. geprueft — keine Treffer in einer der geaenderten Dateien.
Requirements-Abdeckung
QUICK-260914-KU1 ist eine Quick-Task-Anforderung ohne eigenen Eintrag in .planning/REQUIREMENTS.md (projektueblich fuer /gsd-quick-Auftraege, kein Roadmap-Phasenbezug) — kein verwaistes Requirement, da REQUIREMENTS.md keinen Phasen-Bezug fuer diesen Quick-Task erwartet.
Beobachtete Nebenpunkte (keine Gaps)
- Zusaetzliche lokale Docker-Images (
git.vicolab.de/...:latest,tessera-ctl-api:latest,tessera-ctl-web:latest) liegen auf dem Host aus fruehreren Bauten/Pulls — nicht Teil dieses Plans und nicht durch ihn verursacht. sidebar-footer.tsxbleibt wie geplant unangetastet (toter Code, im SUMMARY als Nebenbefund vermerkt)..env.prod.examplebewusst ohneIMAGE_TAG-Zeile (Regel: keine.env*-Aenderungen) — im Handbuch als offener Punkt vermerkt.
Angenommene Risiken
- T-KU1-03 (
GET /health/versionbleibt@Public(), gibt Version/Kanal/Commit/Bauzeit ohne Anmeldung preis): als "accept" im Threat-Register des Plans geflaggt, durch Spec-Test 6 gepinnt. Bei externem Verkauf von Tessera muesste das revidiert werden (im Plan bereits als Folgeaenderung genannt). Die Verifikation bestaetigt nur, dass die Entscheidung wie dokumentiert umgesetzt und getestet ist — keine eigene Bewertung des Risikos selbst. - T-KU1-04 (Tag-Push
v*als alleiniger Freigabe-Hebel, kein Tag-/Branch-Schutz in Gitea): als "accept" geflaggt, weil aktuell nur ein Konto Schreibrecht hat. Diese Verifikation hat KEINE Gitea-Repository-Einstellungen aendern koennen/muessen (ausserhalb der Erlaubnisliste) und bestaetigt nur, dass die Empfehlung im Handbuch/ci-cd-setup steht. live-Zweig und Tagv1.0.0sind bewusst nicht angelegt — laut Plan Folgearbeit nach dem noch ausstehenden „Fehler-melden-Knopf"-Quick-Task. Das bedeutet: der Live-Kanal ist bislang nur durch die drei--print-plan-Simulationen und den lokalen Docker-Falsifizierungslauf bewiesen, NICHT durch einen echten CI-Lauf mitrefs/tags/v*(der echte CI-Lauf in Pruefung 6 deckt nur den Beta-Pfad ab). Das ist im Rahmen des Plans ausdruecklich so vorgesehen (Output-Abschnitt: "Zweig live und Tag v1.0.0 werden NICHT in diesem Plan angelegt") und daher kein Gap, aber ein offener Punkt fuer die naechste Freigabe.- Zusaetzliche, vom Runner gebaute lokale Images auf dem Host (
git.vicolab.de/...:latestetc.) wurden nicht aufgeraeumt — sie stammen nicht aus dieser Verifikation und wurden nicht entfernt, um den Host-Zustand nicht ueber das Mandat hinaus zu veraendern.
Verifiziert: 2026-09-14T13:59:19Z Verifier: Claude (gsd-verifier)