test(calm): name the missing E2E tool and wait for Pi's paint - #2477
Open
Kallas95 wants to merge 2 commits into
Open
test(calm): name the missing E2E tool and wait for Pi's paint#2477Kallas95 wants to merge 2 commits into
Kallas95 wants to merge 2 commits into
Conversation
…tool Pi writes the session file before it paints the transcript, so run_followup_case captured the pane the moment that file settled and could read the screen while it was still on its start-up state. The count of CAPTAIN_ANSWER_<label> was then zero and the assertion reported a duplicate captain answer that never existed. On the adjacent case this failed 9 times in 24 runs, 4 of 12 under bash 3.2.57 and 5 of 12 under bash 5.3.15: the same rate on both, so it was never interpreter dependent. Every captured pane held zero occurrences, and re-capturing 50ms later always showed exactly one. The case now waits for the follow-up answer, which Pi renders after the captain answer, before counting. A genuine duplicate still fails because the count is taken after that anchor and is never satisfied by it. 24 consecutive runs now pass on both interpreters. The three E2E cases also reported "pi or tmux not found" whichever tool was missing. tmux commonly lives outside a trimmed PATH while pi does not, so a run that skipped all three read as a clean nine-check pass. That is how the export defect already fixed in kunchenguid#2461 was misread as a bash 5 regression: the control run removed /opt/homebrew/bin, which removed tmux, which skipped the very case that was failing. The skip now names the tool that is absent.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
Les deux interpreteurs compares dans toute cette tache sont celui livre par Apple, version 3.2.57, et celui installe par Homebrew, version 5.3.15. Ils sont designes ci-dessous par "l'interpreteur 3.2.57" et "l'interpreteur 5.3.15".
Diagnostiquer et corriger l'echec de tests/fm-calm-pi-extension.test.sh, presente comme la SEULE vraie regression de la bascule d'interpreteur sur 146 suites: la suite passait sous l'interpreteur 3.2.57 et echouait sous l'interpreteur 5.3.15 avec "not ok - /export did not complete while calm mode was on".
Mesure d'origine (2026-08-15): interpreteur 3.2.57 avec Homebrew hors PATH -> exit 0, 9 verifications; interpreteur 5.3.15 -> exit 1 sur l'echec /export. Le piege methodologique annonce etait qu'installer le nouvel interpreteur change aussi ce que "env" resout dans les sous-processus, donc le controle devait forcer un PATH sans /opt/homebrew/bin.
Deux hypotheses menant a des corrections OPPOSEES etaient a departager: soit le nouvel interpreteur revelait un vrai defaut latent de l'extension calme que celui d'Apple avalait (corriger le CODE), soit le TEST dependait d'une particularite de l'interpreteur 3.2.57 (corriger le TEST). Consigne explicite: ne pas choisir par confort, charger le skill diagnostic-reasoning avant de conclure, etablir la cause par preuve et non par plausibilite. Element de contexte fourni: sous set -e, l'interpreteur 3.2.57 avale des echecs que le 5.3.15 propage (trois defauts de cette famille trouves le meme jour), ce qui rendait la premiere hypothese serieuse sans la prouver.
Demande: (1) diagnostiquer la cause reelle avec reproduction et controle propre dans les deux sens; (2) corriger la cause etablie, code ou test selon ce que le diagnostic prouve; (3) verifier que la suite passe sous LES DEUX interpreteurs.
Criteres d'acceptation: la cause est etablie par preuve et enoncee explicitement dans la PR (defaut de l'extension calme, ou dependance du test a une particularite de l'interpreteur 3.2.57); tests/fm-calm-pi-extension.test.sh passe sous l'interpreteur 5.3.15 ET sous l'interpreteur 3.2.57 avec un PATH propre; si la cause etait un vrai defaut du code, une verification de non-regression couvre le comportement reel et pas seulement la ligne de test qui echouait; aucune autre suite ne devient rouge.
Hors perimetre explicite, a ne pas corriger: tests/fm-spawn-batch.test.sh (echec identique sous les deux interpreteurs, defaut preexistant sans rapport) et tests/fm-teardown.test.sh (rouge sous les deux, restants couverts par la PR amont 2435 non adoptee localement). Les signaler s'ils changent d'etat, sans les embarquer.
RESULTAT DU DIAGNOSTIC, qui infirme la premisse de la tache: ce n'etait PAS une regression d'interpreteur, et la mesure d'origine comparait deux configurations differant sur DEUX axes au lieu d'un. tmux vit dans /opt/homebrew/bin: retirer ce repertoire du PATH ne neutralise pas seulement le nouvel interpreteur, il fait skipper les 3 tests E2E de la suite, dont precisement celui qui contient l'assertion /export. L'arithmetique le confirme: 12 verifications - 3 skippees = les "9 verifications" rapportees. Le controle dit propre n'a donc jamais execute le test en cause, et aucune preuve de regression d'interpreteur n'existait dans cette mesure.
Contrefactuel decisif: en remettant UNIQUEMENT .pi/extensions/fm-calm.ts a son etat pre-#2461 et en gardant le test de HEAD, l'echec exact "/export did not complete while calm mode was on" se reproduit 2 fois sur 2 sous l'interpreteur 3.2.57, celui cense etre sain. La cause etait donc le vrai defaut de l'extension calme corrige six heures plus tot par ef35d79 (#2461): depuis Pi 0.83.0, setToolsExpanded() emet une ligne de statut, et deux lignes de statut consecutives fusionnent, si bien que le repaint post-export de Calm ecrasait la confirmation "Session exported to: ". A HEAD la suite est verte: 6 runs sur 6 sous les deux interpreteurs. Note: ce fichier de test utilise set -u et non set -e, donc le mecanisme evoque dans le brief ne s'y applique pas.
Consequence sur le perimetre: le defaut d'origine etant deja corrige en amont, il n'y avait pas de correction de code a refaire, et la couverture de non-regression demandee au critere 3 existe deja via ef35d79, qui a ajoute des assertions verifiant que la confirmation reste a l'ecran une fois le redraw stabilise, au-dela de la seule ligne qui echouait. Les deux defauts reels restants ont ete corriges dans ce commit.
Correction 1 - le skip muet: les trois cas E2E annoncaient "pi or tmux not found" quel que soit l'outil reellement absent. tmux vit couramment hors d'un PATH restreint alors que pi non, si bien qu'un run ayant skippe les trois se lisait comme un succes propre a 9 verifications. C'est exactement ainsi que le defaut d'export deja corrige a ete pris pour une regression du nouvel interpreteur. Le skip nomme desormais l'outil absent (verifie: "skip: tmux not found for ...").
Correction 2 - une instabilite preexistante que la mesure d'origine masquait: Pi ecrit le fichier de session avant de peindre le transcript, donc run_followup_case capturait le pane des que ce fichier se stabilisait et pouvait lire l'ecran encore a son etat de demarrage. Le compte de CAPTAIN_ANSWER_ valait alors zero, jamais deux, et l'assertion annoncait pourtant un "duplicate captain answer" inexistant - message trompeur. Mesure sur le cas adjacent: 9 echecs sur 24 runs, soit 4 sur 12 sous l'interpreteur 3.2.57 et 5 sur 12 sous l'interpreteur 5.3.15, taux equivalents donc sans lien avec l'interpreteur; les 9 panes captures contenaient zero occurrence et une recapture 50 ms plus tard en montrait toujours exactement une. Le cas attend desormais la reponse de suivi, que Pi rend apres la reponse du capitaine, avant de compter. Un vrai doublon echoue toujours puisque le comptage a lieu apres cet ancrage et n'est jamais satisfait par lui.
Verification apres correction: cas concerne 24/24 verts contre 15/24 avant; suite complete 6/6 verte sous les deux interpreteurs avec 12 verifications et 0 skip; sous PATH nettoye les deux interpreteurs restent verts avec 3 skips explicitement attribues a tmux; bin/fm-lint.sh vert. Un seul fichier modifie, tests/fm-calm-pi-extension.test.sh, donc aucune autre suite touchee. Pi installe: 0.84.2, plus recent que toutes les versions documentees dans ce test (0.81.1, 0.82.0, 0.83.0).
What Changed
missing_e2e_tools()helper and used it in all three E2E skip messages, which previously reported a fixed"pi or tmux not found"regardless of which tool was actually absent.tmuxcommonly lives outside a trimmed PATH whilepidoes not, so a run that skipped all three E2E cases read as a clean pass - which is how the already-fixed Calm export defect (ef35d79, fix(calm): keep Pi's export confirmation visible under Calm mode #2461) was misread as a bash-version regression rather than a real extension bug.run_followup_casenow waits for the follow-up answer (MONITOR_HANDLED_<label>_ONE) before countingCAPTAIN_ANSWER_<label>. Pi writes the session file before it paints the transcript, so capturing the pane as soon as that file settled could read the screen still in its start-up state: the count was zero, never two, yet the assertion reported a nonexistent "duplicate captain answer". The count is taken only after this anchor holds and is never satisfied by it, so a genuine duplicate still fails. The now-redundantassert_containson that same marker was dropped.wait_for_pane_texthelper that leaves its last capture in the caller'spaneand returns non-zero on timeout, so each wait fails with a message naming the state it was waiting for instead of letting a later, unrelated assertion misreport it.Risk Assessment
✅ Low: Le changement est confine a un seul fichier de test, ne touche aucun code produit ni helper partage, et ses deux corrections (skip nommant l'outil absent, ancrage sur la peinture du pane avant comptage) sont coherentes avec le diagnostic enonce, preservent la garantie anti-doublon et deplacent le point de capture strictement plus tard qu'avant.
Testing
J'ai valide la suite ciblee tests/fm-calm-pi-extension.test.sh sous les deux interpreteurs concernes (3.2.57 d'Apple et 5.3.15 de Homebrew, avec Pi 0.84.2 et tmux 3.7b), en reproduisant d'abord la premisse de la tache puis en la departageant. Le run avec PATH prive de /opt/homebrew/bin sort en exit 0 avec 9 verifications et 3 skips desormais attribues nommement a tmux, ce qui confirme par mesure que le controle d'origine n'executait jamais le test E2E incrimine. En remettant le fichier de test a son etat pre-correctif, l'echec 'rendered a duplicate captain answer' se reproduit 3 fois sur 24 runs a taux comparable entre les deux interpreteurs, et une version instrumentee montre que le pane capture contenait zero reponse capitaine (ecran encore au demarrage de Pi) et une seule 50 ms plus tard, donc un message trompeur et non un vrai doublon. A HEAD la meme fonction passe 24/24 et la suite complete passe 3 fois par interpreteur avec 12 verifications et 0 skip. J'ai aussi injecte un doublon reel dans le fixture pour verifier que la nouvelle attente ne masque rien : l'assertion echoue 6 fois sur 6. La surface concernee est un TUI en terminal : j'ai capture le pane tmux reel avec ses couleurs et produit deux artefacts visuels rendus, dont une comparaison avant/apres de l'ecran au moment de l'echec. Les deux suites hors perimetre ont ete controlees sans etre modifiees et sont vertes. Le worktree est propre, les variantes de test temporaires ont ete supprimees.
Evidence: Meme comparaison en HTML rendu (source de l'image ci-dessus)
Source: Meme comparaison en HTML rendu (source de l'image ci-dessus)
Evidence: Diagnostic instrumente de la version pre-correctif : ce que contenait vraiment le pane quand le test annoncait un doublon
Source: Diagnostic instrumente de la version pre-correctif : ce que contenait vraiment le pane quand le test annoncait un doublon
DIAG cas=adjacent | CAPTAIN_ANSWER dans le pane capture=0 | 50ms plus tard=1 | MONITOR_HANDLED dans le pane capture=0 | 50ms plus tard=1 DIAG premieres lignes non vides du pane capture: pi v0.84.2| escape interrupt · ctrl+c/ctrl+d clear/exit · / commands · ! bash · ctrl+o more| Press ctrl+o to show full startup help and loaded resources.| not ok - Pi follow-up adjacent case rendered a duplicate captain answerEvidence: Runs repetes avant/apres correctif de test_operational_followup_turn_e2e
Source: Runs repetes avant/apres correctif de test_operational_followup_turn_e2e
=== version PRE-FIX (ef35d79) === run 01 FAIL: not ok - Pi follow-up adjacent case rendered a duplicate captain answer run 08 FAIL: not ok - Pi follow-up adjacent case rendered a duplicate captain answer prefix (bash 3.2.57): 10/12 green, 2 red run 03 FAIL: not ok - Pi follow-up adjacent case rendered a duplicate captain answer prefix (bash 5.3.15): 11/12 green, 1 red === version HEAD (adce327) === head (bash 3.2.57): 12/12 green, 0 red head (bash 5.3.15): 12/12 green, 0 redEvidence: Un doublon reellement peint fait toujours echouer l'assertion malgre la nouvelle attente
Source: Un doublon reellement peint fait toujours echouer l'assertion malgre la nouvelle attente
bash 3.2.57 run 1 -> exit 1 | not ok - Pi follow-up adjacent case rendered a duplicate captain answer bash 3.2.57 run 2 -> exit 1 | not ok - Pi follow-up adjacent case rendered a duplicate captain answer bash 3.2.57 run 3 -> exit 1 | not ok - Pi follow-up adjacent case rendered a duplicate captain answer bash 5.3.15 run 1 -> exit 1 | not ok - Pi follow-up adjacent case rendered a duplicate captain answer bash 5.3.15 run 2 -> exit 1 | not ok - Pi follow-up adjacent case rendered a duplicate captain answer bash 5.3.15 run 3 -> exit 1 | not ok - Pi follow-up adjacent case rendered a duplicate captain answerEvidence: Suite complete sous les deux interpreteurs, PATH normal et PATH nettoye
Source: Suite complete sous les deux interpreteurs, PATH normal et PATH nettoye
bash 3.2.57 | runs 1-3 | exit 0 | 12 verifications | 0 skip bash 5.3.15 | runs 1-3 | exit 0 | 12 verifications | 0 skip === PATH prive de /opt/homebrew/bin (le 'controle propre' de la mesure d'origine) === skip: tmux not found for Pi operational follow-up E2E skip: tmux not found for Pi Calm hidden-block geometry E2E skip: tmux not found for Pi calm interactive E2E verifications reellement executees: 9 (12 moins les 3 E2E skippes), exit 0 sous les deux interpreteursEvidence: Le skip nomme l'outil E2E reellement absent dans les trois configurations
Source: Le skip nomme l'outil E2E reellement absent dans les trois configurations
--- tmux absent, pi present --- skip: tmux not found for Pi operational follow-up E2E --- pi absent, tmux present --- skip: pi not found for Pi operational follow-up E2E --- pi et tmux absents --- skip: pi and tmux not found for Pi operational follow-up E2EPipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
tests/fm-calm-pi-extension.test.sh:1845- Le chemin de timeout de la nouvelle boucle d'ancrage reproduit le diagnostic trompeur que le commit visait a supprimer. La boucle 1838-1844 sort aussi apres 120 iterations (6 s) sans avoir trouve MONITOR_HANDLED_<label>ONE ;panecontient alors la derniere capture non peinte, le compte de CAPTAIN_ANSWER<label> vaut 0, et la ligne 1846 echoue avec "Pi follow-up <label> case rendered a duplicate captain answer" alors qu'aucun doublon n'existe. Commefail(tests/lib.sh:44) faitexit 1, l'assertion exacte de la ligne 1848 ("did not render the intended processing result") n'est jamais atteinte. Correction : deplacerassert_contains "$pane" "MONITOR_HANDLED_${label}_ONE"(ligne 1848) juste apres la boucle, avant le comptage de la ligne 1845 - c'est deja l'ordre retenu parreplay_exact_case(assertion ligne 1953 avant l'exploitation du pane) et par la boucle du composeur pret (re-verification explicite lignes 1814-1815).tests/fm-calm-pi-extension.test.sh:1838- La boucle d'attente sur capture-pane existe maintenant en trois exemplaires identiques dans la meme fonction : lignes 1807-1813 (composeur pret), 1838-1844 (nouvelle) et 1946-1952 (replay_exact_case) - seule la chaine recherchee change. Un helper local du typewait_for_pane_text <needle>positionnantpane(pendant quewait_for_text, ligne 52, reste la variante fichier avec -S -600) supprimerait la triple duplication et garantirait que le delai et la re-verification restent coherents entre les trois sites.🔧 Fix: name the unpainted pane and share the wait helper
1 info still open:
tests/fm-calm-pi-extension.test.sh:1848- Les deuxassert_contains "$pane" "MONITOR_HANDLED_..."remplaces parwait_for_pane_text ... || fail ...(1848-1849 et 1951-1952) perdent le dump de l'ecran.assert_contains(tests/lib.sh:266-271) joint "--- output ---" suivi du contenu complet de$paneau message d'echec ;failseul (tests/lib.sh:44) n'imprime que la ligne. Scenario concret ou la difference se voit : Calm masque a tort la ligne de traitement alors que la reponse capitaine est bien unique - avant, le flux atteignaitassert_contains ... MONITOR_HANDLED_${label}_ONEet l'echec CI contenait l'ecran tmux entier ; desormais l'attente expire et le rapport se reduit a "never painted the follow-up answer on screen before the wait expired", sans aucune trace de ce qui etait reellement affiche. Pour un E2E dont l'echec est rarement reproductible en local, c'est le seul element de diagnostic. Correction : passer$panedans les deux messages defail, par exemplefail "..."$'\n'"--- output ---"$'\n'"$pane"(le helper laisse deja la derniere capture danspanesur le chemin de timeout). Cela ne touche ni l'ordre ancrage-puis-comptage ni la specificite des messages exigee.tests/fm-spawn-batch.test.sh- Changement d'etat des deux suites explicitement hors perimetre : tests/fm-spawn-batch.test.sh (5 verifications, exit 0) et tests/fm-teardown.test.sh (58 verifications, exit 0) sont vertes localement sous les deux interpreteurs, alors que l'intent les annonce rouges. Rien n'a ete modifie pour elles ; simple signalement demande par le brief./bin/bash tests/fm-calm-pi-extension.test.shet/opt/homebrew/bin/bash tests/fm-calm-pi-extension.test.sh: 3 runs par interpreteur, exit 0, 12 verifications, 0 skipMeme suite avec un PATH prive de /opt/homebrew/bin sous les deux interpreteurs : exit 0, 9 verifications executees, 3 skipsskip: tmux not found for ...Nommage du skip dans les trois configurations d'outils (tmux absent, pi absent, les deux absents) via des PATH construits avec shims node/npm/git :skip: tmux not found,skip: pi not found,skip: pi and tmux not foundReproduction pre-correctif :test_operational_followup_turn_e2eisole depuisgit show ef35d79:tests/fm-calm-pi-extension.test.sh, 12 runs par interpreteur -> 10/12 et 11/12 verts, echecsnot ok - Pi follow-up adjacent case rendered a duplicate captain answerMeme fonction a HEAD (adce327), 12 runs par interpreteur -> 24/24 vertsVersion pre-correctif instrumentee : dump du pane fige au moment du comptage (0 occurrence de CAPTAIN_ANSWER_adjacent, ecran de demarrage Pi) et recapture 50 ms plus tard (1 occurrence)Mutation de non-regression : fixture followup-e2e.ts modifie pour peindre une vraie reponse capitaine dupliquee ->not ok - ... rendered a duplicate captain answer3/3 sous chaque interpreteurtimeout 300 bash tests/fm-spawn-batch.test.shettimeout 420 bash tests/fm-teardown.test.shsous les deux interpreteurs (controle d'etat des suites hors perimetre)docs/calm-mode-feasibility.md:16- Suivi hors périmètre : docs/calm-mode-feasibility.md « Compatibility evidence » ne mentionne que Pi 0.81.1 et 0.82.0 et conclut qu'aucune API de présentation pertinente n'a été introduite. Depuis le commit de base ef35d79 (fix(calm): keep Pi's export confirmation visible under Calm mode #2461), il est établi que Pi 0.83.0 a introduit un status line sur setToolsExpanded qui cassait la confirmation /export sous Calm. Ce fait n'est découvrable que dans l'enregistrement daté « 2026-08-15 Pi 0.84.1 export-confirmation verification » en fin de document. Rien n'est faux au sens strict (la phrase est bornée aux deux versions nommées), et la lacune n'est pas causée par ce diff, qui ne touche que tests/fm-calm-pi-extension.test.sh. Un pointeur d'une ligne depuis la section « Compatibility evidence » vers cet enregistrement rendrait l'évidence 0.83.0+ découvrable sans dupliquer la prose. Laissé de côté ici pour respecter la discipline de périmètre.✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.