Dotfiles_ArchAP/greetd/LOGIN_RECOVERY_V2.md

16 KiB
Raw Permalink Blame History

Connexion Labfy / Mosaic / QuickShell — V2

État du lot : READY_FOR_EXPLICIT_INSTALL_APPROVAL. Aucune installation ni activation. Ce document complète la V1 de SESSION_SELECTOR et conserve sa recette historique. Le greeter installé utilise encore uwsm start default ; le sélecteur source V1 n'est pas installé.

Périmètre et conservation

LAB privé 0700 : /var/tmp/labfy-greeter-mosaic-login-v2-0dvus1y_/. Les journaux bruts et rc sont sous logs/ et results.jsonl. Le snapshot initial, le diff V1, ses sources et 293 081 empreintes contrôlées hors paquet greeter sont sous audit/. Aucun écart de contenu/mode/propriétaire/lien n'a été trouvé hors greetd/. Le dépôt Mosaic reste propre à 7216eb55, sans modification.

V1 est reprise, sans réécrire le runtime : src/greetd_ipc.py, src/auth.py, src/labfy_greeter.py et style/labfy-greeter.css restent byte-identiques aux sources V1 initiales. Un test ajoute le refus Mosaic puis une nouvelle tentative PAM Stable. session-update.py ajoute une relecture après publication avant de certifier son journal, et une barrière complète de durabilité avant mutation. Les autres nouveaux fichiers sont des candidats, outils, tests et documents sous greetd/, pas des services déployés par Stow.

Le source candidat du lanceur, ses wrappers/configuration de référence et le manifeste sont sous mosaic-login-v2/launcher/. Seuls session.py, manifest.json et le nouveau quickshell-guard.py sont destinés à publication. Les wrappers, l'entrée desktop, la configuration Mosaic, les drop-ins existants, le binaire CORE-C V2 et wlroots restent inchangés.

Sélecteur et autorité PAM

Choix visible avant saisie Commande exacte transmise après PAM, avec env=[]
SwayFX — Stable, défaut à chaque ouverture ["/usr/bin/uwsm", "start", "sway.desktop"]
SwayFX Mosaic — Expérimental, choix explicite ["/usr/bin/uwsm", "start", "swayfx-mosaic-test.desktop"]

Liste immuable ; aucune interpolation, commande libre ou exécution UWSM dans GTK. Le compte et la sélection sont figés pour la conversation. Les contrôles sont gelés pendant une requête ; changer compte/session entre invites annule PAM. Un refus de lancement consomme l'authentification et ne déclenche aucun repli. L'aperçu désactive PAM, alimentation et écriture de luminosité.

default-id vaut actuellement sway.desktop, SHA256 7936c31cdc80c790ebb9c08f20ddd2e52f7a1fe82d46e1a44a0b395137dc141e. La valeur V1 « déjà Mosaic » est une observation historique antérieure ; elle ne décrit plus l'état V2. Aucun test V2 ne modifie cette préférence réelle. Le test stable utilise une préférence factice dans le LAB, sans binaire Mosaic.

Cause attestée et correctif du lanceur

Le journal du 15 octobre 2026 à 16:50:10 +02:00 contient : MOSAIC REFUSÉ : Isolation swayidle/autostart non chargée. Le nom XDG autostart dans systemctl --user show ... -p Conflicts est entre guillemets, avec les antislashs de \x2d doublés. .split() conserve ce codage ; le test reproduit le faux négatif sur la sortie réelle, pas une chaîne inventée.

systemd_words() valide une grammaire bornée puis décode via shlex.split, sans shell. Les échappements inconnus, tokens concaténés, contrôles et noms invalides sont rejetés. validate_isolation() exige l'Id exact, LoadState=loaded, les chemins exacts des deux drop-ins chargés et chaque conflit d'exclusion. Le vrai manager chargé passe en lecture seule. Les négatifs retirent chacun des conflits et altèrent identité, LoadState et DropInPaths. Aucune garde logind, seat/VT, cgroup, notify, parent graphique, LD ou empreinte n'est supprimée. Les alias Stow systemd/QuickShell sont vérifiés littéralement ; les lectures et publications visent ensuite leurs chemins canoniques sans traverser ces liens.

