Files
tessera-ctl/.planning/quick/260917-kgc-desktop-client-update-in-der-app-herunte/260917-kgc-VERIFICATION.md
T
schalli efbd6e8974
Tessera CI/CD / Lint & Type Check (push) Successful in 53s
Tessera CI/CD / Tests (push) Successful in 1m5s
Tessera CI/CD / Desktop-Pakete bauen (push) Successful in 18s
Tessera CI/CD / Build & Publish Images (push) Successful in 4m22s
docs(quick-260917-kgc): Aktenstand — Update in der Desktop-App, alle Nachweise erbracht, Wiedereinstieg bereinigt
Quick 260917-kgc (Plan/Recherche/Bericht/Verifikation) und Schnellfix a6d1a64
in der Quick-Task-Tabelle; Nachweise in allen sechs Berichten nachgetragen
(Playwright lokal, CI-Laeufe 382-384, Windows-Test-VM: In-App-Update
7479cb4 -> a6d1a64). Ueberholte .continue-here-Dateien entfernt,
Desktop-Client-Todo geschlossen.

Dieser Push aendert nichts unter apps/desktop -- er ist zugleich der
Beweisfall 2 des CI-Desktop-Skips (Pakete aus dem Zwischenspeicher).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016g2npLxzH5gZpg8s2S6vKh
2026-09-18 11:29:14 +02:00

15 KiB

