J'utiliserais TikZ `let` :
\documentclass[french]{article}
\usepackage{babel}
\usepackage{listings}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\usetikzmarklibrary{listings}
\usetikzlibrary{calc}
\begin{document}
\begin{lstlisting}[name=codetest,numbers=left]
boucle:
ab
cd
efghijkl
mn
opqr
stuvw
xyz
\end{lstlisting}
\newcommand{\annotate}[2]{
\draw let
\p1=(#1),
\p2=(firstline)
in (\p1) -- (\x2,\y1) node[right]{#2};
}
\begin{tikzpicture}[remember picture,overlay,<-,transform canvas={yshift=0.7ex}]
\coordinate (firstline) at (7,0 |- {pic cs:line-codetest-1-end});
\annotate{pic cs:line-codetest-1-end}{problème}
\annotate{pic cs:line-codetest-3-end}{échec 2a}
\annotate{pic cs:line-codetest-4-end}{échec 2b}
\annotate{pic cs:line-codetest-5-end}{échec 3}
\annotate{pic cs:line-codetest-6-end}{réussite 1}
\annotate{pic cs:line-codetest-7-end}{réussite 1}
\end{tikzpicture}
problème: le point de départ est defini par tikzmark comme en bas de la ligne: j'aimerais qu'il soit au milieu
échecs 2a et 2b: j'arrive à shifter le point de départ mais pas le point d'arrivée. Je n'arrive à pas décaler le point défini grâce à (7,0 |- {pic cs:line-codetest-4-end}) (que ce soit par shift ou par coordonnées relatives ++)
échec 3: j'essaye de shifter d'un coup le tracé mais ça ne fonctionne pas.
réussites 1 et 2: résultat satisfaisant mais j'ai dû passer par la (re)définition du point de départ.
\end{document}