Dotfiles_ArchAP/docs/session-v2-path-stability-diagnostic.md

183 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Premier login V2 : chemins de feuilles après Guard
## Résultat et portée
Correction minimale dans la seule copie
`/tmp/labfy-session-v2-path-stability-LrpgZuut`, basée sur
`8a4d829ce78b67fe1d4ff910c89d3278d81b6e85`, sans commit ni déploiement.
La contradiction entre comparaison post-Guard et admission est corrigée.
**Le login graphique physique reste non validé.** Les résultats ci-dessous
concernent des applications GTK synthétiques, deux UUID Firefox synthétiques
stables et des compositeurs enfants TEST_ONLY. Ils ne valident pas les profils
Firefox réels, leurs codecs ni le premier login SwayFX sur le bureau.
Le dernier login réel a échoué **après l’intégration des protections P0**.
Les validations antérieures ne doivent pas masquer cet échec. Les journaux
réels sont préservés : ils n’ont été ni recherchés, ni lus, ni modifiés pendant
cette mission. Les faits réels suivants sont uniquement ceux fournis au ticket.
## Faits reçus et hypothèse
Vers 16:51, refus `TARGET_OBSERVATION_CHANGED`, phase `cleanup-error`,
`operations=0`, `anchors_created=0`, un helper suspendu puis repris.
Recovery avait admis Kitty7 et Firefox8 ; aucun déplacement ni swap n’a eu lieu.
L’échec à l’admission de Firefox10 est vraisemblable, pas établi par une trace
complète de chaque admission.
Le checkpoint comporte quatre slots : en 1,
`splitv(Firefox1, splith(Firefox2, Kitty))`, et Limusic en 10. Les deux Firefox
ont des UUID exacts distincts. La nouvelle session contient Firefox8 et
Firefox10 de même PID, Kitty7 et Limusic5. Des parents internes unaires peuvent
faire passer les chemins, par exemple, de `[0]` à `[0,0]` ou de `[1,0]` à
`[1,0,0]`, sans changer les feuilles, leur ordre ou leur placement.
**Hypothèse forte, non preuve historique :** Sway/autotiling a ainsi décalé les
chemins entre phase 0 et admission. Les chemins exacts de la preuve PREWARM ne
sont pas archivés. La reproduction contrôlée prouve le défaut du code et sa
correction dans ce cas ; elle ne reconstruit pas rétroactivement le login.
## Contradiction et correction
`Executor._check_prepared(before, after)` autorise déjà les variations de
chemin si le lot exact, con_id/PID/starttime/app_id, workspace/output,
flottement, géométrie pertinente et ordre relatif des feuilles restent stables.
Après Guard, `_apply` faisait cette comparaison puis passait à
`Recovery.admit(node, prepared[id])` l’ancien chemin de phase 0.
`admit` exige une égalité complète, chemin inclus : il refusait donc une
variation que le contrôle précédent venait d’accepter.
Le patch conserve l’observation courante post-Guard, la compare au lot de
phase 0, puis l’utilise comme lot canonique pour toutes les admissions initiales.
Chaque admission relit encore strictement son observation épinglée. Le lot
entier est admis avant le premier déplacement. Un changement après cette
capture n’est pas accepté par simple réobservation. Aucun changement à Recovery,
au journal, à la preuve de focus, aux codecs Firefox ou au catalogue n’est requis.
La preuve initiale de focus de phase 0 reste contrôlée strictement à la
création de Recovery. La variante « après phase 0 » injecte après cette
validation, dans la construction d’Anchors avant Guard ; elle ne renouvelle
pas artificiellement la preuve initiale. La variante « pendant Guard » injecte
uniquement après la construction réelle de Guard et avant son retour à
Executor. Les injections vérifient l’identité du focus actif, sans prétendre
que la topologie complète de `focus_proof` est inchangée ni en attribuer la cause.
Un changement avant la validation initiale de cette preuve peut donc toujours
être refusé par `RESTORE_FOCUS_UNSTABLE`.
Après les déplacements possédés, `Recovery.command` actualise les états
`expected`, chemins compris, de toutes les fenêtres admises. Les pins
post-provider sont pris après ces commandes : les nouveaux chemins possédés
sont correctement acceptés. Le provider n’est pas une mutation possédée de
placement : une insertion unaire pendant son attente reste refusée par
l’égalité stricte de `admit`. Aucune relaxation supplémentaire n’a été ajoutée.
## Régressions et résultats
Le test graphique a été écrit et exécuté avant la correction. Sur la baseline,
l’injection pendant Guard produit `TARGET_OBSERVATION_CHANGED`, zéro commande,
zéro ancre et zéro swap. La reproduction des quatre variantes positives a
ensuite été rejouée contre l’Executor de HEAD dans un backend temporaire,
avec le même test final : les quatre refusent avant correction, sans commande.
Ces échecs attendus sont conservés sous `build/path-stability/avant-final/`
et dans `avant-final.log` ; le premier échec est aussi sous `avant/`.
Après correction, les variantes suivantes réussissent sur Sway 1.12/Pixman :
- Parents unaires horizontaux/verticaux autour des trois fenêtres en 1,
uniquement pendant Guard, avec focus actif inchangé.
- Insertion après la preuve de phase 0, avant Guard.
- Insertions réparties entre ces deux frontières.
- Même scénario avec un vrai autotiling enfant, suspendu puis repris une fois.
Chaque succès exige quatre swaps, quatre slots, statut `success`, journal
`complete`, deux vérifications finales vraies, arbre exact en 1 et 10 et
un seul Limusic. Les deux Firefox sont des surfaces du même processus et leurs
UUID exacts sont résolus par un provider synthétique stable.
L’autotiling testé est un enfant privé ; seuls son PID et son socket sont
fournis à la découverte du test. Les splits déterministes sont injectés par le
contrôleur de test. Ce scénario ne prouve pas qu’autotiling a causé le refus réel.
Les deux nouvelles méthodes backend comportent 17 sous-cas de refus à la
frontière Guard ou après la capture canonique : ordre, PID, starttime,
remplacement Firefox8 ou Firefox10 par 21 (mêmes app_id/PID et cardinalité), Firefox
supplémentaire, workspace, output, flottement, focus tiers, Limusic dupliqué,
chemin/identité/membres/focus modifiés après capture et entrée pending.
Elles exigent zéro commande et aucun build d’ancres. Une cinquième expérience
graphique modifie les chemins pendant le provider et exige le refus
`TARGET_OBSERVATION_CHANGED`, zéro swap et aucune commande après cette attente.
Les anciens tests de crash mid-IPC, intentions durables et dernière capture
provider restent inchangés et passent.
Campagne `build/path-stability/campagne/results.json` : **23 groupes réussis**.
| Suite | Résultat |
| --- | --- |
| Backend, anciens P0 et nouvelles frontières | 43 tests OK |
| Focus Python | 28 tests OK |
| QML Python | 13 tests OK |
| QtTest | 5 contrôles OK, aucun ignoré |
| Runtime | 35 scénarios OK |
| Erreurs contrôlées | 3 scénarios OK |
| Crash/SIGKILL | 10 scénarios OK |
| Sécurité | 22 contrôles OK |
| Runtime Limusic | Succès, absence et duplication contrôlés |
| UI QuickShell headless | 7 scénarios OK |
| Anciens login Focus | 11 scénarios OK |
| P0 headless | 5 contre-exemples refusés comme attendu |
| Chemins post-Guard/provider | 4 succès exacts et 1 refus attendu |
Les helpers C sont compilés en C17 avec `-Wall -Wextra -Werror` par les fixtures.
Les contrôles UTF-8 des pages Session V2 et `git diff --check` sont consignés
séparément dans `controles-finaux.log`.
L’essai privé sur le SwayFX installé (`/usr/bin/sway`, GLES2) échoue avant
création du serveur : `drmGetDevices2 failed`, `no DRM FD available`,
`Failed to create renderer`. Le log est `swayfx/resultat.log`.
C’est une **validation fonctionnelle indisponible dans le sandbox**, pas un
PASS SwayFX. Le binaire Sway 1.12/Pixman préexistant sous `/tmp` a permis la
campagne fonctionnelle sans installation ni remplacement système.
## Reproduction sur ArchASP
Depuis cette copie, avec le renderer de l’hôte accessible :
```sh
python3 -B tests/session_v2/validate_p0.py \
--sway /usr/bin/sway --renderer gles2 \
--evidence build/path-stability/hote-swayfx
```
Cette commande inclut les nouveaux tests de chemins et toutes les suites
précédentes. Le harnais définit un environnement positif HOME/XDG privé ; chaque
Lab démarre son compositeur headless enfant, son Wayland et son socket Sway
explicite TEST_ONLY. Il n’utilise pas le socket du bureau. Aucun reload,
logout, redémarrage, changement d’autostart ou de greetd/mosaic n’est requis.
Un refus de renderer garde un code non nul et doit être signalé séparément.
La campagne équivalente réalisable dans ce sandbox est :
```sh
python3 -B tests/session_v2/validate_p0.py \
--sway /tmp/limusic-test-sway-1.12/usr/bin/sway --renderer pixman \
--evidence build/path-stability/reproduction-pixman
```
## Livraison et conditions restantes
`build/path-stability/session-v2-path-stability.patch` contient le patch exact,
y compris les nouveaux tests et cette documentation, sans staging ni commit.
`manifest.json` contient le SHA de base Git, les SHA-256 des fichiers livrés,
du patch et des preuves, les commandes et les résultats. Les artefacts de
construction ne font pas partie du patch. Aucun journal utilisateur réel
n’est inclus.
La correction est bornée à l’incohérence de snapshot démontrée. Une différence
d’identité, membres, placement, ordre, focus externe ou une intention ambiguë
reste bloquante. Le contrôle GET_TREE puis IPC n’est pas atomique : une mutation
postérieure à la dernière observation ne peut être exclue par cette interface.
Les chemins inconnus à la prochaine vérification sont refusés ; un crash après
intention durable conserve le besoin de recovery. Ne pas transformer ces
refus conservateurs en succès par app_id ou cardinalité.
Restent à valider séparément : cette nouvelle version sur le renderer SwayFX
hôte, puis un véritable login graphique physique et les applications réelles.
Aucune action sur la session réelle n’a été effectuée ou autorisée ici.