QuickShell propre à Mosaic

Source : mosaic-login-v2/systemd/quickshell-labfy-mosaic.service, avec son lien .target.wants/ relatif conservé dans le même répertoire de sources. La cible est exactement wayland-session@swayfx\x2dmosaic\x2dtest.desktop.target. WantedBy ne vise qu'elle ; PartOf et BindsTo attachent l'arrêt au target. After et Requisite visent target et WM. Le WM UWSM est Type=notify : son uwsm finalize existant exporte les sockets avant READY=1. Aucun exec qs n'est ajouté à la configuration du compositeur. Commande : /usr/bin/qs -c labfy-sway --no-color. Restart=no, arrêt borné à 5 secondes.

L'ExecStartPre valide les états, MainPID, cgroup, SHA du processus, mapping wlroots, contexte logind/VT et propriété des deux sockets par le processus. Un autre WM, un QuickShell existant ou un serveur de notifications fait refuser le démarrage. Aucun Conflicts n'arrête QuickShell Stable pour le remplacer. Le service Stable et son lien d'activation sont byte-identiques aux originaux.

Le manager partagé contient actuellement un SWAYSOCK ancien (PID 5630), alors que le WM Stable réel est PID 12197. Aucun correctif de la session active n'a été tenté. La nouvelle garde empêche précisément cette confusion sur Mosaic.

Le seul adaptateur QML est une garde dans SessionV2Service.run() : LABFY_MOSAIC_SMOKE=1, fourni uniquement au service Mosaic, refuse les opérations V2 avant démarrage du backend. Stable garde son comportement lorsque ce drapeau est absent. Le candidat est isolé sous mosaic-login-v2/quickshell/, et n'a pas été copié dans le QML actif. Après installation approuvée, la publication de ce QML partagé peut provoquer sa détection/relecture par QuickShell Stable ; aucun changement de service ni redémarrage explicite n'est déclenché par les outils.

L'audit des QML trouve un PolkitAgent et le NotificationServer existants dans labfy-sway, ainsi que les accès Sway via l'environnement SWAYSOCK. Les adaptateurs WiFi/Bluetooth restent ceux de Quickshell. Aucun nouveau daemon/agent ou lock n'est introduit. L'autostart XDG, swayidle, wlsunset et les collecteurs clipboard restent exclus par les drop-ins actuels. Session Restore V2 reste désactivé dans le smoke Mosaic, y compris ses actions manuelles. La barre réelle, les services D-Bus, la sortie physique et les fonctions interactives restent NOT_RUN.

Matrice de validation

Contrôle Résultat effectif
Suite V1 initiale PASS : 19 recensés, 17 exécutés, 2 GTK ignorés
Suite greeter V2 complète avec Wayland explicite PASS : 21/21, rc=0
Même suite sans GTK PASS : 19 exécutés, 2 ignorés, rc=0
Suite lanceur/garde/publications/coordination V2 PASS : 29/29, rc=0
Ancien parser sur vraie propriété Faux négatif reproduit ; nouveau parser PASS
Négatifs isolation, contexte, PID Stable, SHA, symlink et stable sans LAB PASS dans tests réels/factices explicités
Deux uwsm start -n <id>.desktop PASS, rc=0 ; aucune écriture ni démarrage
systemd-analyze --user --generators=no verify unité candidate PASS, rc=0
Relations WantedBy/After/Requisite/PartOf/BindsTo, source .wants PASS, modèle statique ; manager privé non nécessaire
Qt6 qmllint avec vrais modules et copie candidate de 86 sources rc=0 ; mêmes 17 avertissements qu'en baseline, aucun nouveau
AST + py_compile, pycache LAB PASS, 18 fichiers Python
Aperçus GTK natifs, fenêtre seule, 1131 × 853 PASS : Stable initial et Mosaic, aucun PAM
Root : erreur d'écriture, vraie mort après deux rename, reprise PASS sur cibles factices, suite greeter
User : mort après chacun des six rename, rollback et idempotence PASS sur cibles factices, six points d'interruption
Coordination : mort après user et après root, reprise des deux lots PASS sur cibles factices, deux frontières
Barrières complètes : ordre fsync/publication, défauts outils/métadonnées/parents PASS sur fixtures ; aucun fichier actif publié si échec
Garde complète PID/maps/inodes/autre QuickShell/logind PASS sur fixture isolée et sockets factices ; aucun compositeur lancé
Préflight global du nouveau bundle PASS, aucune publication active
Installation/rollback réels root/user, daemon-reload NOT_RUN
Login VT1, Mosaic autonome, barre réelle, sortie et retour greeter NOT_RUN