phase, verified, status, score, covered_files, covered_digest, behavior_unverified, overrides_applied, behavior_unverified_items, coincidental_reliance_items, human_verification
phase verified status score covered_files covered_digest behavior_unverified overrides_applied behavior_unverified_items coincidental_reliance_items human_verification
quick-260917-kgc 2026-09-17T15:45:00Z human_needed 8/10 must-haves verified
.gitea/scripts/desktop-collect.sh
.gitea/scripts/desktop-stamp.sh
.gitea/workflows/ci.yml
.gitignore
.planning/quick/260917-kgc-desktop-client-update-in-der-app-herunte/260917-kgc-PLAN.md
.planning/quick/260917-kgc-desktop-client-update-in-der-app-herunte/260917-kgc-SUMMARY.md
CHANGELOG.md
apps/api/src/desktop/desktop.controller.ts
apps/api/src/desktop/desktop.service.spec.ts
apps/api/src/desktop/desktop.service.ts
apps/desktop/src-tauri/Cargo.lock
apps/desktop/src-tauri/Cargo.toml
apps/desktop/src-tauri/src/lib.rs
apps/desktop/src-tauri/tauri.conf.json
docs/anleitung-anwender.md
docs/anleitung-betrieb.md
docs/anleitung-entwicklung.md
docs/ci-cd-setup.md
packages/shared/src/index.ts
v1:sha256:dc01a09c0bf779e0c311f942b53240c8ad8a984254ebbc3a3a36b247441cf3cd 2 0
truth test expected why_human
spawn_version_check setzt den Tray-Eintrag und den abgelegten PendingUpdate-Stand zu Beginn jeder Pruefung zurueck (Server-Wechsel darf keinen alten Hinweis stehen lassen) In der laufenden App (oder einem AppHandle-Mock) zweimal hintereinander die Server-Adresse wechseln, waehrend ein Update-Fund im State liegt, und pruefen, dass der Eintrag sofort auf den Standardtext springt und PendingUpdate leer ist, bevor die neue Pruefung antwortet Menuetext == UPDATE_ITEM_DEFAULT, Eintrag gesperrt, PendingUpdate == None unmittelbar nach dem Wechsel Die 33 Unit-Tests decken ausschliesslich die reinen Helfer (is_update_newer, beta_commit, update_endpoint, release_labels, update_labels, parse_server_url, server_host, tray_labels, setup_page_url, with_desktop_marker) ab; spawn_version_check haengt an AppHandle/TrayItems/PendingUpdate-State und wird von keinem Test aufgerufen — Reset-Verhalten ist nur am Laufzeit-Client oder mit einem Tauri-Mock zu beobachten
truth test expected why_human
Tray-Klick 'update' nimmt den abgelegten Stand per take() (verhindert Doppelklick-Downloads), laedt mit Fortschritt im Menuetext, installiert (Windows NSIS passiv / Linux AppImage) und startet neu; bei Fehler springt Menuetext/Stand zurueck und der Browser-Rueckfall oeffnet Am echten (oder in der Windows-VM installierten) Client: Update-Fund abwarten, Tray-Eintrag zweimal schnell hintereinander anklicken, danach den vollen Ablauf bis zum Neustart beobachten; anschliessend denselben Ablauf mit einem absichtlich fehlerhaften Download (z. B. Netz trennen) wiederholen Zweiter Klick loest keinen zweiten Download aus (Eintrag bleibt gesperrt); bei Erfolg Fortschritt 'Laedt ... N %' -> 'Wird installiert...' -> Neustart auf neuem Stand; bei Fehler Menuetext/Stand zurueck, Eintrag wieder aktiv, Benachrichtigung 'Update fehlgeschlagen: ...' und Einstellungsseite im Browser spawn_update_install und der Menue-Zweig 'update' (take()-Semantik, download_and_install, app.restart()) werden von keinem Unit-Test ausgeloest — das ist explizit als offener Orchestrator-Nachweis (Windows-VM) im PLAN/SUMMARY vermerkt und braucht ein vom CI signiertes Paket
test expected why_human
(a) CI-Bau auf main: beide tauri-build-Schritte mit den Secrets TAURI_SIGNING_PRIVATE_KEY/_PASSWORD durchlaufen lassen 'Pakete einsammeln' loggt 'signiert' fuer linux und windows; Manifest im Abbild traegt updateVersion (X.Y.Z-beta.g<sha7>) und je Plattform signature; Job publish gruen; alter Stempel-Cache (ohne die Felder) wird verworfen (Neubau) Nur im Gitea-Runner beweisbar (Secrets, echte tauri-CLI, Cross-Bau-Toolchain) — lokal simuliert per Mini-Fixture-Proben (siehe unten), aber nicht der echte Bau
test expected why_human
(b) Endpunkt gegen alpha.tessera.ctl.de nach dem Pull des neuen Abbilds: curl -si "https://alpha.tessera.ctl.de/api-proxy/desktop/update?target=windows&arch=x86_64&current=0.0.0&base=https://alpha.tessera.ctl.de" 200 mit version, absoluter url (.../api-proxy/desktop/download/windows), signature, pub_date, notes; target=linux analog; base=https://alpha.tessera.ctl.de/x -> 400; vor dem Pull des neuen Abbilds noch 404 (Route existiert nicht) Braucht den laufenden Server mit dem neuen Abbild — nicht lokal simulierbar
test expected why_human
(c) Windows-VM (8233): bereits installierter Client 1.2.0 aktualisiert sich per Tray-Klick, sobald ein neuer signierter Beta-Bau auf dem Server liegt Benachrichtigung 'Neuer Beta-Stand <sha7> verfuegbar', Eintrag 'Auf Beta-Stand <sha7> aktualisieren'; Klick -> Fortschritt im Menuetext -> passives NSIS-Fenster -> Tessera startet neu, Tray zeigt neuen Stand, Server-Adresse bleibt erhalten; SmartScreen-Verhalten notieren Reale Installation/Neustart/Betriebssystem-Verhalten (SmartScreen) ist nur am Bildschirm zu pruefen; Client 1.2.0 hat das Plugin noch nicht, der erste Wechsel muss einmal ueber den Browser laufen (Einmaliger Wechsel, wie im Anwenderhandbuch dokumentiert)
test expected why_human
(d) Cross-Bau von ring/rustls (x86_64-pc-windows-msvc, cargo-xwin) in der CI-Pipeline Bau gruen; Fallback bei rotem Bau: tauri-plugin-updater mit default-features = false, features = ["native-tls", "system-proxy"] Nur im Runner mit der echten xwin/Clang-Toolchain beweisbar

