Tag 1 abgeschlossen

This commit is contained in:
Christoph Schwörer
2026-08-26 08:19:33 +02:00
parent f045b99a25
commit 7df384f6d2
77 changed files with 7456 additions and 3311 deletions
+137 -16
View File
@@ -2,7 +2,7 @@
name: run-experiment
description: Führt einen Versuchs-Prompt aus einer Prompt-Datei als messbaren Headless-Lauf aus (claude -p) und schreibt ein Messprotokoll mit Start-/Endzeit, Modell, Tokenverbrauch und weiteren Metriken. Verwenden bei "/run-experiment <Pfad-zur-Prompt-Datei>" oder wenn der User einen Versuch/ein Experiment ausführen und tracken will.
argument-hint: <Pfad zur Prompt-Datei> <Root-Verzeichnis>
version: 3.10.0
version: 4.0.0
---
# RunExperiment – Versuchslauf mit Messprotokoll
@@ -72,7 +72,22 @@ gilt das Protokoll.
für parallele Läufe (siehe „Parallele Läufe") und archiviert nebenbei den exakt gesendeten
Prompt je Lauf. `Ergebnisse\` enthält ausschließlich die vom Prompt geforderten Artefakte.
## Ablauf
## Aufbau dieses Skills
Der Skill ist zweigeteilt:
- **`## Prozess`** beschreibt werkzeugneutral, **was** je Lauf zu tun und zu erheben ist. Dieser
Teil gilt unabhängig davon, mit welchem LLM oder welcher CLI gearbeitet wird.
- **`## Werkzeugadapter`** beschreibt **wie** das mit einem konkreten Werkzeug umgesetzt wird.
Derzeit ist nur der Adapter für Claude Code ausgearbeitet.
**Arbeitsteilung mit der Prompt-Datei:** Der Prompt enthält ausschließlich die *Analyseanweisung*
und ist damit von jedem LLM verwendbar. Alles Werkzeug- und Ablaufbezogene – verfügbare
Werkzeuge, Ausgabeverzeichnis, Messgrößen – steuert dieser Skill bei und dokumentiert es im
Protokoll. Die Prompt-Datei wird dabei **nie verändert**; ergänzende Blöcke werden nur an den
per stdin übergebenen Text angehängt (siehe Schritt „Prompt zusammenstellen").
## Prozess
### 1. Vorbereitung
@@ -177,7 +192,7 @@ Prompt je Lauf. `Ergebnisse\` enthält ausschließlich die vom Prompt geforderte
```powershell
# Bedingungen werden Ordnerebenen, nicht Namensbestandteile
$zelle = Join-Path (Join-Path $modell $modus) $effort
$skillVer = 'v3.10.0' # entspricht version: im Frontmatter dieses Skills
$skillVer = 'v4.0.0' # entspricht version: im Frontmatter dieses Skills
do {
$id4 = '{0:x4}' -f (Get-Random -Maximum 65536)
$lauf = Join-Path "<promptverzeichnis>\$zelle" "<NN>_Lauf_$(Get-Date -Format 'yyyy-MM-dd_HHmmss')_${skillVer}-$id4"
@@ -232,11 +247,34 @@ committet und im Protokoll dokumentiert.
**Das Remote ist entkoppelt.** Im Codebasis-Repo wird niemals gepusht, gefetcht oder ein Remote
hinzugefügt. Der Snapshot bleibt eingefroren.
### 2. Ausführung (Headless-Lauf)
### 2. Prompt zusammenstellen
Dem Prompt eine Ausgabe-Anweisung anhängen, damit die Ergebnisse im Laufverzeichnis landen
und nicht im Root. Dazu den Prompttext um einen Abschnitt ergänzen (Prompt-Datei selbst
NICHT verändern – nur den per stdin übergebenen Text):
Dem Prompttext werden **zwei** Blöcke angehängt. Die Prompt-Datei selbst bleibt unverändert –
ergänzt wird nur der per stdin übergebene Text, und dieser wird als `_meta\combined_prompt.md`
archiviert.
**Block 1 – Werkzeugkontext.** Der Prompt trifft bewusst keine Annahme darüber, welche Werkzeuge
zur Verfügung stehen. Diese Bedingung stellt der Versuchsaufbau bei; sie ist die untersuchte
unabhängige Variable und gehört deshalb hierher, nicht in die Analyseanweisung:
```
### Werkzeugkontext (vom Versuchsaufbau vorgegeben)
Für diesen Lauf stehen zur Verfügung: <Auflistung>.
Nicht verfügbar sind: <Auflistung>.
Triff keine Annahmen über weitere Werkzeuge und versuche nicht, nicht verfügbare
Werkzeuge zu ersetzen.
```
Der Inhalt richtet sich nach dem Agentenmodus:
| Modus | „Zur Verfügung" | „Nicht verfügbar" |
|---|---|---|
| `solo` | Lesen, Suchen und Ausführen von Kommandozeilenbefehlen im Arbeitsverzeichnis | Subagenten, spezialisierte Agentenrollen, externe Werkzeugserver |
| `builtin` | zusätzlich die werkzeugeigenen Subagenten | spezialisierte Agentenrollen aus Konfigurationsdateien, externe Werkzeugserver |
| `custom` | zusätzlich die beigestellten Agentenrollen (namentlich nennen) | externe Werkzeugserver, sofern nicht Teil des Versuchs |
**Block 2 – Ausgabeverzeichnis.** Damit die Ergebnisse im Laufverzeichnis landen und nicht in
der Codebasis:
```
### Ausgabeverzeichnis (überschreibt anderslautende Pfadangaben oben)
@@ -245,6 +283,8 @@ Schreibe ALLE zu erzeugenden Ergebnisdateien in das Verzeichnis
Verändere keine Dateien im Arbeitsverzeichnis (der analysierten Codebasis).
```
### 3. Ausführung (Headless-Lauf)
Dann den kombinierten Prompt per stdin an `claude -p` übergeben. `--add-dir` gibt dem
Headless-Lauf Schreibrecht auf das Laufverzeichnis außerhalb seines Arbeitsverzeichnisses.
Versuchsläufe können lange dauern – **immer als Background-Task starten** (`run_in_background`),
@@ -347,7 +387,7 @@ Regeln:
der Tokenverbrauch. Anhaltspunkt: Der bisher aufwendigste Lauf verbrauchte 55.167.397 Tokens.
- Nach Abschluss des Background-Tasks: Endzeit mit `Get-Date -Format o` erfassen.
### 3. Ergebnis auswerten
### 4. Ergebnis auswerten
`RawResult.json` im Laufverzeichnis lesen und defensiv parsen (Feldnamen können je nach Claude-Code-Version
leicht abweichen). Relevante Felder:
@@ -472,6 +512,16 @@ aus `Ergebnisse\StRS.md`, `SyRS.md` und `SwRS.md` und schreibt `_metanforderung
Abrechnung, Berechtigungen brauchen `PRIMÄR` **oder** `[HYPOTHESE]`), Verifizierbarkeit
(Prüfidee vorhanden), Traceability (Tracelinks gesetzt)
**Zuordnung zum Evaluationsrahmen (Kap. 4.3).** Die erhobenen Kenngrößen decken die
**maschinell prüfbare** Hälfte der drei Qualitätsdimensionen ab; die Expertenbewertung nach
Likert-Skala bleibt davon unberührt und tritt daneben:
| Dimension (Kap. 4.3) | Maschinell erhoben | Bleibt der Expertenbewertung |
|---|---|---|
| **Statement-Qualität** | Belegqualität, Primärbelegquote, Anteil mit Prüfidee, Hypothesenanteil, Übernahmewürdigkeit | Eindeutigkeit der Formulierung, sachliche Korrektheit, Verständlichkeit |
| **Set-Qualität** | Verteilung über die Ebenen, Konsolidierungskandidaten, doppelte IDs, Anforderungen ohne Beleg | Vollständigkeit der Prozessabdeckung, Redundanzfreiheit im fachlichen Sinn |
| **Traceability-Qualität** | Anteil mit Tracelinks, Belegklassifikation, Tracelinks auf nicht existierende IDs | Auffindbarkeit des Belegs, Nachvollziehbarkeit der Ableitung |
**Warum das erhoben wird:** Die Anforderungsanzahl allein ist als Qualitätsmaß wertlos – sie
streute über Läufe gleicher Bedingung um Faktor 5,9. Belegdichte, Primärbelegquote und
Regelverstöße sind dagegen inhaltliche Größen und machen Läufe vergleichbar, deren Mengengerüst
@@ -488,7 +538,7 @@ ins Protokoll. Beim Vergleich Zeilenenden
normalisieren (`before.txt` entsteht je nach Werkzeug mit CRLF, der Nachher-Stand mit LF),
sonst meldet ein naiver `diff` alle Zeilen als geändert.
### 4. Messprotokoll schreiben
### 5. Messprotokoll schreiben
Als `Protokoll.md` ins Laufverzeichnis, neben `RawResult.json` und `Stderr.log`.
@@ -522,6 +572,10 @@ Vorlage:
- **Parallele Läufe:** <nein | ja: welche Laufverzeichnisse liefen zeitgleich>
- **Agentenmodus:** <solo (V1) | builtin (V1b) | custom (V2)>; bei `custom` zusätzlich
Pfad und SHA-256 der Agentendefinitionen
- **Kontextfenster:** <Tokens, z. B. aus `modelUsage.contextWindow`>
- **Sampling-Parameter:** <Temperatur u. a. | nicht steuerbar>
- **Nur bei lokalem Modellbetrieb:** Inferenz-Runtime samt Version, Quantisierungsstufe des
Modell-Builds
- **Permission-Mode:** <acceptEdits | ...>
- **Toolfreigabe:** `--allowedTools <wörtlich>` / `--disallowedTools <wörtlich>`
- **Isolationsmechanismus:** <--safe-mode, --strict-mcp-config, ggf. --setting-sources>
@@ -531,6 +585,16 @@ Vorlage:
Bei `max_depth` > 1 ausdrücklich vermerken – die Tokens der tieferen Ebenen sind in
„Tokens gesamt" enthalten, ihre Prompts jedoch **nicht** in `_meta\subagenten.md`
## Validierungsstichprobe
- **Größe:** <vor Versuchsbeginn festgelegte Anzahl Anforderungen>
- **Ziehungsverfahren:** <Zufallsstichprobe über alle Ebenen | ...>
- **Validatoren:** <Anzahl und fachlicher Zuschnitt>
- **Stand:** <noch nicht gezogen | gezogen am <Datum> | ausgewertet>
Kapitel 4.3 verlangt, die Stichprobengröße **vor** Versuchsbeginn festzulegen und im
Versuchsprotokoll zu dokumentieren. Ist für den Lauf keine Validierung vorgesehen, hier
`entfällt` eintragen – das Feld darf nicht fehlen.
## Verbrauch
### Hauptagent (`usage`)
@@ -576,12 +640,59 @@ Status, Regelkonformität>
- **Anmerkungen/Auffälligkeiten:** <Beobachtungen, Abbrüche, manuelle Eingriffe>
```
### 5. Abschlussbericht an den User
### 6. Abschlussbericht an den User
Kurz zusammenfassen: Status, Dauer, Tokenverbrauch (inkl. Cache), Modell, Pfad des
Laufverzeichnisses und welche Dateien der Lauf erzeugt hat. Bei `is_error` oder leerem
Ergebnis: `Stderr.log` und `RawResult.json` zitieren, nicht spekulieren.
## Werkzeugadapter
Der Prozess oben ist werkzeugneutral. Dieser Abschnitt hält fest, wie er mit einem konkreten
Werkzeug umgesetzt wird und welche Messgrößen dieses Werkzeug liefert.
### Adapter: Claude Code
Der einzige derzeit ausgearbeitete Adapter. Alle konkreten Aufrufe, Flags und Feldnamen im
Prozessteil beziehen sich auf ihn; er wurde gegen **CLI 2.1.245** entwickelt und verifiziert.
**Gelieferte Messgrößen** – vollständig aus `RawResult.json`:
| Messgröße | Feld |
|---|---|
| Abbruchstatus | `is_error`, `subtype`, `stop_reason`, `terminal_reason` |
| Dauer | `duration_ms`, `duration_api_ms` (Wanduhr wird selbst gemessen) |
| Tokens Hauptagent | `usage.*` inkl. `output_tokens_details.thinking_tokens` |
| Tokens gesamt inkl. aller Subagenten-Ebenen | `modelUsage` je Modell-ID |
| Tatsächlich eingesetzte Modelle | Schlüssel von `modelUsage` |
| Verweigerte Werkzeugaufrufe | `permission_denials` |
| Subagenten | `subagent_stats` inkl. `spawned_by_subagents`, `max_depth`, `failed` |
| Sitzungskennung für Transcript-Analyse | `session_id` |
**Nicht erfasst:** Sampling-Parameter wie Temperatur sind über die CLI nicht steuerbar und
werden nicht ausgewiesen; der Effort steht **nicht** in `RawResult.json` und ist nur über das
Session-Transkript belegbar (siehe Schritt 6 der Vorbereitung).
### Weitere Adapter (für Versuch 4 nachzurüsten)
Kapitel 4 der Arbeit sieht einen LLM-Querschnitt über Codex CLI, Qwen Code CLI über LM Studio
und DeepSeek über die Cloud-API vor. Diese Adapter sind noch nicht ausgearbeitet. Damit ein
Lauf als Messpunkt taugt, muss ein Adapter mindestens liefern:
| Pflichtangabe | Zweck |
|---|---|
| Modell-ID und Kontextfenster | Bedingung dokumentieren |
| Input- und Output-Tokens | Aufwandsvergleich |
| Dauer | Aufwandsvergleich |
| Abbruchstatus | Gültigkeit des Laufs |
| Erzeugte Artefakte | Ertrag |
| Sampling-Parameter, soweit steuerbar | Reproduzierbarkeit (Kap. 4.3) |
| Bei lokalem Betrieb: Runtime samt Version, Quantisierungsstufe | Reproduzierbarkeit (Kap. 4.3) |
Was ein Adapter nicht liefern kann, wird im Protokoll ausdrücklich als `nicht erfasst`
ausgewiesen – niemals geschätzt. Fehlen mehrere Pflichtangaben, ist der Lauf nur eingeschränkt
mit Claude-Code-Läufen vergleichbar; das gehört in die Anmerkungen des Protokolls.
## Randbedingungen
- Niemals Messwerte schätzen oder erfinden – fehlt ein Feld im JSON, im Protokoll als
@@ -638,6 +749,7 @@ der Historie unten – im selben Arbeitsschritt.
| **3.8.0** | **Pflichtprüfung der tatsächlich eingesetzten Modelle.** `modelUsage` ist nach jedem Lauf gegen das angeforderte Modell abzugleichen; neue Protokollfelder „Modell (angefordert)", „Modelle (tatsächlich eingesetzt)" und „Kontrolle Modell". | `--model` steuert nur den Hauptagenten. Im Lauf `fable5_builtin_ehigh_v3.7.0-15db` liefen die 13 Subagenten auf `claude-opus-5[1m]` statt auf Fable – 91 % des Verbrauchs entfielen auf ein nicht angefordertes Modell, und der Lauf wurde mit 150,3 Mio. Tokens der teuerste der Reihe. Ohne diese Prüfung bleibt die Bedingungsverletzung unbemerkt. | ab sofort; Gegenprüfung der 23 Vorläufe ergab keine weiteren Fälle |
| **3.9.0** | **Pflichtabschnitt „Gefundene Anforderungen" im Protokoll.** Neues Skript `analyse-anforderungen.py` wertet die erzeugten Anforderungen aus: Verteilung, Typen, Belegqualität (`PRIMÄR`/`SEKUNDÄR`/`KONTEXT`), Status, Konsolidierungskandidaten und **Regelkonformität gegen die Vorgaben des Prompts**. | Die Protokolle maßen bis dahin nur den Aufwand, nicht den Ertrag. Die reine Anforderungsanzahl taugt nicht als Qualitätsmaß (Streuung Faktor 5,9 bei gleicher Bedingung); Belegdichte und Regelverstöße sind inhaltliche Größen. Erste Anwendung deckte sofort Verstöße gegen die risikobasierte Priorisierung auf. | rückwirkend auf alle 24 Protokolle angewandt |
| **3.10.0** | **Bedingungen als Ordnerstruktur statt im Dateinamen.** Ablage unter `<ModellID>\<Agentenmodus>\<Effort>\`; der Verzeichnisname lautet wieder `<NN>_Lauf_<yyyy-MM-dd_HHmmss>_v<skillversion>-<id4>`. Neues Protokollfeld „Ablage". | Der Name wuchs mit jeder unabhängigen Variable und war mit fünf Bestandteilen kaum lesbar. Als Ordnerebenen sind die Bedingungen navigierbar, je Zelle unmittelbar abzählbar und um weitere Variablen erweiterbar, ohne bestehende Namen zu brechen. | rückwirkend auf alle 24 Läufe angewandt |
| **4.0.0** | **Ausrichtung auf Kapitel 4 der Arbeit.** Skill zweigeteilt in `## Prozess` (werkzeugneutral) und `## Werkzeugadapter` (konkrete Aufrufe, derzeit nur Claude Code). Der Prompt trägt nur noch die Analyseanweisung; Werkzeugkontext und Ausgabeverzeichnis werden zur Laufzeit angehängt. Versuchszuordnung korrigiert: **V1 = `solo`, V1b = `builtin`**. Neue Protokollfelder: Kontextfenster, Sampling-Parameter, lokale Runtime-Angaben, Abschnitt Validierungsstichprobe. Abschnitt „Gefundene Anforderungen" den drei Qualitätsdimensionen zugeordnet. | Prompt und Skill waren über 24 Läufe organisch gewachsen und stellenweise nicht mehr deckungsgleich mit Kap. 4. Der Prompt enthielt Aussagen zur Werkzeugkonfiguration, die dort nicht hingehören und ihn an Claude Code banden; der Skill verankerte weder den Evaluationsrahmen noch die von Kap. 4.3 geforderten Reproduzierbarkeitsangaben. MAJOR, weil sich die Zuordnung der Versuchsbedingungen ändert. | ab sofort |
## Parallele Läufe
@@ -671,13 +783,22 @@ verwenden.
## Zuordnung Versuch ↔ Agentenmodus
Nach Kapitel 4 der Arbeit (Versuchsdesign):
| Versuch | Modus | Bedeutung |
|---|---|---|
| **V1** – Baseline (Prompt-only) | `solo` | Ein Thread, ein Kontext; keine Subagenten |
| **V1b** – Baseline mit internen Agenten | `builtin` | Eingebaute Subagenten (`Explore`, `general-purpose`) |
| **V2** – Agentengestützt | `custom` | Nur vordefinierte, geprompte Agenten aus `--agents` |
| **V1b** – Baseline mit werkzeugeigenen Agenten | `builtin` | Eingebaute Subagenten des Werkzeugs zugelassen |
| **V2** – Agentengestützt | `custom` | Rollenspezialisierte Agentendateien: Stakeholder, System, Software, ISO-29148-Orchestrator |
| **V3** – Werkzeugzugriff | `custom` + MCP | Wie V2, zusätzlich externe Werkzeugserver |
**Einordnung der bisherigen Läufe:** Die Läufe 1–6 in `Versuche/Versuch_01/` liefen sämtlich mit
eingebauten Subagenten und gehören damit fachlich zu **V1b**, nicht zu V1. Sie belegen weiterhin
die Laufvarianz unter `builtin`, sind aber keine Baseline-Messung im Sinne der neuen Definition.
Bei der Auswertung entsprechend zuordnen.
**Abgrenzung V1 gegen V1b.** Die Arbeit unterscheidet zwischen *Agentendateien* (V2) und den
*werkzeugeigenen* Subagenten, die eine CLI von sich aus mitbringt. Letztere sind keine
Konfigurationsartefakte und damit nach dem Wortlaut von V1 nicht ausgeschlossen – ihr Einsatz
verändert die Ergebnisse jedoch erheblich. V1b trennt beide Fälle, sodass der Effekt der
werkzeugeigenen Delegation getrennt vom Effekt der rollenspezialisierten Agentendateien
messbar wird.
**Bisherige Läufe.** Die 24 Läufe in `Versuche/Versuch_01/` verteilen sich auf V1 (`solo`) und
V1b (`builtin`). Die Ordnerstruktur macht die Zuordnung unmittelbar sichtbar; die Zellen sind
über `ls <ModellID>/<Modus>/<Effort> | wc -l` abzählbar.
@@ -54,6 +54,7 @@ def analysiere(lauf):
konsolidierung=feld(b, 'Konsolidierung'),
pruefidee=feld(b, 'Prüfidee') or feld(b, 'Pruefidee'),
qm=feld(b, 'Qualitätsmerkmal'),
uebernahme=feld(b, 'Übernahmewürdigkeit') or feld(b, 'Uebernahmewuerdigkeit'),
))
return anf
@@ -88,6 +89,20 @@ def abschnitt(anf):
kons = [a for a in anf if a['konsolidierung'] and a['konsolidierung'].lower() != 'nein']
mit_qm = [a for a in anf if a['qm']]
# Uebernahmewuerdigkeit: erst ab Prompt-Fassung 2026-08-26; aeltere Laeufe kennen das Feld nicht
uebern = collections.Counter()
for a in anf:
v = a['uebernahme'].lower()
if not v:
continue
for schl in ('übernehmen', 'workaround', 'sonderfall', 'veraltet'):
if schl in v:
uebern[schl] += 1
break
else:
uebern['(sonstige Angabe)'] += 1
mit_uebern = sum(uebern.values())
risiko = [a for a in anf if RISIKO.search(a['typ'] + ' ' + a['titel'])]
risiko_ungedeckt = [a for a in risiko if 'PRIMÄR' not in a['belege'] and not a['hypothese']]
@@ -97,6 +112,11 @@ def abschnitt(anf):
z = ['## Gefundene Anforderungen', '',
'Maschinell aus `Ergebnisse\\StRS.md`, `SyRS.md` und `SwRS.md` ausgewertet '
'(Blockformat des Prompts). Erzeugt von `analyse-anforderungen.py`.', '',
'Die Kenngrößen decken die **maschinell prüfbare** Hälfte des Evaluationsrahmens aus '
'Kapitel 4.3 ab: Belegqualität und Übernahmewürdigkeit gehören zur *Statement-Qualität*, '
'Verteilung und Konsolidierungskandidaten zur *Set-Qualität*, Tracelinks und '
'Belegklassifikation zur *Traceability-Qualität*. Die Expertenbewertung nach '
'Likert-Skala tritt daneben und wird hier nicht ersetzt.', '',
'### Verteilung über die Ebenen', '',
'| Ebene | Anzahl | Anteil |', '|---|---:|---:|']
for eb in EBENEN:
@@ -122,6 +142,20 @@ def abschnitt(anf):
pct(sum(1 for a in anf if 'PRIMÄR' in a['belege']), n)),
'']
z += ['### Übernahmewürdigkeit', '']
if not mit_uebern:
z += ['**nicht erhoben** – das Feld `Übernahmewürdigkeit` wurde erst mit der '
'Prompt-Fassung vom 2026-08-26 eingeführt und liegt für diesen Lauf nicht vor. '
'Hinweise auf Workarounds stecken ersatzweise im Feld `Status`.', '']
else:
z += ['| Einstufung | Anzahl | Anteil |', '|---|---:|---:|']
for k in ('übernehmen', 'workaround', 'sonderfall', 'veraltet', '(sonstige Angabe)'):
if uebern.get(k):
z.append('| %s | %d | %s |' % (k, uebern[k], pct(uebern[k], n)))
if n - mit_uebern:
z.append('| **ohne Angabe** | %d | %s |' % (n - mit_uebern, pct(n - mit_uebern, n)))
z.append('')
z += ['### Status', '', '| Kategorie | Anzahl | Anteil |', '|---|---:|---:|',
'| belegt | %d | %s |' % (n - len(hyp), pct(n - len(hyp), n)),
'| als `HYPOTHESE` gekennzeichnet | %d | %s |' % (len(hyp), pct(len(hyp), n)),
@@ -145,6 +179,10 @@ def abschnitt(anf):
z.append('| **Verifizierbarkeit** – jede Anforderung mit Prüfidee oder Akzeptanzkriterium | %s |'
% ('**erfüllt**' if not ohne_pruef
else '**verletzt** – %d ohne Prüfidee' % len(ohne_pruef)))
z.append('| **Übernahmewürdigkeit** – Einstufung für die Migrationsperspektive | %s |'
% ('*nicht erhoben* (Feld erst ab Prompt-Fassung 2026-08-26)' if not mit_uebern
else ('**erfüllt** (alle %d Anforderungen eingestuft)' % n if mit_uebern == n
else '**verletzt** – %d von %d ohne Angabe' % (n - mit_uebern, n))))
z.append('| **Traceability** – Verknüpfung zwischen den Ebenen | %d von %d mit Tracelinks (%s) |'
% (n - len(ohne_trace), n, pct(n - len(ohne_trace), n)))
z.append('')