Échecs initiaux conservés dans les logs : constructeur Selection convertissant None en Path (corrigé) ; premier GTK sans WAYLAND_DISPLAY (socket identifié en lecture seule puis fourni explicitement) ; préflight refusant le parent symlink Stow (chemins canoniques corrigés) ; ConfigParser du test refusant deux lignes Environment (une ligne équivalente, verify systemd passant). Aucun échec brut n'est converti en PASS. PyGObject émet des avertissements de dépréciation asyncio. Les captures sont captures/preview-stable.png et captures/preview-mosaic.png dans le LAB ; la date affichée en anglais vient de la locale de cet aperçu. Aucune qualification fullscreen/VT1 ou daily-driver Mosaic n'en découle.

Audit final et correction bornée

L'audit final unique du snapshot bundle-r1 reste FAIL : un BLOCKING de barrière de durabilité complète, et une limite NON_BLOCKING de couverture du parcours positif verify_process(). Le bundle r1 est conservé et supersédé, jamais promu en PASS rétroactivement.

La réparation ajoute les deux barrières complètes décrites ci-dessous, teste leur ordre avant le premier rename et injecte des erreurs sur les outils, métadonnées et parents : zéro cible changée. La fixture positive de la garde et ses mutations maps/inodes/autre QuickShell/logind passent également. Ces corrections appartiennent à une seule chaîne bornée après audit. La revue bornée indépendante du delta et du bundle r2 est PASS, sans finding restant. La validation indépendante finale confirme 21/21 tests GTK greeter et 29/29 tests V2, les 23 empreintes du bundle et le préflight global. Inventaire r2 SHA256 : d4c1c393e5217ec583c1c1ac30b7b6c7841c659dfcd3a385325b3b0d19d8aa3d. Les tests de mort de processus ne constituent pas une coupure électrique réelle, qui reste NOT TESTED ; la garantie de durabilité repose sur les fsync ordonnés et les garanties du système de fichiers, pas sur une simulation de panne machine.

Installation proposée — après approbation explicite uniquement

Le bundle courant examiné est bundle-r2/ dans le LAB : sous-lots root/ et user/, inventaire SHA256.json. Ne jamais réutiliser les .new V1 ou les premières préparations intermédiaires staging/. prepare-login-recovery.py reconstruit les deux sous-lots depuis les sources courantes, copie les outils et scelle les fichiers user dans le sous-lot root. Le préflight global vérifie également default-id, Stable, les scripts greeter, config.toml et le couple binaire/wlroots exact. Un changement impose nouvelle préparation/revue.

Les commandes ci-dessous sont préparées, NON EXÉCUTÉES. Avant de les autoriser, examiner diff, captures, SHA et résultats. Les répertoires durables doivent être neufs ; mkdir refuse de remplacer un lot déjà installé. Ne pas ouvrir une nouvelle connexion pendant la courte publication des fichiers.

# UNIQUEMENT APRÈS APPROBATION — préparation durable sans activation
login_v2_bundle=/var/tmp/labfy-greeter-mosaic-login-v2-0dvus1y_/bundle-r2
python3 -I -B "$login_v2_bundle/root/login-recovery-update.py" check \
  "$login_v2_bundle/root" "$login_v2_bundle/user"
mkdir -p -m 0700 /home/fy59/.local/state/labfy-greeter-mosaic-login-v2
mkdir -m 0700 /home/fy59/.local/state/labfy-greeter-mosaic-login-v2/v2
install -m 0600 "$login_v2_bundle/user/"* \
  /home/fy59/.local/state/labfy-greeter-mosaic-login-v2/v2/
sudo mkdir -m 0700 /var/lib/labfy-greeter/login-recovery-v2
sudo install -o root -g root -m 0600 "$login_v2_bundle/root/"* \
  /var/lib/labfy-greeter/login-recovery-v2/
