Da `\def` nicht expandiert, enthält `\textstring` nach dem ersten `\expandafter\def…` ein `\system`. Das wird dann von Dir umdefiniert. Also ändert sich damit auch die Ausgabe von `\textstring`. Lerne den Unterschied zwischen `\def`, `\edef`, `\protected@edef` etc. Es gibt dazu AFAIK auch schon eine Frage.
Übrigens: Bei Verwendung von `\edef` oder (besser) `\protected@edef` brauchst du kein `\expandafter`:
\documentclass[12pt]{article}
\begin{document}
% 0. Definiere TextString
\newcommand{\textstring}{}
% 1. Definiere Variablen
\edef\system{System 1: }
\edef\notiz{Online; }
% 2. Konkatiniere den String
\edef\textstring{\textstring { }\system \notiz}
% 3. Ausgabe zu Testzwecken
\textstring
% Wiederhole Schritt 1-3 beliebig oft
\edef\system{System 2: }
\edef\notiz{Offline; }
\edef\textstring{\textstring { }\system \notiz}
\textstring
\end{document}
[![alt text][1]][1]
Allerdings geht das natürlich in die Hose, wenn `\system` oder `\notiz` etwas enthält, was nicht voll expandierbar ist.
Und dann wären da noch die Sequenzen in [LaTeX3](https://ctan.org/pkg/l3kernel), die sich für so etwas ebenfalls anbieten.
[1]: https://i.imgur.com/SxA5qSb.png