Skip to content

fix: window/EXE-Icon zeigte altes Design nach Store-Update 1.0.3 - #5

Merged
lukisch merged 2 commits into
mainfrom
fix/T-20260926-864299616-window-icon-regression
Sep 26, 2026
Merged

lukisch merged 2 commits into
mainfrom
fix/T-20260926-864299616-window-icon-regression

Conversation

@lukisch

@lukisch lukisch commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Zusammenfassung

  • T-20260926-864299616: Nutzer meldet, dass im Store-Update 1.0.3 zwar
    das Taskleisten-/Kachel-Icon korrekt ist, das Fenster-Icon (Titelleiste,
    EXE-Ressource) aber ein altes, anderes Design zeigt -- ein Ruckfall
    gegenuber dem letzten Store-Paket.
  • Ursache (gemessen, nicht vermutet): die Store-Kachel
    (store_assets/Square*.png) wurde in einem spaeteren Commit neu
    gebrandet, das Desktop-Icon-Material (.ico-Dateien UND die
    Master-/Fallback-PNGs, die load_app_icon() in main.py als Kandidaten
    durchgeht) wurde dabei nicht mitgezogen. Jede einzelne Datei war fuer
    sich konsistent (alle eingebetteten Groessen/Aufloesungen zeigten
    dasselbe -- alte -- Design), weshalb ein reiner Selbstvergleich das nie
    gefunden hatte -- erst der Quervergleich Desktop-Icon <-> Store-Kachel
    zeigt den Bruch.
  • Fix (zwei Commits, nach Review nachgezogen):
    1. d2f7e20: die fuenf Desktop-.ico-Dateien
      (assets/cleanmarkdown.ico, CleanMarkdown.ico, DesktopIcon.ico,
      icon.ico, assets/icon.ico) aus store_assets/Square310x310Logo.png
      neu erzeugt.
    2. 29389ac (Review-Nachbesserung): die verbleibenden, im ersten Commit
      uebersehenen Fallback-Assets aus derselben Quelle neu erzeugt --
      icon.png/DesktopIcon.png/assets/icon.png (1024px-Master,
      310->1024 hochskaliert, da keine hoeher aufgeloeste Quelle im Repo
      existiert) sowie assets/favicon.png/assets/favicon.ico. Plus
      Versionsbump auf 1.0.4 (main.py, pyproject.toml, store_package.json,
      build_exe.bat, tests/test_metadata.py) und CHANGELOG-Eintrag, nach dem
      Muster des 1.0.3-Release-Commits.
  • Test: test_window_icon_matches_store_tile_branding in
    tests/test_assets_and_icons.py prueft jetzt jeden Frame jeder
    .ico-Datei in load_app_icon()s Fallback-Kette PLUS jede
    Master-/Fallback-PNG gegen die Store-Kachel (perzeptueller Diff,
    Schwelle 0.20). Prueft damit direkt die Pixel, die Windows tatsaechlich
    zeichnet (EXE-Ressource + Fenster-Titelleiste), nicht nur "ein QIcon
    existiert". 167/167 Tests im Projekt gruen.

Zusaetzlich (nicht Teil dieses Fixes, nur zur Kenntnis)