sudo python3 -I -B /var/lib/labfy-greeter/login-recovery-v2/login-recovery-update.py check
# Commande de publication complète, seulement après accord explicite :
sudo python3 -I -B /var/lib/labfy-greeter/login-recovery-v2/login-recovery-update.py apply
# Toujours après approbation ; recharge seulement, sans démarrer de service :
systemctl --user daemon-reload

Le lot user publie trois fichiers lanceur, le service et son lien dédié, et le seul adaptateur QML canonique. Le lot root publie ensuite les quatre fichiers V1 autorisés. Les deux bundles complets sont synchronisés avant toute mutation : sauvegardes, manifestes, outils autonomes, coordinateur, seals/protected et journaux existants, puis bundle et chaque ancêtre jusqu’à /. Le coordinateur exécute la barrière user sous UID/verrou user avant son premier journal global. Une erreur de cette barrière interdit toute publication et ne déclenche aucun rollback mutateur. Les transactions autonomes possèdent également leur barrière. Verrou root global, verrou user et journaux permettent la reprise. Chaque fichier est publié par rename puis relu ; le lot multi-fichiers n'est pas une opération atomique unique. Une erreur ordinaire restaure les deux sous-lots dans l'ordre inverse ; si une restauration est empêchée, les deux sont tentées et le journal reste rolling-back. Après arrêt brutal, le prochain apply restaure et s'arrête pour vérification/nouvel essai. Aucun outil ne recharge/redémarre greetd, ne ferme une session ou ne démarre UWSM/QuickShell. Conserver les copies durables jusqu'à validation physique puis décision explicite de suppression ; le LAB peut alors être archivé séparément. Une panne peut laisser un temporaire caché dans une cible ; il n'est jamais un module chargé et exige inspection avant suppression.

Premier essai et secours indépendant

Après installation approuvée : sauvegarder le travail, fermer volontairement SwayFX au moment choisi, retrouver Labfy, garder Stable ou choisir explicitement Mosaic avant le mot de passe. L'essai attendu est Mosaic autonome + QuickShell

  • Kitty de récupération. Vérifier alors barre, notifications, identité des sockets, puis quitter Mosaic avec Super+Shift+E et choisir Stable sur Labfy. Ce parcours complet est NOT_RUN. Ne pas verrouiller l'écran pendant ce smoke.

En cas de panne : Ctrl+Alt+F2, login console. Après fermeture de la session graphique défaillante, un retour Stable explicite ne dépend ni du launcher Mosaic ni de la préférence ni d'un ancien socket :

# Procédure manuelle APRÈS approbation, depuis console sans parent graphique :
exec /usr/bin/uwsm start sway.desktop

Si les fichiers publiés doivent être restaurés, depuis TTY2 et sans nouvelle connexion concurrente :

sudo python3 -I -B /var/lib/labfy-greeter/login-recovery-v2/login-recovery-update.py rollback
systemctl --user daemon-reload

Le rollback n'exige ni binaire/LAB Mosaic ni IPC, et ne change pas default-id. Si le sous-lot utilisateur est divergent/inaccessible, le secours greeter reste indépendant :

sudo python3 -I -B /var/lib/labfy-greeter/login-recovery-v2/session-update.py \
  rollback /var/lib/labfy-greeter/login-recovery-v2
# Restauration user indépendante, sans importer le lanceur Mosaic :
python3 -I -B /home/fy59/.local/state/labfy-greeter-mosaic-login-v2/v2/mosaic-user-update.py \
  rollback /home/fy59/.local/state/labfy-greeter-mosaic-login-v2/v2

L'ancien greeter restauré utilise start default ; pour un secours indépendant de cette préférence, utiliser la commande Stable explicite ci-dessus. Aucun redémarrage greetd ou du PC n'est automatique ; une action de récupération supplémentaire doit être décidée par l'utilisateur. Aucun secours ne dépend du dépôt source ou de /var/tmp après promotion durable.

Aucun commit/push. Aucune modification du dépôt Mosaic, du moteur, PAM, config Sway Stable, unité QuickShell Stable ou préférence UWSM. Le candidat temporaire CORE-C V2 reste expérimental et refuse son lancement si sa copie disparaît.