Quick Task 260917-kgc: Desktop-Client — Update in der App Verifizierung

Ziel: Der Desktop-Client aktualisiert sich selbst per Tray-Klick (tauri-plugin-updater 2, minisign-Signaturpruefung, Endpunkt zur Laufzeit aus der gespeicherten Server-Adresse); API GET /desktop/update liefert das Format im Updater-Vertrag; Manifest/CI signieren und stempeln entsprechend; Doku + CHANGELOG.

Verifiziert: 2026-09-17 Status: human_needed Hinweis: Kein einziger truth ist FEHLGESCHLAGEN. Die zwei offenen Punkte sind Laufzeitverhalten (Zustandswechsel/Installation), die von keinem der bestehenden Unit-Tests ausgeloest werden koennen und laut PLAN/SUMMARY selbst als "Nachweis durch Orchestrator" gefuehrt werden (Windows-VM, echtes CI-Paket). Das ist keine Luecke in der Umsetzung, sondern der erwartete Zustand fuer diesen Task-Typ.

Beobachtete Wahrheiten (must_haves.truths)

# Truth (gekuerzt) Status Evidenz
1 Cargo.toml/Cargo.lock: tauri-plugin-updater "2" (-> 2.11.x), semver "1" (1.0.28), reqwest bleibt 0.12 ✓ VERIFIED grep-Gates gruen; cargo test --lib 33/33 gruen
2 tauri.conf.json: createUpdaterArtifacts, exakter pubkey, installMode passive, kein endpoints/dangerous* ✓ VERIFIED jq-Gate mit dem exakten Orchestrator-Schluessel bestanden
3 Reine Helfer is_update_newer/beta_commit/update_endpoint/release_labels/update_labels + fmt/check/clippy/test gruen ✓ VERIFIED cargo fmt --check, cargo clippy, cargo test --lib (33/33) selbst ausgefuehrt; is_update_newer-Regel Zeile fuer Zeile gelesen (Z. 123-135) — hoehere Basis true, niedrigere false, gleiche Basis+Beta+anderer Commit true, gleicher Commit false, gleiche Basis ohne Prerelease false, leerer Commit false; alle 8 zugehoerigen Tests gruen
4 spawn_version_check: check() mit eigenem Comparator, 15 s Pruefung, 600 s Download-Timeout vor Ablage, InsecureTransportProtocol -> gesperrter Text, Reset zu Beginn ⚠️ PRESENT_BEHAVIOR_UNVERIFIED Code exakt wie gefordert (Z. 263-338), Timeout-Trennung im Code bestaetigt; kein Test ruft die Funktion auf (State-Reset ist ein Laufzeit-Zustandswechsel)
5 Tray-Klick update: take(), Fortschritt, Installation, Neustart, Fehler-Rueckfall Browser ⚠️ PRESENT_BEHAVIOR_UNVERIFIED Code exakt wie gefordert (Z. 352-411, 591-601); kein Test loest den Menue-Zweig/spawn_update_install aus — explizit als offener Windows-VM-Nachweis im PLAN gefuehrt
6 API GET /desktop/update: base-Origin-Validierung 400, 204-Faelle, dynamisches Format, /latest und download unveraendert ✓ VERIFIED 23/23 vitest-Tests selbst ausgefuehrt, Route-Order-Gate bestanden, Code gelesen (safeOrigin, getUpdate, UPDATE_VERSION_RE, RFC3339_RE) — deckt sich exakt mit dem Vertrag
7 desktop-collect.sh schreibt signature+updateVersion mit Pflichtregel; desktop-stamp.sh check verlangt beides ✓ VERIFIED Alle Mini-Fixture-Proben aus dem PLAN selbst nachgestellt (Beta/Live/Dev-Kanal, fehlende .sig auf main/Tag/mit Schluessel -> Abbruch, dev -> Warnung, zweizeilige .sig -> Abbruch, stamp reuse=true/false-Faelle) — alle bestanden
8 CI: Secrets nur an den zwei tauri-build-Schritten, kein Job-env, kein --no-sign, sonst strukturgleich ✓ VERIFIED js-yaml-Tiefenvergleich gegen git show 5a444ec:.gitea/workflows/ci.yml selbst ausgefuehrt — CI-OK; Negativ-Grep --no-sign leer; .gitignore traegt *.key; git ls-files '*.key' leer
9 Doku (Anwender/Betrieb/Entwicklung/ci-cd-setup/CHANGELOG) ✓ VERIFIED Alle Grep-Gates aus dem PLAN selbst ausgefuehrt (14 Pruefungen) — alle gruen; changelog.test.ts 10/10 gruen
10 Vier Commits, kein Push/.planning/tauri build/Docker ✓ VERIFIED git rev-list --count 5a444ec..HEAD = 4; keine .planning/-Dateien in den vier Commits