mobile_icons/* (aeltere olivbraune Gestaltung fuer PWA/Web) wurde
bewusst NICHT angefasst -- andere Verbrauchsstelle (mobil/Web statt
Desktop-Fenster), separater Befund.

Release-Gate

Das generische Release-Gate-Skript (icon_consistency_check.py,
.SOFTWARE/_STORE/) wurde im selben Review-Zug nachgebessert: es
uebersah zuvor genau diese Luecke (favicon-grosse .ico-Dateien ohne
128/256px-Frame wurden stillschweigend uebersprungen, Master-PNGs
wurden gar nicht geprueft) und ist jetzt in WINDOWS_STORE_BUGFIX_POLICY.md
Abschnitt 7a als Pflichtschritt vor jeder Store-Einreichung verankert.

Test plan

  • python -m pytest -q -- 167 passed
  • python icon_consistency_check.py <worktree> -- "gate passed"

🤖 Generated with Claude Code

https://claude.ai/code/session_01PTbvD41MCVmnQWaobvHfCk

T-20260926-864299616: after the 1.0.3 Store update, the taskbar/tile
icon was correct but the window titlebar icon (and the EXE resource
feeding it) still showed an old, different design.

Root cause (measured, not assumed): assets/cleanmarkdown.ico and its
duplicates (CleanMarkdown.ico, DesktopIcon.ico, icon.ico,
assets/icon.ico) were generated from an older master image, while
store_assets/Square*.png (used by the MSIX manifest for the taskbar
tile) got rebranded in a later commit. Each .ico was internally
consistent -- same design across all embedded sizes -- which is why
this wasn't caught: the mismatch is only visible when comparing the
desktop icon against the Store tile, not within one file.

Regenerated all five desktop .ico files from
store_assets/Square310x310Logo.png (same source, 7 sizes:
16/24/32/48/64/128/256), and added a regression test
(test_window_icon_matches_store_tile_branding) that fails if the
desktop icon and the Store tile ever drift apart again -- perceptual
diff against store_assets/Square310x310Logo.png, threshold 0.20.
Measured: broken file diffed by 0.35, this fix by 0.0005.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PTbvD41MCVmnQWaobvHfCk

@lukisch lukisch left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review (merge-reviewer, claude-opus) auf Head d2f7e20: Die .ico-Korrektur ist richtig, reicht aber noch nicht.

Wer hat recht: Der Nutzer. Ich habe alle 5 .ico in allen 7 eingebetteten Größen alt gegen neu neben Square310x310Logo gerendert. Das alte Icon (auch assets/cleanmarkdown.ico) ist ein braunes Quadrat mit grünem Rahmen, darin ein winziges Dokument-Motiv. Perzeptueller Abstand zur Kachel 0.35 in jeder Größe. Das neue ist das Kachel-Motiv (Dokument mit „M→[ ]“, blau-grüner Verlauf): Abstand 0.00 bei 48/256, 0.01 bei 32, 0.07 bei 16. Bei 16 px ist die Form klar erkennbar, bei 24/32 px auch „M→[ ]“. Die Aussage von heute Mittag, assets/cleanmarkdown.ico sei das richtige, aktuelle Motiv, war falsch.

Mängel:

  1. Die Master-/Fallback-PNGs tragen weiter das alte Design (Abstand 0.35): assets/icon.png (1024², Fallback in load_app_icon(), main.py:77), icon.png, DesktopIcon.png (laut CHANGELOG die 1024er „Master-Icons“), assets/favicon.png sowie assets/favicon.ico. Nur CleanMarkdown.png ist aktuell. Das ist vermutlich die eigentliche Rückfallquelle: Wer die .ico wieder aus den „Master-PNGs“ erzeugt, bekommt das alte Design zurück. Bitte in diesem PR aus derselben Quelle neu erzeugen.
  2. Der Regressionstest deckt die tatsächliche Fensterquelle nicht ab: load_app_icon() probiert zuerst assets/icon.ico, getestet werden aber nur assets/cleanmarkdown.ico und CleanMarkdown.ico, und das nur im 256/128-Frame. Bitte alle getrackten .ico (außer bewusst ausgenommenen), jeweils alle Größen, sowie die Fallback-PNGs gegen die Kachel prüfen.
  3. Gate _STORE/icon_consistency_check.py (10 Tests grün, Policy 7a schlüssig): Auf diesem PR meldet es „passed … every .ico is internally consistent“, obwohl assets/favicon.ico noch das alte Design trägt (Abstand 0.35). Vermutlich werden .ico ohne 128/256-Frame still übersprungen, PNG-Master prüft es gar nicht. Beides entgegen der Doku („vergleicht jedes .ico“). Bitte Skip melden statt schweigen, PNG-Master mit einbeziehen.
  4. Hinweis zum Release: Kein CHANGELOG-Eintrag, keine Versionsanhebung. Für die Store-Neueinreichung nach 1.0.3 braucht es beides (hier oder im Release-PR).

Review of PR#5 (T-20260926-864299616) found PR#5 only fixed the .ico
files load_app_icon() tries first -- the PNG masters/fallbacks it also
uses, and the favicon, still carried the pre-fix design and were the
actual regression source for anyone hitting the PNG fallback path:

- icon.png, DesktopIcon.png, assets/icon.png (1024px masters)
- assets/favicon.png, assets/favicon.ico

All regenerated from store_assets/Square310x310Logo.png (the same,
single source as the .ico fix), master PNGs upscaled 310->1024 via
LANCZOS (no higher-resolution source exists in this repo).

Test extended (test_window_icon_matches_store_tile_branding) to check
every embedded frame of every .ico candidate in load_app_icon()'s
fallback chain, plus every master/fallback PNG, against the Store
tile -- not just the first two .ico candidates.

Version bumped to 1.0.4 (main.py, pyproject.toml, store_package.json,
build_exe.bat, tests/test_metadata.py) following the 1.0.3 pattern,
CHANGELOG entry added.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PTbvD41MCVmnQWaobvHfCk

@lukisch lukisch left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-Review (merge-reviewer, claude-opus) auf Head 29389ac: Merge.

  • Alle Desktop-.ico (assets/icon.ico als erste Fensterquelle, cleanmarkdown.ico, CleanMarkdown.ico, icon.ico, DesktopIcon.ico, favicon.ico) sind in allen eingebetteten Größen gegen Square310x310Logo gemessen: Abstand 0.00 (48–256), 0.01 (32), 0.03 (24), 0.07 (16). Die Master- und Fallback-PNGs icon.png, DesktopIcon.png, assets/icon.png, favicon.png, CleanMarkdown.png liegen bei 0.00–0.005, die echten Paket-Kacheln in store_package/CleanMarkdown/icons ebenfalls.
  • Tests: 167 passed. Gate-Tests 11 passed. Gate gegen den PR-Stand: passed. Negativkontrolle gegen den alten master: Das Gate meldet jetzt alle alten .ico einschließlich favicon.ico sowie die vier PNG-Master (0.35). CI komplett grün.
  • Version 1.0.4 steht in main.py, build_exe.bat, pyproject, store_package.json und den Tests, der CHANGELOG-Eintrag ist korrekt.

Nicht blockierend, als Folgeauftrag:

  1. Version noch auf 1.0.3 in README.md und README_DE.md (Badge), WINDOWS_STORE_PREP.md und PORTIERUNGSPLAN.md.
  2. Der Legacy-Spiegel store_assets/icon_{44x44,50x50,150x150,310x310,310x150}.png trägt noch das alte Design (Abstand 0.35). Er wird vom echten Paket nicht genutzt (das referenziert store_package/CleanMarkdown/icons, dort ist alles aktuell), das Gate prüft ihn aber nicht. Neu erzeugen oder entfernen.
  3. Die eingecheckten AppxManifest.xml (store_package und store_assets) stehen auf Version="1.0.2.0". Vorbestehend, laut store_assets.py wird das beim Paketbau aus store_package.json erzeugt; vor dem Paketbau trotzdem prüfen, dass im MSIX 1.0.4.0 steht.

@lukisch
lukisch merged commit 2ce9c34 into main Sep 26, 2026
16 checks passed
lukisch added a commit that referenced this pull request Sep 27, 2026
….5 (#7)

* fix: .md-Dateisymbol zeigte Kachel auf brauner Platte; Store-Paket ohne Dateityp-Zuordnung (1.0.5)

T-20260927-699609650. Gemessen, nicht vermutet:
- .md -> ProgId CleanMarkdown.mdfile -> DefaultIcon "<CleanMarkdown.exe>,0".
  Das Symbol ist also das in die EXE eingebackene Icon. Die ausgelieferte
  1.0.3-EXE traegt das Plattendesign aus e712d9d (byte-identisch zum
  CleanMarkdown.ico von b26390d, Abweichung 0.35 zur Store-Kachel). PR #5
  hat das nur im Quellbaum behoben, 1.0.4 wurde nie ausgeliefert.
- Das installierte 1.0.3-MSIX hat keine FileTypeAssociation, kein
  resources.pri und keine targetsize/unplated-Varianten:
  _STORE/msstore_build_msix.ps1 erzeugte das Manifest selbst und ignorierte
  store_package.json file_types (Builder ausserhalb des Repos mitgefixt).

Fix: Version 1.0.5; Square44x44Logo.targetsize-{16..256} je plain,
altform-unplated, altform-lightunplated aus der Store-Kachel
(scripts/gen_targetsize_icons.py); Regressionstest; STORE_ISSUES korrigiert.
Gate (_STORE/icon_consistency_check.py --package) prueft jetzt das gebaute
MSIX: rot gegen das installierte 1.0.3 (4 Befunde), gruen gegen 1.0.5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PTbvD41MCVmnQWaobvHfCk

* fix: unplated targetsize-Assets waren opak; Migrationspfad für lokale Installation

T-20260927-699609650, Blocker D aus der astra-Abnahme von PR #7 (81dacc6):

- install_local.ps1 registriert eine eigene ProgID (CleanMarkdown.mdfile,
  DefaultIcon auf die lokale EXE). Diese Installation blieb nach einem
  Store-Update unverändert bestehen und "gewann" weiterhin die .md-Zuordnung
  -- das MSIX ersetzt sie nicht automatisch. uninstall_local.ps1 ist das
  Gegenstück: bricht ab, wenn kein Store-Paket installiert ist, sichert die
  betroffenen Registry-Zweige per reg export und entfernt danach nur, was
  install_local.ps1 selbst angelegt hat (ProgID, DefaultIcon, .md-Verweis,
  OpenWithProgids, Applications-Key, UserChoice falls zutreffend, Startmenü-
  Verknüpfung, Installationsordner). README/README_DE dokumentieren jetzt,
  dass lokale und Store-Installation nicht parallel bestehen sollen.

- gen_targetsize_icons.py erzeugte für unplated/lightunplated-Varianten
  byte-identische, opake Kopien der plated-Variante -- ein Nebenbefund der
  Gate-Härtung in _STORE/icon_consistency_check.py (siehe dortigen Commit):
  das jetzt strengere --package-Gate hätte den eigenen 1.0.5-Build
  andernfalls selbst abgelehnt. Fix: kleiner transparenter Eckpatch pro
  Variante -- genug für echte Transparenz, klein genug, um innerhalb der
  bereits kalibrierten Diff-Schwelle von test_assets_and_icons.py zu bleiben
  (ein voller 12%-Rand ergab 0.22 bei 16px, Schwelle 0.20).

Verifiziert: 168 Projekttests grün; echter 1.0.5-MSIX-Neubau über das
gehärtete _STORE/msstore_build_msix.ps1 (inkl. erzwungenem
icon_consistency_check.py --package) läuft mit Exit 0 durch.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PTbvD41MCVmnQWaobvHfCk

* fix: 2. astra-Abnahme (5 Blocker) schliessen — C1/C2/D1-D3

T-20260927-699609650, Head 9596928 wurde von gpt-6-astra (effort high) mit
"NICHT OK" bewertet (voller Bericht: _codex/ASTRA-REABNAHME_T-20260927-699609650.md).
Alle 5 Blocker sind behoben und gegen astras real reproduzierte Manipulationen
verifiziert (Details: _codex/FIX-C1-C2-D1-D2-D3_T-20260927-699609650.md):

- C1: Gate pruefte nur 5 von 14 ausgelieferten Icon-Groessen -- jetzt werden
  alle tatsaechlich im Paket/resources.pri vorhandenen Varianten erkannt und
  geprueft, nicht nur eine feste Pflichtliste.
- C2: Das reale 1.0.5-MSIX enthielt den onedir-Laufzeitordner (_internal,
  Python-DLLs) nicht -- die App waere nicht gestartet. Kopierschritt erkennt
  jetzt onedir-Layout und uebernimmt den kompletten Ordner.
- D1: uninstall_local.ps1 loeschte beim UserChoice-Rueckbau den gesamten
  Explorer-Elternzweig FileExts\.md samt fremden Geschwisterzweigen -- jetzt
  nur noch der UserChoice-Unterschluessel selbst.
- D2: Fehlgeschlagene Registry-Backups stoppten die Loeschung nicht -- jeder
  Export wird jetzt geprueft, ein Fehlschlag bricht vor jeder Aenderung ab.
- D3: Jede installierte Store-Version wurde akzeptiert, auch die real
  installierte 1.0.3 ohne .md-FileTypeAssociation -- das Manifest wird jetzt
  geprueft, eine Version ohne Handler wird abgelehnt.

D1-D3 zusaetzlich per gemocktem PowerShell-Testlauf verifiziert (kein echter
Registry-Zugriff). Store-Gate-Tests 27/27 gruen, Projekt-Testsuite 168/168
gruen, realer 1.0.5-MSIX-Neubau ueber das gehaertete msstore_build_msix.ps1
gruen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PTbvD41MCVmnQWaobvHfCk

* fix: uninstall_local.ps1 loeschte .md-Standardwert nicht wirklich (D4)

T-20260927-699609650, 3. Abnahme (Fable, schreibgeschuetzt) fand: mein D1-Fix
`Remove-ItemProperty -Name "(Default)"` schlaegt gegen den PowerShell-
Registry-Provider fehl (verifiziert in pwsh 7.6.6 und Windows PowerShell 5.1),
`-ErrorAction SilentlyContinue` machte das unsichtbar. Folge: HKCU:\Software\
Classes\.md zeigte nach dem Rueckbau weiter auf die bereits geloeschte ProgID
CleanMarkdown.mdfile -- schlimmer als der vorherige Set-Item -Value "" (der
den Verweis wenigstens leerte).

Fix: echte Entfernung ueber die .NET-Registry-API
([Microsoft.Win32.Registry]::CurrentUser...DeleteValue), die den PowerShell-
Provider umgeht. Verifiziert in einem Wegwerf-Schluessel (angelegt, geprueft,
wieder entfernt -- keine dauerhafte Aenderung am Host).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PTbvD41MCVmnQWaobvHfCk

* chore: internal review reports aus dem Repo entfernen, README neutralisieren

merge-reviewer-Befund vor dem Merge von PR #7: Das Repo ist public. _codex/
enthielt interne Abnahmeberichte mit lokalen Pfaden, Hostnamen und
Reviewernamen -- nach einem Squash-Merge waeren die dauerhaft in der
main-Historie gelandet.

- _codex/ aus dem Git-Tracking entfernt (git rm --cached), lokal behalten,
  in .gitignore aufgenommen.
- README.md/README_DE.md: interne Ticket-ID und Reviewername ("astra
  abnahme review") aus der Nutzer-Doku entfernt/neutralisiert. Die Ticket-ID
  bleibt wie besprochen im CHANGELOG stehen.

Fachliche Pruefung wird durch diesen Commit nicht beruehrt (reine
Bereinigung, kein Verhaltensunterschied).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PTbvD41MCVmnQWaobvHfCk

---------

Co-authored-by: Lukas Geiger <lukas@um-bruch.org>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant