Testen von megálos-Workflows
1. Umfang und Nicht-Ziele
Diese Fertigkeit lehrt einen KI-Codierungsagenten, wie das Verhalten einer
megálos-Workflow-YAML-Datei überprüft wird, bevor sie ausgeliefert wird. Die primäre Oberfläche ist die
Dry-Run-CLI (python -m megalos_server.dryrun), die einen Workflow
durch die Produktionslaufzeit mit einer simulierten Eingabequelle anstelle eines echten
LLMs führt. Der Dry-Run beantwortet die Frage: „Erhalten diese simulierten Antworten, dass dieser
Workflow-Schritt, -Verzweigung, -Gate, -Abstieg und -Abschluss so funktioniert, wie der
Autor es beabsichtigt hat?“ Er ist schnell, offline und deterministisch; er tätigt keine LLM-Aufrufe
und keine MCP-Round-Trips. Ein Live-Durchlauf gegen eine echte megálos-Bereitstellung ist
als begrenzte sekundäre Oberfläche für die Fälle verfügbar, die der Dry-Run nicht erreichen kann
— echte LLM-Ausgabeverzweigungen und echte Registry-mcp_tool_call-Abschweifungen
— und wird in §6 (in einer späteren Aufgabe entworfen) behandelt.
Im Umfang. Das interaktive Dry-Run-Rezept (§3). Skript-Response-Fixtures
(§4) für Regressions-Wiedergabe. Ladezeitübergreifende Workflow-Fehler —
unknown_call_target und call_cycle_detected — und wie der Dry-Run sie
über die create_app()-Bootstrapierung (§5) sichtbar macht. Exit-Code- und
Fehlerbanner-Verträge, die der Agent lesen muss.
Nicht im Umfang. Die Validierung einzelner Workflow-Dateien — wird von der
begleitenden Fertigkeit „Workflows validieren“ abgedeckt. Die Autorenarbeit von Workflows — wird von
„Workflows erstellen“ abgedeckt. Domain-Repo-Paketierung, Horizon-Bereitstellung und
Registry-Einrichtung — werden von „Workflows bereitstellen“ abgedeckt. Framework-Level-Tests
und Workflow-Fixtur-Beiträge zum megálos-Repository selbst:
pytest/conftest ist keine Oberfläche, die diese Fertigkeit lehrt. Die
Fertigkeit zum Testen von Workflows überprüft das Workflow-Verhalten mit dem Dry-Run;
Framework-Test-Erstellung ist eine eigenständige Aktivität für Mitwirkende an
megálos und ist ausdrücklich nicht im Umfang enthalten. Echte LLM-Aufrufe — der Dry-Run ruft niemals ein LLM auf;
Autoren, die ein echtes LLM in der Schleife benötigen, greifen auf die Live-Run-Oberfläche
(§6) oder eine bereitgestellte Instanz zurück.
Zielgruppe. Der Leser ist ein KI-Codierungsagent, der im Auftrag eines
Workflow-Autors handelt. Das Dry-Run-Design adressiert explizit diese Zielgruppe: Autoren
sind keine Testentwickler. Ein Workflow-Autor muss das gerenderte Direktiv-Template,
die aufgelisteten Gates und das Schema-Feedback bei jedem Schritt sehen —
und nicht einen pytest-Testfall schreiben. Die interaktiven und skriptgesteuerten Dry-Run-Rezepte
unten sind auf diese Zielgruppe zugeschnitten.
2. Dry-Run als primärer Modus
python -m megalos_server.dryrun lädt einen Workflow und führt ihn durch den
Produktionsausführungspfad, wobei die simulierten „LLM-Antworten“ jedes Schrittes
von der Standardeingabe (oder aus einer skriptgesteuerten YAML-Datei — siehe §4) gelesen werden, anstatt ein
Modell aufzurufen. Der Dry-Run ist kein paralleler Simulator; es ist die
Produktionslaufzeit mit einer simulierten Eingabequelle. Dieselben
start_workflow, submit_step, Klassifizierung, output_schema-Validierung, Wiederholungs-
buchhaltung, Verzweigungsauswahl und Unter-Workflow-Abstiege, die ein Live-Server
ausführt, werden auch vom Dry-Run ausgeführt. Alles, was der Dry-Run akzeptiert, akzeptiert auch der Server;
alles, was der Dry-Run beim Bootstrap ablehnt, lehnt auch der Server beim Start ab.
Was der Dry-Run testet. Schritt-Rendering (Banner, Vorbedingung, Gates,
Direktiv). output_schema-Validierung und die Wiederholungsoberfläche (Validierungs-
hinweise, verbleibende Wiederholungsanzahl, Budgeterschöpfung). Verzweigungsauswahl und
Standardverzweigungsauflösung. Vorbedingungs-Überspringungserkennung — wenn die precondition: eines Schrittes
zur Laufzeit nicht erfüllt ist, gibt der Dry-Run Skipped: <step_id>
auf der Standardausgabe aus und fährt fort (siehe §3 für den Oberflächenvertrag; §9 für die
Form häufiger Fehler). Unter-Workflow-Abstieg und Eltern-Wiederaufnahme.
create_app()-Ladezeitprüfungen über den gesamten Workflow-Satz im
übergeordneten Verzeichnis des Ziels, einschließlich unknown_call_target und call_cycle_detected
(§5).
Was der Dry-Run nicht testet. Echte LLM-Generierungsqualität. Echte MCP
Registry-Round-Trips (mcp_tool_call-Schritte werden durch Schema- und
Strukturprüfungen zur Ladezeit abgedeckt, aber ein echter Registry-Aufruf ist ein
Live-Run-Thema). Produktionsskalige Sitzungspersistenz, Latenz oder Parallelität.
Wenn der Autor eines dieser Dinge überprüfen muss, ist die Live-Run-Oberfläche das
Werkzeug (§6).
Exit-Code-Vertrag. Der Dry-Run beendet sich mit 0 bei workflow_complete und 1
bei jedem anderen Endstatus — die Produktion _TERMINAL_STATUSES-
frozenset ist {"workflow_complete", "error", "session_escalated", "workflow_changed"}. Ein Exit-Code ungleich Null wird immer von einem dekodierten Fehlerbanner
auf stderr begleitet. Skripte, die um den Dry-Run herum arbeiten (CI-Smoke-Tests, Pre-Commit-
Prüfungen), sollten Exit 0 als alleiniges grünes Signal behandeln.
3. Interaktives Dry-Run-Rezept
Der interaktive Modus ist der häufigste Fall: Der Agent (oder sein menschlicher Bedienter) gibt bei jedem Schritt eine simulierte LLM-Antwort ein und beobachtet, wie sich der Workflow entfaltet. Aufruf:
python -m megalos_server.dryrun workflows/my_workflow.yaml
Der Dry-Run lädt jede *.yaml-Datei im übergeordneten Verzeichnis des Ziels
(erforderlich, damit sich call:-Ziele von Unter-Workflows auflösen können — siehe §5),
dann bootet er den Workflow und startet eine REPL. Bei jedem Schritt rendert die Laufzeit
ein Banner, die optionale Vorbedingungszeile, alle Gates und das
Direktiv-Template des Schrittes und fordert dann mit > zur Eingabe auf. Der Agent gibt eine simulierte
LLM-Antwort ein und drückt die Eingabetaste. Der Workflow wird fortgesetzt.
Eine minimale Sitzung mit einem linearen Drei-Schritte-Workflow sieht so aus:
$ python -m megalos_server.dryrun workflows/example.yaml
=== Schritt: alpha — Erster Schritt ===
<hier wird das Direktiv-Template gerendert>
> ok
=== Schritt: bravo — Zweiter Schritt ===
<hier wird das Direktiv-Template gerendert>
> ok
=== Schritt: charlie — Dritter Schritt ===
<hier wird das Direktiv-Template gerendert>
> ok
Workflow abgeschlossen
Exit-Code 0. Drei simulierte Antworten führten drei Schritte zum
workflow_complete.
Eingabeaufforderungen, denen der Agent begegnen kann.
-
Schrittantwort-Eingabeaufforderung (
>). Die Standardaufforderung bei jedem Schritt. Was auch immer der Agent eingibt, wird der Laufzeit zugeführt, als hätte ein LLM es produziert. Bei Schritten mit einemoutput_schemamuss die Antwort ein gültiges JSON sein, das dem Schema entspricht; eine ungültige JSON-Nutzlast löst einen Validierungsfehler aus (mit einerVerbleibende Wiederholungen: N-Zeile auf stderr) und fordert erneut beim selben Schritt zur Eingabe auf. Das Erschöpfen des Wiederholungsbudgets beendet den Lauf mit einemMaximale Wiederholungen (N) überschritten-Banner und Exit1. -
Verzweigungsauswahl-Eingabeaufforderung. Wenn ein Schritt mit einem
branches:-Block erreicht wird, verbraucht der Dry-Run zuerst eine Schrittantwort und gibt dann Folgendes aus:Verzweigungen: 1. first_branch_target 2. second_branch_target [Standard] Wählen Sie eine Verzweigung [1-2, leer = Standard]:Das
[Standard]-Tag markiert die Verzweigung, die gewählt wird, wenn der Selektor gegen die Schrittantwort auswertet. Eine leere Eingabe löst den Standard auf. -
Vorbedingungszeile. Schritte mit einer
precondition:rendern diese beim Eintritt alsVorbedingung: <ref> == "<value>"oderVorbedingung: <ref> ist vorhanden, vor dem Direktiv. -
Überspringen-Oberfläche (
Skipped: <step_id>). Wenn die Vorbedingung eines Schrittes zur Laufzeit nicht erfüllt ist, rendert der Dry-Run weder das Banner noch die Eingabeaufforderung dieses Schrittes; stattdessen gibt erSkipped: <step_id>auf der Standardausgabe aus und fährt zum nächsten Schritt fort. Die zuvor gerenderteVorbedingung:-Zeile im vorherigen Schritt ist die implizite Erklärung. Die Überspringungserkennung kennzeichnet nur Schritte mit Vorbedingungen; alternative Verzweigungen, die einfach nicht genommen wurden, werden nicht „übersprungen“ — sie sind ein nicht erreichter Pfad. Ein Lauf, der versehentlich einen Schritt überspringt, endet dennoch mitworkflow_completebei Exit0, sodass das einzige Signal eines unbeabsichtigten Überspringens dieSkipped:-Zeile in der Standardausgabe ist. Lesen Sie jedeSkipped:-Zeile und bestätigen Sie, dass die Vorbedingung, die den Schritt unterdrückt hat, ihn unterdrücken sollte. -
EOF (Ctrl-D). Das Schließen der Standardeingabe mitten im Workflow bricht mit
Dry-Run vom Benutzer abgebrochen (EOF)auf stderr und Exit1ab.
Unter-Workflow-Abstieg. Wenn das call:-Ziel eines Schrittes zu einem
Geschwister-Workflow aufgelöst wird, gibt der Dry-Run Betrete Unter-Workflow <name> aus und
rückt die Banner des Kindes pro Verschachtelungsebene um zwei Leerzeichen ein. Beim
workflow_complete des Kindes gibt der Dry-Run Vom Unter-Workflow zurückgekehrt aus
und setzt den Eltern-Workflow beim nächsten Schritt fort.
Disziplin für saubere Verzeichnisse. Da der Dry-Run jede *.yaml im
übergeordneten Verzeichnis lädt, blockiert ein defektes Geschwister-YAML das Laden des Ziels.
Wenn das Fehlerbanner zum Bootstrap-Zeitpunkt eine andere Datei als das Ziel benennt, liegt ein Fehler in einem
Geschwister vor — beheben Sie ihn oder verschieben Sie das Ziel in ein
Verzeichnis, das nur es und seine call:-Ziele enthält. Der Einleitungsabsatz, den der Dry-Run bei einem Ladefehler ausgibt, ist:
Workflows konnten nicht aus <parent_dir> geladen werden: <exception>
Hinweis: Der Dry-Run lädt alle *.yaml-Dateien im übergeordneten Verzeichnis (erforderlich
für die Auflösung von Unter-Workflow-'call'-Zielen). Wenn der obige Fehler eine
andere Datei als <target.yaml> benennt, hat ein Geschwister-Workflow ein Problem — beheben Sie
es oder verschieben Sie <target.yaml> in ein Verzeichnis, das nur es und seine
Call-Ziele enthält.
4. Skript-Response-Fixtures
Für die Regressions-Wiedergabe und CI-Smoke-Tests akzeptiert der Dry-Run eine
--responses-file, die auf ein YAML-Fixture verweist, das den Workflow
nicht-interaktiv steuert:
python -m megalos_server.dryrun workflows/my_workflow.yaml \
--responses-file tests/responses/my_workflow_happy.yaml
Die Antwortdatei hat eine feste Struktur: eine Zuordnung auf oberster Ebene mit einem erforderlichen
version: 1-Schlüssel und einem erforderlichen entries:-Liste. Jeder Eintrag ist eine Zuordnung
mit einem erforderlichen step_id: und genau einem von response: (für Schrittinhalt)
oder branch: (für Verzweigungsauswahl-Eingabeaufforderungen) — niemals beide, niemals
keines. Ein minimales Fixture für den Happy Path mit drei Schritten:
version: 1
entries:
- step_id: alpha
response: ok
- step_id: bravo
response: ok
- step_id: charlie
response: ok
Geordneter Verbrauch. Im Stamm-Workflow-Frame (Abstiegstiefe 0)
werden Einträge in der Reihenfolge verbraucht: Der erste Eintrag muss mit dem step_id des ersten Schrittes
übereinstimmen, der zweite Eintrag mit dem zweiten Schritt und so weiter. Eine Abweichung in der Schreibweise oder Reihenfolge bricht den Lauf ab.
Während des Unter-Workflow-Abstiegs (Tiefe > 0) überspringt der Dry-Run
nicht übereinstimmende Einträge, bis eine Übereinstimmung gefunden wird, sodass
Einträge des Eltern- und des Kind-Frames in der Dateireihenfolge gemischt sein können
— aber die eigenen Einträge jedes Frames müssen in der Ausführungsreihenfolge dieses Frames erscheinen.
Banner zur Abweichungserkennung. Der Parser und die skriptgesteuerte Verbrauchsschicht geben
vor dem Beenden mit 1 wörtliche Banner auf stderr aus. Autoren werden genau diese
Zeichenfolgen sehen, wenn ein Fixture falsch ist:
- Fehlendes Versionsfeld:
Antwortdatei hat das erforderliche 'version'-Feld nicht. Erwartet: version: 1 - Unbekannte Version:
Unbekannte Antwortdatei-Version: <n>. Unterstützt: [1] - Antwort/Verzweigungs-Mutex (beide vorhanden):
... muss genau eines von 'response' oder 'branch' haben, nicht beide. - Antwort/Verzweigungs-Mutex (keines vorhanden):
... muss genau eines von 'response' oder 'branch' haben. - Schritt-ID-Abweichung auf Stammebene:
Skripteintrag erwartet step_id=<entry_step>, REPL bei step_id=<repl_step> - Eintragstypenkonflikt (Schritt erwartet Antwort, Skript lieferte Verzweigung):
Bei Schritt <repl_step> wurde eine Schrittantwort erwartet, aber das Skript lieferte eine Verzweigungsauswahl(oder symmetrisch:Verzweigungsauswahl erwartet, aber das Skript lieferte eine Antwort) - Erschöpfung (zu wenige Einträge):
Antwortdatei bei Schritt <repl_step> erschöpft (erwartet: <expected_label>) - Unbenutzte Einträge beim Abschluss (zu viele Einträge):
Antwortdatei hatte <N> unbenutzte Einträge nach Workflow-Abschluss
Die Prüfung auf unbenutzte Einträge läuft bei workflow_complete unmittelbar bevor
der Lauf beendet wird; ein länger als nötiges Fixture ist ein Skriptfehler, kein
stilles Bestehen. Jeder Fall einer Abweichung endet mit 1, sodass CI, die Exit 0 als
grün behandelt, bei jedem der oben genannten Fälle laut scheitert.
Abdeckungsparität mit dem interaktiven Modus. Der skriptgesteuerte Modus steuert dieselbe
Oberfläche, die auch der interaktive Modus steuert: output_schema-Validierung und
Wiederholungsbanner (eine ungültige response: löst dieselbe Validierungsfehler-
Eingabeaufforderung aus), Verzweigungsauswahl (über branch:-Einträge) und Unter-Workflow-
Abstieg (mit gemischten Eltern-/Kind-Einträgen). Ein skriptgesteuertes Fixture, das
einen Workflow Ende-zu-Ende durchläuft, ist das kanonische Regressionsartefakt für diesen
Workflow.
5. Ladezeitübergreifende Workflow-Fehler — unknown_call_target und call_cycle_detected
Zwei workflowübergreifende Fehler treten zur Ladezeit des Workflow-Satzes auf, nicht im Rahmen einer dateiweisen Validierung. Beide werden aus demselben Durchlauf ausgegeben, den die Fertigkeit zur Workflow-Validierung als Vorwärtsreferenz markiert hat:
Eine Nuance, die es zu verinnerlichen gilt: Diese beiden Fehler treten zur Ladezeit des Workflow-Satzes auf, nicht unter einem dateiweisen
python -m megalos_server.validate <file>-Lauf. Der dateiweise Validator deckt nur die eigenen strukturellen und semantischen Regeln des äußeren Workflows ab; er kann nichts über die anderen Workflows wissen, die der Server schließlich laden wird. Die Call-Ziel- und Zyklusprüfungen laufen innerhalb dercreate_app()des Servers, nachdem jede Workflow-YAML im Workflow-Verzeichnis einzeln geladen wurde, und sie laufen bevor die MCP-App konstruiert wird. In der Praxis bedeutet das: Ein Agent, der einen Workflow mit einemcall:-Schritt erstellt oder ändert, muss entweder den vollständigen Workflow-Satz in den Server laden, umunknown_call_targetundcall_cycle_detectedsichtbar zu machen, oder die Testoberfläche verwenden, die intesting-workflowsabgedeckt ist. Ein grüner dateiweiser Validierungslauf ist eine notwendige, aber nicht hinreichende Bedingung für einen ladbaren Server.
Dieser Abschnitt ist diese Testoberfläche. Die wörtlichen f-String-Formen, die der Lader ausgibt, sind:
Workflow '<parent_name>' Schritt '<step_id>' ruft unbekannten Workflow '<target>' auf (Code: unknown_call_target)
Call-Zyklus erkannt: <wf_a> -> <wf_b> -> ... -> <wf_a> (Code: call_cycle_detected)
Wie der Dry-Run sie sichtbar macht. Der Bootstrap des Dry-Runs ruft
create_app(workflow_dir=<übergeordnetes Verzeichnis des Ziels>) auf. create_app()
lädt jede *.yaml in diesem Verzeichnis und führt dann den workflowübergreifenden
Call-Auflösungsdurchlauf bevor die MCP-App konstruiert wird. Wenn ein
call:-Ziel nicht zu einem geladenen Workflow aufgelöst wird oder wenn der Call-
Graph einen Zyklus enthält, schlägt das Laden mit dem obigen Fehlercode fehl und der Dry-Run
beendet sich mit 1 beim Bootstrap, bevor die REPL startet. Der Fehler ist in den
Einleitungsabsatz aus §3 eingewickelt („Der Dry-Run lädt alle *.yaml-Dateien im übergeordneten Verzeichnis …“), damit der Autor sehen kann, welche Datei betroffen ist.
Die praktische Auswirkung. Ein dateiweiser python -m megalos_server.validate <file>-Lauf kann unknown_call_target oder call_cycle_detected
nicht sichtbar machen. Ein Agent, der die Fertigkeit zum Testen von Workflows nicht
verwendet, wird diese Fehler erst sehen, wenn er die Server-App tatsächlich zu starten versucht. Die
create_app()-Bootstrapierung des Dry-Runs ist die früheste und billigste Stelle, um
sie abzufangen | Ein Agent, der die Fertigkeit zum Testen von Workflows
nicht verwendet, wird diese Fehler erst sehen, wenn er die Server-App tatsächlich zu starten versucht. Die
create_app()-Bootstrapierung des Dry-Runs ist die früheste und billigste Stelle, um
sie abzufangen.