Score: 8/10 truths verified (2 present, behavior-unverified)

Hinweis zu Wahrheit 3 (kein coincidental reliance)

Die is_update_newer-Regel wird von acht dedizierten Tests direkt und unmittelbar geprueft (kein Fixture-Only-Fall, keine unbekannte Vorbedingung) — als sauber VERIFIED eingestuft, keine Advisory-Markierung noetig.

Artefakt-Pruefung

Artefakt Erwartet Status Details
apps/desktop/src-tauri/src/lib.rs Updater-Kette, Helfer, Tests ✓ VERIFIED Alle geforderten Symbole vorhanden (is_update_newer, beta_commit, update_endpoint, release_labels, spawn_update_install, open_download_page, PendingUpdate, download_and_install, version_comparator); DesktopLatest entfernt, /desktop/latest nicht mehr referenziert
apps/desktop/src-tauri/Cargo.toml/Cargo.lock/tauri.conf.json Neue Abhaengigkeiten + Config ✓ VERIFIED Versionen exakt wie gefordert
packages/shared/src/index.ts signature?, updateVersion?, DesktopUpdateResponse ✓ VERIFIED Alle drei per grep bestaetigt, type-check gruen
apps/api/src/desktop/desktop.service.ts + .controller.ts + .spec.ts safeOrigin, getUpdate, update()-Route, Tests ✓ VERIFIED Code gelesen, Tests ausgefuehrt, Route-Order bestaetigt
.gitea/scripts/desktop-collect.sh/desktop-stamp.sh/ci.yml/.gitignore .sig -> signature, updateVersion, Secrets, *.key ✓ VERIFIED Proben + Deep-Compare selbst ausgefuehrt
Vier Dokudateien + CHANGELOG Update-in-der-App-Beschreibung ✓ VERIFIED Grep-Gates gruen
Von Nach Via Status
CI-Signatur (.sig) desktop-collect.sh -> Manifest signature read_signature liest <bundle>.sig, jq schreibt es ins Manifest ✓ VERIFIED (Probe bestanden)
Manifest signature/updateVersion API-Antwort GET /desktop/update getUpdate() liest beide Felder, 204 wenn eines fehlt ✓ VERIFIED (Code + Tests)
version_comparator Plugin-Standardvergleich is_update_newer ersetzt den Vergleich vollstaendig, Aufruf in check_for_update bestaetigt ✓ VERIFIED (Code gelesen, Z. 273-276)
UpdaterBuilder::timeout(15s) update.timeout = 600s Beide Stellen im Code gefunden und in der richtigen Reihenfolge (Pruefung vor Ablage) ✓ VERIFIED (Z. 275, 316)
Client-Klick "update" PendingUpdate.take() -> spawn_update_install Menue-Zweig ruft take(), dann spawn_update_install oder open_download_page ✓ WIRED (Code), ⚠️ Laufzeitverhalten nicht getestet (siehe Wahrheit 5)

Verhaltens-Stichproben

Verhalten Befehl Ergebnis Status
Rust fmt/check/clippy/test cargo fmt --check && cargo clippy --lib && cargo test --lib (CARGO_BUILD_JOBS=4) fmt clean, clippy 0 Warnungen, 33/33 Tests gruen ✓ PASS
API-Tests pnpm --filter @tessera/api exec vitest run src/desktop 23/23 gruen ✓ PASS
API/Shared type-check pnpm --filter @tessera/api type-check / @tessera/shared type-check 0 Fehler je ✓ PASS
Skript-Syntax sh -n desktop-collect.sh / sh -n desktop-stamp.sh beide clean ✓ PASS
Route-Order-Gate awk-Pruefung @Get('update') vor @Get('download/:platform') Manuell im Quelltext bestaetigt (update() vor download()) ✓ PASS
pubkey-Gate jq -e .plugins.updater.pubkey == "<exakter Schluessel>" true ✓ PASS
CI js-yaml-Tiefenvergleich Node-Skript gegen git show 5a444ec:.gitea/workflows/ci.yml "CI-OK" ✓ PASS
Skript-Mini-Fixtures (Beta/Live/Dev, fehlende/zweizeilige .sig, stamp reuse) Eigenstaendig im Scratchpad nachgestellt (siehe PLAN Task 3 <verify>) Alle 15 Teilpruefungen gruen ✓ PASS
Doku-Grep-Gates (14 Pruefungen) siehe PLAN Task 4 <verify> Alle gruen ✓ PASS
changelog.test.ts pnpm --filter @tessera/web exec vitest run src/lib/changelog.test.ts 10/10 gruen ✓ PASS
Secret-Leck-Pruefung grep auf private-key-Werte im Diff Nichts gefunden ✓ PASS
.key-Dateien im Repo git ls-files '*.key' leer ✓ PASS

Requirements Coverage

Requirement Quelle Beschreibung Status
QUICK-260917-KGC 260917-kgc-PLAN.md Desktop-Client Update in der App (siehe Task-Ziel) ✓ SATISFIED (bis auf die zwei Laufzeit-Nachweise, siehe oben)

Anti-Pattern-Scan

Keine TBD/FIXME/XXX-Debt-Marker (der einzige Treffer auf "XXXX" ist ein Doc-Kommentar-Beispiel 1.2.0-beta.gXXXX, kein Debt-Marker); keine TODO/HACK/PLACEHOLDER; keine "not implemented"-Stellen ausser zwei bereits bestehenden, legitimen NotFoundException-Meldungen ("Desktop packages are not available on this server"). Keine unerwarteten Dateien ausserhalb files_modified veraendert (3 generierte gen/schemas/*.json-Dateien sind dokumentierte Abweichung, Praezedenz aus Phase 18-04).

Erforderliche menschliche Verifizierung

Siehe human_verification im Frontmatter — die vier vom Orchestrator selbst als offen gefuehrten Nachweise (a) CI-Bau mit echten Secrets, (b) Endpunkt-curl gegen alpha, (c) Windows-VM Update-Durchlauf, (d) Cross-Bau ring/rustls. Diese sind keine Luecken, sondern der erwartete naechste Schritt nach diesem Quick Task (siehe SUMMARY.md "Nachweis durch Orchestrator (offen)").

Zusammenfassung

Alle zehn must_haves.truths sind im Code vorhanden, exakt wie im PLAN spezifiziert verdrahtet, und alle automatisierten Gates (Rust fmt/clippy/test, API-Tests/Type-Checks, Skript-Proben, CI-Deep-Compare, Doku-Grep-Gates, Changelog-Test) wurden von mir selbst ausgefuehrt und bestanden — keine SUMMARY-Behauptung wurde ungeprueft uebernommen. Zwei Wahrheiten (State-Reset bei Server-Wechsel, Tray-Klick-Installationsfluss inkl. take()-Semantik) haengen an Tauri-Laufzeitzustand, den keiner der 33 Unit-Tests ausloest; das deckt sich mit den vier vom Orchestrator selbst als offen gefuehrten Nachweisen und ist fuer einen Quick Task dieser Art normal, nicht ein Zeichen unvollstaendiger Umsetzung.


Verifiziert: 2026-09-17 Verifizierer: Claude (gsd-verifier)