Ein Abschnitt oder ein einzelner Schritt erscheint nur, wenn seine Bedingung zutrifft — abhaengig von einer Variable des Laufs oder vom Zustand eines anderen Schritts. Der echte Fall steht im Seed: "Mitarbeiter-Onboarding" traegt beide Konto-Abschnitte, fuenf AD-Schritte und vier fuer Entra ID, und `konto_typ` sagt beim Start, welcher gilt. Bisher klickte ein Techniker die anderen neun bei jedem Onboarding weg. Entscheidungen, alle im Issue begruendet: - Laufend ausgewertet, nicht beim Start festgeschrieben. Fuer die Abteilungsabschnitte (#031) ist Festschreiben richtig; fuer Bedingungen nicht — die Antwort auf "ist Pruefen fehlgeschlagen?" entsteht erst waehrend der Arbeit. Ein struktureller Test prueft, dass alle drei Schichten (Abschlussregel, Abarbeitung, Druck) die Auswertung rufen. - Nicht entscheidbar heisst: gilt. Ein Lauf ohne konto_typ zeigt beide Abschnitte — genau wie vorher. Ein Abschnitt zu viel ist sichtbar und korrigierbar, ein fehlender faellt niemandem auf. - OFFEN ist eine Antwort, keine Luecke: waere es unentscheidbar, waere ein bedingter Abschnitt von Anfang an sichtbar. - Eine Bedingung, kein Ausdrucksbaum. Kein und, kein oder. - Verwiesen wird ueber Titel-Pfade, nicht ueber Kennungen: vier Wege schreiben eine Struktur neu und geben neue Kennungen. Zwei stille Datenverluste gefunden, der zweite aelter als dieser Meilenstein: - Der Import verwarf `nurFuerAbteilungen`. Der Export schreibt es seit #031, das Schema nimmt es an, der Import setzte es nicht — eine exportierte Vorlage verlor ihre Abteilungsabschnitte und galt dort fuer alle. - Die tiefe Kopie verwarf es ebenfalls, womit jedes "Bearbeiten" einer Vorlage alle Einschraenkungen verlor. Ursache war ein von Hand getippter Zwischentyp, der weniger Felder nannte als die Abfrage liefert; jetzt aus Prisma abgeleitet, beide Kopierwege teilen eine Stelle, und ein Test vergleicht Kopie und Original Feld fuer Feld. Gefunden hat beides die Klickprobe am gebauten Stand, nicht die Suite: im Editor stand "Bedingung gesetzt", nach "Bearbeiten" war sie weg. Dreizehn Gegenproben liefen, alle wurden rot — und der teuerste Befund lag ausserhalb von allen. 1499 Vitest-Tests (vorher 1457), 115 E2E-Ablaeufe gruen. Closes #39 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
10 KiB
#039 M23 – Bedingte Schritte und Abschnitte
Status: erledigt Im Tracker: – Meilenstein: v0.3.0 Labels: phase-3, backend, frontend Geschätzt: 12 h Tatsächlich: 5 h 20 min
Ziel
Eine Checkliste enthält heute alles, und was nicht zutrifft, wird von Hand auf
NICHT_ZUTREFFEND gesetzt. Der echte Fall steht im Seed: „Mitarbeiter-Onboarding“ trägt beide
Konto-Abschnitte — „Konto anlegen (Active Directory)“ mit 5 Schritten und „Konto anlegen (Entra
ID)“ mit 4 —, obwohl in jedem einzelnen Lauf nur einer gilt. Die Variable konto_typ sagt es
bereits; niemand wertet sie aus.
Neun Schritte, die ein Techniker bei jedem Onboarding wegklickt. Die Abschnitts-Aktion aus #013 macht es erträglich, aber sie ist ein Pflaster: der Fortschrittsbalken zählt die Schritte mit, und im Archiv steht später eine Checkliste mit einem Abschnitt, den niemand je gebraucht hat.
Setzt #031 voraus: geltendeAbschnitte und nurGeltende sind die
Stelle, an der das sitzt.
Zu entscheiden
-
Wann wird ausgewertet? Das ist die Entscheidung, an der alles hängt.
Für Abteilungen (#031) wird beim **Start festgeschrieben** — die Abteilung des Laufs steht dann fest, und ein archivierter Lauf muss genau die Schritte zeigen, die damals galten. Für Bedingungen reicht das **nicht**: eine Bedingung auf einer Variable (`konto_typ`) ließe sich beim Start auswerten, eine Bedingung auf einem **Schrittergebnis** („wenn Schritt 3 = nein, dann Abschnitt B“) nicht — die Antwort entsteht erst während der Arbeit. Empfehlung: **laufend auswerten, Ergebnis mitschreiben.** Die Auswertung läuft bei jeder Änderung an einem Schrittergebnis; was dabei herauskommt, wird in den Lauf geschrieben (wie `geltendeAbschnitte`). Damit gilt für das Archiv weiter „der Lauf weiß, was galt“, und der Ereignisstrom aus #033 trägt die Änderung ohnehin schon zur zweiten Sitzung. -
Woran darf eine Bedingung hängen? Empfehlung: an einer Variable des Laufs und an einem Schrittergebnis derselben Version. Nicht an Gerätetyp, Abteilung oder Rolle — für Abteilungen gibt es #031, und je mehr Quellen, desto schwerer zu erklären, warum ein Schritt fehlt.
-
Wie wird sie gespeichert? Empfehlung: ein Json-Feld
bedingunganVorlagenAbschnittundVorlagenSchritt, mit einem engen Schema —{ art: "variable", schluessel, operator, wert }oder{ art: "schritt", schrittId, zustand }. Json, weilkonfiges schon so macht und ein neuer Operator dann keine Migration braucht. Eine Bedingung, kein Ausdrucksbaum. Keinund/oder, keine Verschachtelung: das wäre eine kleine Sprache, die niemand im Editor pflegen kann, und ein Abschnitt, der aus unerklärlichen Gründen fehlt, ist schlimmer als einer zu viel. -
Was passiert mit einem Schrittergebnis, das schon Daten trägt, wenn die Bedingung umschlägt? Empfehlung: die Zeile bleibt und wird nur ausgeblendet. Löschen hieße, eine Notiz zu verlieren, die jemand geschrieben hat; und schlägt die Bedingung zurück, ist sie wieder da.
Aufgaben
- Migration:
bedingung Json?anVorlagenAbschnittundVorlagenSchritt, dazu ein CHECK, der sicherstellt, dass eine Bedingung auf einen Schritt derselben Version zeigt (sonst zeigt sie nach dem Veröffentlichen ins Leere) src/lib/bedingungen.ts, framework-frei: Schema, Auswertung, und die Liste der Schritte und Abschnitte, die gelten. Dieselbe Stelle für alle drei Schichten, wiesrc/lib/geltende-abschnitte.ts- Auswertung bei jedem Schreiben an einem
Schrittergebnis; das Ergebnis in den Lauf - Abschlussregel: ein ausgeblendeter Pflichtschritt hält den Abschluss nicht auf (dieselbe Regel wie bei #031, dieselbe Funktion)
- Fortschrittsbalken und Zählwerte rechnen nur mit dem, was gilt
- Editor: Bedingung an Abschnitt und Schritt setzen, mit Auswahl der Variable bzw. des Schritts aus derselben Version; eine Vorschau, die sagt „gilt, wenn …“
- Warnung im Editor bei einer Bedingung auf einen Schritt, der nach dem bedingten steht — sie wäre beim Abarbeiten noch offen, und der Abschnitt erschiene erst rückwirkend
- Abarbeitung: ausgeblendete Abschnitte verschwinden, ohne die Nummerierung zu verschieben
(
01 · Vorbereitungkommt aus der Position und wird nie gespeichert) - Druckansicht und Archiv zeigen, was galt
- Export/Import: die Bedingung wandert mit, und ein Verweis auf einen Schritt wird dabei auf die neue Kennung umgeschrieben — sonst zeigt sie in der zweiten Installation ins Leere
- Seed: „Mitarbeiter-Onboarding“ bekommt die Bedingung auf
konto_typ, die beiden Konto-Abschnitte bleiben drin und schließen sich gegenseitig aus. Das ist die Gegenprobe am echten Fall. - Anleitung Kapitel 04 (Vorlagen): wann eine Bedingung das richtige Mittel ist und wann eine zweite Vorlage
Akzeptanzkriterien
- Test: ein Lauf mit
konto_typ = ADhat die 5 AD-Schritte und keinen der 4 Entra-Schritte - Test: dasselbe umgekehrt, und bei nicht gesetzter Variable gelten beide — eine Bedingung, die nicht entschieden werden kann, blendet nichts aus
- Test: eine Bedingung auf einem Schrittergebnis schlägt um, während der Lauf läuft, und der Abschnitt erscheint
- Test: ein ausgeblendeter Pflichtschritt hält den Abschluss nicht auf
- Test: ein Schrittergebnis mit Notiz bleibt stehen, wenn seine Bedingung umschlägt, und ist danach wieder da
- Test: Export und Import einer Vorlage mit Bedingungen ergeben dieselbe Struktur, und der Schritt-Verweis zeigt auf den richtigen Schritt der neuen Version
- Test: ein archivierter Lauf zeigt genau die Schritte, die bei seinem Abschluss galten
- Am Handy kein horizontales Scrollen
Beim Umsetzen dazugekommen
- Die Entscheidungen aus dem Issue sind so gefallen wie empfohlen, und zwei davon haben sich im
Code als richtig erwiesen:
- Laufend auswerten, nicht beim Start festschreiben. Eine Bedingung auf einer Variable ließe sich wie #031 beim Start festhalten; eine auf einem Schrittergebnis nicht — und genau die ist der interessante Fall (ein Abschnitt „Nacharbeit“, der erscheint, wenn der Restore-Test fehlschlägt).
- Nicht entscheidbar heißt: gilt. Ein Lauf ohne
konto_typzeigt beide Konto-Abschnitte — genau wie vor diesem Meilenstein. Eine erfundene Antwort wäre die Verschlechterung.
OFFENist eine Antwort, keine Lücke. Der Unterschied zur Variable musste scharf gezogen werden: eine nicht gesetzte Variable ist nicht entscheidbar, ein offener Schritt dagegen klar „noch nicht erfüllt“. WäreOFFENunentscheidbar, wäre ein bedingter Abschnitt von Anfang an sichtbar — das Gegenteil des Zwecks.- Verwiesen wird über Titel-Pfade, nicht über Kennungen, und das war die größte Einzelerkenntnis.
Vier Wege schreiben eine Struktur neu und geben dabei neue Kennungen: Import, Export, Seed und
entwurfSpeichern. Eine Bedingung auf einer Kennung überlebt keinen davon.bedingungAufloesenist für alle vier dieselbe Stelle; dass eine Bedingung auf dieselbe Version zeigt, hält zusätzlich ein Trigger. - Ein struktureller Test bewacht die drei Schichten. Abschlussregel, Abarbeitung und Druck
müssen alle
geltendeStrukturrufen; vergisst eine es, sieht der Techniker andere Schritte als der Ausdruck. Der Test liest die drei Dateien — dieselbe Art Prüfung wie „jede Seite prüft selbst“ (#038). - Zwei Schemas für dieselbe Form liefen fast auseinander. Austauschformat und Editor-Struktur
brauchen die Pfad-Form; ich hatte sie zweimal geschrieben, und TypeScript meldete es erst, als die
beiden Typen aufeinandertrafen. Jetzt steht
PfadBedingungSchemainsrc/lib/bedingungen.ts, undvorlagen-format.tsimportiert es.
Zwei stille Datenverluste, gefunden bei der Klickprobe
Beides hätte keine Suite gezeigt, und das zweite war älter als dieser Meilenstein:
-
Der Import verwarf
nurFuerAbteilungen. Der Export schreibt die Abteilungseinschränkung seit #031, das Schema nimmt sie an — und der Import setzte sie nicht. Eine Vorlage, die jemand in eine zweite Installation brachte, verlor ihre Abteilungsabschnitte: sie galten dort für alle. Also mehr Schritte statt weniger, und niemand merkt es. -
Die tiefe Kopie verwarf sie ebenfalls — und seit heute auch die Bedingung. „Bearbeiten“ einer Vorlage erzeugt eine tiefe Kopie als Entwurf (#009);
vorlageDuplizierendasselbe. Beide hatten die Kopie einzeln ausgeschrieben, und beide vergaßen dieselben Felder. Damit verlor jede Bearbeitung alle Abteilungseinschränkungen.Die Ursache war ein von Hand getippter Zwischentyp.
VersionMitInhaltnannte weniger Felder, als die Abfrage liefert; die Felder waren da, der Code konnte sie nicht sehen. Jetzt ist der Typ aus Prisma abgeleitet — ein neues Feld am Modell ist dort automatisch vorhanden.Gefunden hat es die Klickprobe am gebauten Stand: der Editor zeigte „Bedingung gesetzt“ in der veröffentlichten Version, und nach „Bearbeiten“ war sie weg. Das ist genau der Grund, warum diese Probe in
CLAUDE.mdsteht.Bewacht wird es jetzt von einem Test, der Kopie und Original Feld für Feld vergleicht — nicht stichprobenweise. So fällt auch das nächste Feld auf, das jemand ergänzt und beim Kopieren vergisst.
-
Ein Mangel an der neuen Komponente, aufgefallen beim Klicken: die Auswahlfelder standen in einem umhüllenden
<label>, und damit schluckte ihr zugänglicher Name den Text der gewählten Option mit („VariableKontotyp“). Für einen Screenreader ist das eine Bezeichnung, die sich beim Umschalten ändert. JetzthtmlFor/id— derselbe Fehler wie bei der Adresse im Verzeichnis-Formular (#016).
Was offen bleibt
- Kein
und/oder, bewusst. Wer zwei Bedingungen braucht, nimmt zwei Abschnitte. - Ein Baustein-Schritt hat keine Bedingung (der Abschnitt, in dem er steht, darf eine haben): ein Baustein ist wiederverwendbar, und eine Bedingung auf einer Variable der Zielvorlage wäre dort nicht entscheidbar.
- Zwei Schritte mit demselben Titel im selben Abschnitt sind über den Titel-Pfad nicht
unterscheidbar; die Bedingung zeigt dann auf den ersten. Benannt in
src/lib/bedingungen.ts— zwei gleich benannte Schritte nebeneinander kann auch ein Mensch nicht unterscheiden.