Automatischer Push: 6 Datei(en) geändert

- .claude/workflows/verbrauch.js
- .vault-tools/workflow-pruefung/LIESMICH.md
- .vault-tools/workflow-pruefung/docs/plans/2026-10-16-ableser-abweichung/00-uebersicht.md
- .vault-tools/workflow-pruefung/docs/plans/2026-10-16-ableser-abweichung/task-01-erkennung.md
- .vault-tools/workflow-pruefung/faelle_workflows.mjs
- .vault-tools/workflow-pruefung/mutanten_workflows.py

Erzeugt vom PostToolUse-Hook .vault-tools/auto-push/auto_push.py.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
Pascal MichelandClaude Opus 5 committed 2026-10-17 04:00:01 +02:00
1 parent 5c997a23e2
commit 07675bf541
6 files changed
+309 -4

No files matched your search

+4 -2
View File
@@ -5,7 +5,7 @@ title: "Workflow-Prüfung: Attrappe, Fälle und Messreihe zum Verbrauch"
summary: "Node-Attrappe für die gespeicherten Workflows des Vaults mit Fällen je Workflow, dazu verbrauch_reihe.py, das aus den Workflow-Protokollen rechnet, wie viel vom 5-Stunden-Fenster und von der Woche zwischen zwei Verbrauchsablesungen verbraucht wurde. Entstanden 2026-09-24."
tags: [vault-tools, codeworkflow]
created: 2026-09-24
updated: 2026-09-24
updated: 2026-10-16
---
# Workflow-Prüfung
@@ -16,7 +16,7 @@ Die Regel dazu steht in [[AI/Regelwerk/codeworkflow|codeworkflow.md]], Abschnitt
1. **Nach jeder Änderung an einem Workflow unter `.claude/workflows/`:** `node .vault-tools/workflow-pruefung/faelle_workflows.mjs` im Vault-Wurzelordner. Mit einem Ordner als Argument prüft das Skript die Workflows dort, etwa eine Kopie mit angewendetem Plan. Jeder Workflow hat zuerst eine Grundlinie; scheitert sie, messen seine übrigen Fälle nichts.
2. **Ein neuer Fall braucht einen Rotlauf.** Die Fälle gegen den Stand vor der Änderung fahren, oder den Mutanten nachstellen, den der Fall fangen soll. Grün allein belegt nichts.
3. **Mutanten:** `python .vault-tools/workflow-pruefung/mutanten_workflows.py` (einige Minuten) und `python .vault-tools/workflow-pruefung/mutanten_reihe.py`. Ein veraltetes Muster bricht mit Exit 2 ab und muss an den neuen Code angepasst werden; ein wirkungsloser Mutant steht mit Grund in `WIRKUNGSLOS`. Wer einen Workflow ändert, ergänzt hier den Mutanten, den sein neuer Fall fangen soll.
3. **Mutanten:** `python .vault-tools/workflow-pruefung/mutanten_workflows.py` (am 2026-10-16 knapp 50 Minuten, im Hintergrund fahren) und `python .vault-tools/workflow-pruefung/mutanten_reihe.py`. Ein veraltetes Muster bricht mit Exit 2 ab und muss an den neuen Code angepasst werden; ein wirkungsloser Mutant steht mit Grund in `WIRKUNGSLOS`. Wer einen Workflow ändert, ergänzt hier den Mutanten, den sein neuer Fall fangen soll.
4. **Messreihe:** `python .vault-tools/workflow-pruefung/verbrauch_reihe.py [--seit JJJJ-MM-TT]`. Die Ausgabe ist eine Tabelle je Paar aufeinanderfolgender Ablesungen eines Laufs: Minuten, Agentenminuten je Modellfamilie, Differenz im 5-Stunden-Fenster und in der Woche. Darunter steht eine Näherung in Prozent des 5-Stunden-Fensters je Opus-Agentenstunde. Ein `Reset` zwischen zwei Ablesungen zählt nicht mit.
## Was die Attrappe nachbildet
@@ -39,6 +39,8 @@ Stand 2026-09-24 nach Plankritik, Prüfung und Nachbesserung. Die Zahlen gelten
- **Neue `planung.js` im echten Laufzeitsystem** (wf_5df09faa-a4d, Probe mit drei Tasks im Scratchpad): Task 1 lief allein, Task 2 und 3 starteten erst nach seinem Ende und liefen gleichzeitig; beide übernahmen die Zieldatei-Zeile aus Task 1, haben seine Taskdatei also gelesen.
- **Erster Eichwert** am Abend des 2026-09-24, Plan laut App „Pro“: `verbrauch_reihe.py --seit 2026-09-24` ergab 8,1 % des 5-Stunden-Fensters je Opus-Agentenstunde (5 Paare, 1,7 Opus-Stunden, darunter ein Plankritik-Lauf der Trading-Sitzung). Die Woche stieg in denselben Paaren um 5 Punkte. Der Verbrauch anderer Sitzungen und der Hauptsitzung steckt mit drin; die Zahl ist also eher zu hoch. Für das Nachstellen der Stufen reicht ein Abend nicht.
- **Ableser verlässt den Auftrag** (2026-10-16, Plan `docs/plans/2026-10-16-ableser-abweichung/`): Zweimal bearbeitete der Haiku-Ableser die Nutzeranfrage statt `get_usage` zu lesen und schrieb seine Antwort in `status` und `plan` (wf_7ca17029-421, wf_80616e8e-0e3). `verbrauch.js` meldet diese Form jetzt als `status: abgewichen` mit einer Logzeile, die mit `WARNUNG` beginnt; Plätze wie ohne Ablesung. Neun neue Fälle, sieben davon gegen den alten Stand rot; die zwei Gegenproben (ehrlicher Fehlschlag, `not_applicable`) bleiben auf beiden Ständen grün. Acht neue Mutanten, alle gefangen; der volle Mutantenlauf brauchte knapp 50 Minuten. Die drei echten Antworten aus den Journalen ergaben `abgewichen`, `abgewichen` und `nicht_gelesen`. **Ungemessen:** ob der neue Brückensatz im Auftrag einen echten Ableser vom Abweichen abhält; der Fall misst nur, dass der Satz dasteht. Ein abweichender Ableser hat weiterhin alle Werkzeuge.
**Offen:** Die Trading-Sitzung hat `plankritik.js` am 2026-09-24 nach einem echten Lauf nachgebessert (Ausgabe der Planwerkzeuge nur bei `EXIT 0`). Für diese Stelle gibt es noch keinen Fall.
## Was die Skripte nicht sehen
@@ -0,0 +1,50 @@
---
type: plan
title: "verbrauch.js: Ableser, der den Auftrag verlässt, erkennen und laut melden"
status: active
summary: "Nach dem Plan erkennt verbrauch.js an status und plan, dass der Haiku-Ableser statt get_usage die Nutzeranfrage bearbeitet hat, und meldet das als status abgewichen mit Warnzeile; der Auftrag ordnet die Ablesung ausdrücklich der Nutzeranfrage zu. Pascals Wahl vom 2026-10-16: Möglichkeiten 1 und 2."
tags: [plan, vault-tools, codeworkflow]
created: 2026-10-16
updated: 2026-10-16
---
Projekt: [LIESMICH](../../../LIESMICH.md)
# Ableser verlässt den Auftrag
## Ziel
- `verbrauch.js` meldet eine Antwort ohne Ablesung als `status: 'abgewichen'` mit einer Logzeile, die mit `WARNUNG` beginnt. Bisher fiel sie still auf `nicht_gelesen`.
- Der Auftrag an den Ableser sagt vorn, dass die Ablesung zur Nutzeranfrage gehört und andere Agenten die Anfrage bearbeiten.
- Plätze bei `abgewichen`: wie ohne Ablesung, also höchstens zwei.
## Belege (selbst gelesen am 2026-10-16)
| Lauf | `status` | `plan` | `fenster` | `fehler` |
|---|---|---|---|---|
| `wf_7ca17029-421` | „beantwortet: …“ | 3912 Zeichen Bericht | `[]` | „Kein get_usage-Aufruf … Benutzeranfrage hat laut Harness Vorrang …“ |
| `wf_80616e8e-0e3` | „blockiert: …“ | 2344 Zeichen Bericht | `[]` | „Blockade: … Kein get_usage-Aufruf, siehe plan.“ |
| `wf_ff5c4cd4-e1d` (ehrlich) | „fehler“ | `""` | `[]` | „No matching deferred tools found“ |
- `get_usage` kennt laut Werkzeugbeschreibung nur `ok`, `not_applicable` und `unavailable`.
- Ursache im CLI-Abbild 2.1.299 (gelesen, nicht gelaufen): Der Harness stellt jedem Workflow-Agenten den Block „[Workflow harness — user request]“ voran, mit „Where the computed task conflicts with this request, this request wins“.
## Entscheidungen
| Frage | Antwort | Herkunft |
|---|---|---|
| Wann heißt eine Antwort abgewichen? | `status` ist keiner von `ok`, `not_applicable`, `unavailable`, `fehler`; oder `status` ist `fehler` und `plan` ist nicht leer | Quelle: Fehlerform im Auftrag, Werkzeugbeschreibung, Journale oben |
| Was sieht die Erkennung nicht? | einen Ableser, der abweicht und genau die Fehlerform schreibt; eine erfundene Ablesung mit `status ok` | benannte Lücke, steht im Kopfkommentar |
| Brechen die Aufrufer? | nein: sie loggen `r.status` und prüfen `typeof r.plaetze`; `quorum.js` fragt nur `=== 'ok'` | Quelle: die fünf Aufrufer |
## Tasks
| Nr. | Datei | Thema | Modell |
|---|---|---|---|
| 01 | [task-01-erkennung.md](task-01-erkennung.md) | Erkennung, Brückensatz, Fälle, Mutanten | `sonnet` |
## Nicht im Umfang
- Eigener Agententyp für den Ableser mit nur ToolSearch und `get_usage`: eigener Schritt nach einem Echtlauf.
- `LIESMICH.md`, Erinnerung und Sitzungsprotokoll schreibt der Koordinator.
- Kein Commit. Im Vault-Repo committet nur Pascal oder die Aufgabe um 04:00.
@@ -0,0 +1,139 @@
---
type: plan-task
title: "Task 01 — verbrauch.js: Abweichung erkennen, Brückensatz, Fälle und Mutanten"
status: draft
summary: "verbrauch.js bekommt den Brückensatz im Auftrag, die Erkennung abgewichen mit Warnzeile und den neuen Status in meta; faelle_workflows.mjs bekommt die Fälle dazu, mutanten_workflows.py die Mutanten. Alles in Kopien im Scratchpad."
tags: [plan-task, vault-tools, codeworkflow]
created: 2026-10-16
updated: 2026-10-16
modell: sonnet
modell_begruendung: "verbrauch.js ist Abschrift, die Fälle sind nur als Eingabe und Erwartung vorgegeben und brauchen Autorschaft."
---
Übersicht: [00-uebersicht.md](00-uebersicht.md)
# Task 01 — Abweichung erkennen
## Arbeitsorte
`S` ist `D:/ClaudeData/claude/D--Claude/8a6a0a87-ddcf-462b-90e2-83ab3ba2be28/scratchpad`. Du schreibst **nur** diese drei Dateien:
- `S/wf-neu/verbrauch.js` (Kopie von `D:/Claude/.claude/workflows/verbrauch.js`)
- `S/wp-neu/faelle_workflows.mjs` (Kopie aus `D:/Claude/.vault-tools/workflow-pruefung/`)
- `S/wp-neu/mutanten_workflows.py` (Kopie, ebenda)
Nichts unter `D:/Claude/` anfassen. Keine Hilfsdateien. Kein Commit.
## 1 verbrauch.js
Ersetze genau diese Stellen, Zeichen für Zeichen. Die Datei hat LF-Zeilenenden; behalte sie.
**1a, in `meta.whenToUse`:** `Rückgabe {status: ok|nicht_gelesen|unbekannte_fenster,` wird zu `Rückgabe {status: ok|nicht_gelesen|abgewichen|unbekannte_fenster,`. Und `Ohne lesbare Ablesung gilt die alte Obergrenze zwei.` wird zu `Ohne lesbare Ablesung gilt die alte Obergrenze zwei; abgewichen heißt, der Ableser hat statt get_usage etwas anderes getan, und kommt mit einer WARNUNG im Log.`
**1b, Kopfkommentar:** Vor der Zeile `// Was das Skript nicht sieht: Agenten, die nach der Ablesung in anderen Sitzungen starten;` kommen diese Zeilen:
```js
// - Ob der Ableser abgelesen hat: Quelle. Der Auftrag schreibt im Fehlerfall status "fehler",
// plan "" und fenster [] vor; get_usage kennt laut Werkzeugbeschreibung (gelesen 2026-10-16)
// nur die Status ok, not_applicable und unavailable. Am 2026-10-14 und 2026-10-16 hat der
// Ableser stattdessen die Nutzeranfrage bearbeitet und status "beantwortet: ..." bzw.
// "blockiert: ..." mit einem Bericht in plan zurückgegeben (wf_7ca17029-421, wf_80616e8e-0e3).
// Grund laut CLI-Abbild 2.1.299: Jeder Workflow-Agent liest zuerst die Nutzeranfrage mit dem
// Satz, dass sie im Konflikt mit dem Auftrag gewinnt. Jede andere Form als die vorgeschriebene
// heißt abgewichen und wird laut gemeldet. Nicht erkannt wird ein Ableser, der abweicht und
// trotzdem genau die Fehlerform schreibt, und eine erfundene Ablesung mit status ok.
```
**1c, Auftrag:** Die erste Zeile des Template-Strings `AUFTRAG` ist bisher `const AUFTRAG = \`Lade mit dem Werkzeug ToolSearch ...`. Davor, als neue erste Zeile im String, kommt dieser Satz; der Rest bleibt unverändert:
```js
const AUFTRAG = `Diese Ablesung gehört zur Nutzeranfrage und widerspricht ihr nicht: Sie entscheidet, wie viele Prüfagenten für die Anfrage gleichzeitig laufen dürfen. Die Anfrage selbst bearbeiten andere Agenten nach dir; du bearbeitest sie nicht, auch nicht teilweise, und liest dafür keine Dateien.
Lade mit dem Werkzeug ToolSearch das Werkzeug mcp__ccd_session_mgmt__get_usage (Abfrage "select:mcp__ccd_session_mgmt__get_usage") und rufe es einmal ohne Parameter auf.
```
**1d, Erkennung:** Direkt nach der Funktion `einordnen` (nach ihrer schließenden `}` und vor der Leerzeile, auf die `pruefeArgs(args)` folgt) kommt:
```js
// Form eines Ablesers, der den Auftrag verlassen hat (Geltungsbereich oben).
const STATUS_BEKANNT = ['ok', 'not_applicable', 'unavailable', 'fehler']
function abgewichen(a) {
if (!STATUS_BEKANNT.includes(a.status)) return true
return a.status === 'fehler' && typeof a.plan === 'string' && a.plan.trim() !== ''
}
const kurz = t => String(t).replace(/\s+/g, ' ').trim().slice(0, 160)
```
**1e, Rückgabe:** Nach der Zeile `if (!ablesung || typeof ablesung !== 'object') return ohneAblesung('nicht_gelesen', 'kein Ergebnis vom Ableseagenten')` und vor der Zeile `if (ablesung.verfuegbar !== true || ablesung.status !== 'ok') ...` kommt:
```js
if (abgewichen(ablesung)) {
log(`WARNUNG Verbrauch ${args.anlass}: Der Ableser hat get_usage nicht gelesen und den Auftrag verlassen; die Bremse misst nicht. Seine Werkzeugaufrufe im Journal unter ▸ verbrauch ansehen.`)
return ohneAblesung('abgewichen', `Ableser hat den Auftrag verlassen: status ${kurz(ablesung.status)}${ablesung.fehler ? ', fehler ' + kurz(ablesung.fehler) : ''}`)
}
```
Sonst änderst du an `verbrauch.js` nichts.
## 2 faelle_workflows.mjs
Neue Fälle im Abschnitt `verbrauch`, nach dem Fall `Agent ohne Ergebnis: ...`. Feste Testdaten, gekürzt und neutral, in der Form der echten Abweichungen:
```js
// Form der echten Abweichungen vom 2026-10-14 und 2026-10-16, Texte gekürzt und neutral.
const abweichung = (status, fehler) => ({ verfuegbar: false, status, plan: '**Stand:** Bericht zur Nutzeranfrage statt Ablesung.\n- Punkt 1\n- Punkt 2', fenster: [], fehler })
const BEANTWORTET = abweichung('beantwortet: offene Punkte im Projekt X, Stand 2026-10-10', 'Kein get_usage-Aufruf und kein Planverbrauch abgelesen: Die Benutzeranfrage hat laut Harness Vorrang vor dem Verbrauchsauftrag.')
const BLOCKIERT = abweichung('blockiert: Folgesitzung nicht abgeschlossen; nichts geaendert', 'Blockade: Workflow- und Agent-Werkzeug fehlen. Kein get_usage-Aufruf, siehe plan.')
const warnung = p => p.logs.filter(l => /^WARNUNG/.test(l))
```
Fälle, je mit `pruefe()` und `soll` wie die Nachbarn; die Abweichung kommt als Antwort des Ablesers (`V({ anlass: 't', wunsch: 3 }, { ablesungen: [X] })`), nicht über `probe`:
| Name | Eingabe | Erwartung |
|---|---|---|
| `Ableser beantwortet die Nutzeranfrage: abgewichen, Warnung, zwei Plätze` | `BEANTWORTET`, `wunsch: 3` | `status 'abgewichen'`, `plaetze 2`, `gebremst false`, `quelle 'agent'`, `grund` passt auf `/Auftrag verlassen/` und enthält `beantwortet:`, genau eine Warnzeile |
| `Ableser meldet blockiert: abgewichen, Warnung` | `BLOCKIERT`, `wunsch: 1` | `status 'abgewichen'`, `plaetze 1`, `grund` enthält `blockiert:`, genau eine Warnzeile |
| `status fehler mit Bericht in plan: abgewichen` | `{ verfuegbar: false, status: 'fehler', plan: 'Bericht', fenster: [], fehler: 'x' }` | `status 'abgewichen'`, eine Warnzeile |
| `ehrlicher Fehlschlag bleibt nicht_gelesen, ohne Warnung` | `{ verfuegbar: false, status: 'fehler', plan: '', fenster: [], fehler: 'No matching deferred tools found' }` | `status 'nicht_gelesen'`, `plaetze 2`, keine Warnzeile |
| `not_applicable bleibt nicht_gelesen, ohne Warnung` | `{ verfuegbar: true, status: 'not_applicable', plan: '', fenster: [], fehler: '' }` | `status 'nicht_gelesen'`, keine Warnzeile |
| `grund kürzt einen langen status auf 160 Zeichen, ohne Zeilenumbruch` | `abweichung('beantwortet:\n' + 'x'.repeat(400), '')` | `status 'abgewichen'`; der Teil von `grund` hinter `status ` ist höchstens 160 Zeichen lang und enthält kein `\n` |
| `Auftrag ordnet die Ablesung der Nutzeranfrage zu` | Grundlinie ohne Abweichung | `p.agents[0].prompt` enthält `gehört zur Nutzeranfrage` und `bearbeiten andere Agenten`. Kommentar über dem Fall: misst nur, dass der Satz da ist, nicht, ob er wirkt |
Zwei neue Fälle im Abschnitt `plankritik`, nach `Ablesung ohne Ergebnis: Linsen zu zweit (alte Obergrenze)` (Reihenfolge: derselbe Schaden an erster und letzter Ablesung):
| Name | Eingabe | Erwartung |
|---|---|---|
| `Abweichung bei der ersten Ablesung: Linsen zu zweit, Status abgewichen im Ergebnis` | `PK(PK_ARGS, { ablesungen: [BEANTWORTET] })` | `e.status 'fertig'`, Spitze `Plankritik`/`opus` gleich 2, `e.verbrauch[0].status 'abgewichen'`, eine Warnzeile im Protokoll |
| `Abweichung bei der letzten Ablesung: Status abgewichen im Ergebnis` | `PK(PK_ARGS, { ablesungen: [undefined, undefined, BLOCKIERT] })` | `e.status 'fertig'`, `e.verbrauch[2].status 'abgewichen'`, `e.verbrauch[0].status 'ok'`, eine Warnzeile |
Sonst änderst du an `faelle_workflows.mjs` nichts.
## 3 mutanten_workflows.py
Diese Einträge in `MUTANTEN`, direkt nach `("verbrauch", "5-Stunden-Regex unverankert", ...)`:
```python
("verbrauch", "Abweichung nicht erkannt", "if (abgewichen(ablesung)) {", "if (false) {"),
("verbrauch", "unbekannter Status gilt als bekannt", " if (!STATUS_BEKANNT.includes(a.status)) return true\n", ""),
("verbrauch", "Bericht in plan bei status fehler uebersehen", "return a.status === 'fehler' && typeof a.plan === 'string' && a.plan.trim() !== ''", "return false"),
("verbrauch", "ehrlicher Fehler gilt als Abweichung", "'unavailable', 'fehler']", "'unavailable']"),
("verbrauch", "Abweichung als nicht_gelesen", "return ohneAblesung('abgewichen',", "return ohneAblesung('nicht_gelesen',"),
("verbrauch", "Warnzeile fehlt", "log(`WARNUNG Verbrauch", "String(`WARNUNG Verbrauch"),
("verbrauch", "status ungekuerzt im grund", ".trim().slice(0, 160)", ".trim()"),
("verbrauch", "Brueckensatz fehlt", "Diese Ablesung gehört zur Nutzeranfrage und widerspricht ihr nicht: Sie entscheidet, wie viele Prüfagenten für die Anfrage gleichzeitig laufen dürfen. Die Anfrage selbst bearbeiten andere Agenten nach dir; du bearbeitest sie nicht, auch nicht teilweise, und liest dafür keine Dateien.\n", ""),
```
## Prüfen
Mit `S` wie oben, je Befehl Ausgabe und Exit-Code in den Bericht:
```bash
# Neue Fälle gegen den neuen Stand: alle grün
node "$S/wp-neu/faelle_workflows.mjs" "$S/wf-neu"; echo "EXIT $?"
# Rotlauf: neue Fälle gegen den alten Stand; die Gegenproben ehrlicher Fehlschlag und not_applicable bleiben grün, die übrigen neuen Fälle scheitern
node "$S/wp-neu/faelle_workflows.mjs" "D:/Claude/.claude/workflows" | grep -v "^OK"; echo "EXIT ${PIPESTATUS[0]}"
# Mutanten gegen den neuen Stand: kein UEBERLEBT, kein VERALTET (läuft einige Minuten)
python "$S/wp-neu/mutanten_workflows.py" "$S/wf-neu" | grep -v "^GEFANGEN"; echo "EXIT ${PIPESTATUS[0]}"
```
Melde am Ende: geänderte Dateien, die drei Ausgaben, und **was du anders gemacht hast als beauftragt und warum**.
@@ -248,6 +248,71 @@ fall('verbrauch', 'Agent ohne Ergebnis: nicht_gelesen, zwei Plätze, bei wunsch
return fehler
})
// Form der echten Abweichungen vom 2026-10-14 und 2026-10-16, Texte gekürzt und neutral.
const abweichung = (status, fehler) => ({ verfuegbar: false, status, plan: '**Stand:** Bericht zur Nutzeranfrage statt Ablesung.\n- Punkt 1\n- Punkt 2', fenster: [], fehler })
const BEANTWORTET = abweichung('beantwortet: offene Punkte im Projekt X, Stand 2026-10-10', 'Kein get_usage-Aufruf und kein Planverbrauch abgelesen: Die Benutzeranfrage hat laut Harness Vorrang vor dem Verbrauchsauftrag.')
const BLOCKIERT = abweichung('blockiert: Folgesitzung nicht abgeschlossen; nichts geaendert', 'Blockade: Workflow- und Agent-Werkzeug fehlen. Kein get_usage-Aufruf, siehe plan.')
const warnung = p => p.logs.filter(l => /^WARNUNG/.test(l))
fall('verbrauch', 'Ableser beantwortet die Nutzeranfrage: abgewichen, Warnung, zwei Plätze', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await V({ anlass: 't', wunsch: 3 }, { ablesungen: [BEANTWORTET] })
soll(e && e.status === 'abgewichen' && e.plaetze === 2 && e.gebremst === false && e.quelle === 'agent', JSON.stringify(e))
soll(e && /Auftrag verlassen/.test(e.grund) && e.grund.includes('beantwortet:'), 'grund: ' + (e && e.grund))
soll(warnung(p).length === 1, 'Warnzeilen: ' + JSON.stringify(warnung(p)))
return fehler
})
fall('verbrauch', 'Ableser meldet blockiert: abgewichen, Warnung', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await V({ anlass: 't', wunsch: 1 }, { ablesungen: [BLOCKIERT] })
soll(e && e.status === 'abgewichen' && e.plaetze === 1 && e.grund.includes('blockiert:'), JSON.stringify(e))
soll(warnung(p).length === 1, 'Warnzeilen: ' + JSON.stringify(warnung(p)))
return fehler
})
fall('verbrauch', 'status fehler mit Bericht in plan: abgewichen', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await V({ anlass: 't', wunsch: 3 }, { ablesungen: [{ verfuegbar: false, status: 'fehler', plan: 'Bericht', fenster: [], fehler: 'x' }] })
soll(e && e.status === 'abgewichen', JSON.stringify(e))
soll(warnung(p).length === 1, 'Warnzeilen: ' + JSON.stringify(warnung(p)))
return fehler
})
fall('verbrauch', 'ehrlicher Fehlschlag bleibt nicht_gelesen, ohne Warnung', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await V({ anlass: 't', wunsch: 3 }, { ablesungen: [{ verfuegbar: false, status: 'fehler', plan: '', fenster: [], fehler: 'No matching deferred tools found' }] })
soll(e && e.status === 'nicht_gelesen' && e.plaetze === 2, JSON.stringify(e))
soll(warnung(p).length === 0, 'Warnzeilen: ' + JSON.stringify(warnung(p)))
return fehler
})
fall('verbrauch', 'not_applicable bleibt nicht_gelesen, ohne Warnung', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await V({ anlass: 't', wunsch: 3 }, { ablesungen: [{ verfuegbar: true, status: 'not_applicable', plan: '', fenster: [], fehler: '' }] })
soll(e && e.status === 'nicht_gelesen', JSON.stringify(e))
soll(warnung(p).length === 0, 'Warnzeilen: ' + JSON.stringify(warnung(p)))
return fehler
})
fall('verbrauch', 'grund kürzt einen langen status auf 160 Zeichen, ohne Zeilenumbruch', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e } = await V({ anlass: 't', wunsch: 3 }, { ablesungen: [abweichung('beantwortet:\n' + 'x'.repeat(400), '')] })
soll(e && e.status === 'abgewichen', JSON.stringify(e))
const teil = e && e.grund.split('status ')[1]
soll(typeof teil === 'string' && teil.length > 0 && teil.length <= 160 && !teil.includes('\n'), 'Teil hinter status: ' + JSON.stringify(teil) + ' Länge ' + (teil && teil.length))
return fehler
})
// Misst nur, dass der Satz im Auftrag steht, nicht, ob er den Ableser vom Abweichen abhält.
fall('verbrauch', 'Auftrag ordnet die Ablesung der Nutzeranfrage zu', async () => {
const { fehler, soll } = pruefe()
const { protokoll: p } = await V({ anlass: 't', wunsch: 3 }, {})
const prompt = p.agents[0] && p.agents[0].prompt
soll(typeof prompt === 'string' && prompt.includes('gehört zur Nutzeranfrage') && prompt.includes('bearbeiten andere Agenten'), 'prompt: ' + JSON.stringify(prompt))
return fehler
})
for (const [name, probe] of [
['status unavailable', { verfuegbar: true, status: 'unavailable', plan: '', fenster: [], fehler: '' }],
['verfuegbar false', { verfuegbar: false, status: 'fehler', plan: '', fenster: [], fehler: 'Werkzeug fehlt' }],
@@ -414,6 +479,25 @@ fall('plankritik', 'Ablesung ohne Ergebnis: Linsen zu zweit (alte Obergrenze)',
return fehler
})
fall('plankritik', 'Abweichung bei der ersten Ablesung: Linsen zu zweit, Status abgewichen im Ergebnis', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await PK(PK_ARGS, { ablesungen: [BEANTWORTET] })
soll(e && e.status === 'fertig', 'status ' + (e && e.status))
soll(spitze(p, 'Plankritik', 'opus') === 2, 'Linsen gleichzeitig: ' + spitze(p, 'Plankritik', 'opus'))
soll(e && e.verbrauch[0].status === 'abgewichen', JSON.stringify(e && e.verbrauch[0]))
soll(warnung(p).length === 1, 'Warnzeilen: ' + JSON.stringify(warnung(p)))
return fehler
})
fall('plankritik', 'Abweichung bei der letzten Ablesung: Status abgewichen im Ergebnis', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await PK(PK_ARGS, { ablesungen: [undefined, undefined, BLOCKIERT] })
soll(e && e.status === 'fertig', 'status ' + (e && e.status))
soll(e && e.verbrauch[2].status === 'abgewichen' && e.verbrauch[0].status === 'ok', JSON.stringify(e && e.verbrauch.map(v => v.status)))
soll(warnung(p).length === 1, 'Warnzeilen: ' + JSON.stringify(warnung(p)))
return fehler
})
fall('plankritik', 'als Kind: verbrauch.js wirft, Rückfall auf zwei', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, fehler: f, protokoll: p } = await PK(PK_ARGS, {}, { tiefe: 1 })
@@ -77,6 +77,14 @@ MUTANTEN = [
("welle-mit-pruefung", "status fertig ohne Pruefung", "status: pruefung ? 'fertig' : 'ohne_pruefung',", "status: 'fertig',"),
("welle-mit-pruefung", "Ablesung ohne try", " try {\n r = await workflow({ scriptPath: VERBRAUCH }, { anlass: 'welle-mit-pruefung:' + anlass, wunsch: 0 })\n } catch (e) {\n r = { status: 'nicht_gelesen', grund: 'verbrauch.js nicht ausführbar: ' + (e && e.message) }\n }", " r = await workflow({ scriptPath: VERBRAUCH }, { anlass: 'welle-mit-pruefung:' + anlass, wunsch: 0 })"),
("verbrauch", "5-Stunden-Regex unverankert", "const FUENF_STUNDEN = /^\\s*5[- ]?hour/i", "const FUENF_STUNDEN = /hour/i"),
("verbrauch", "Abweichung nicht erkannt", "if (abgewichen(ablesung)) {", "if (false) {"),
("verbrauch", "unbekannter Status gilt als bekannt", " if (!STATUS_BEKANNT.includes(a.status)) return true\n", ""),
("verbrauch", "Bericht in plan bei status fehler uebersehen", "return a.status === 'fehler' && typeof a.plan === 'string' && a.plan.trim() !== ''", "return false"),
("verbrauch", "ehrlicher Fehler gilt als Abweichung", "'unavailable', 'fehler']", "'unavailable']"),
("verbrauch", "Abweichung als nicht_gelesen", "return ohneAblesung('abgewichen',", "return ohneAblesung('nicht_gelesen',"),
("verbrauch", "Warnzeile fehlt", "log(`WARNUNG Verbrauch", "String(`WARNUNG Verbrauch"),
("verbrauch", "status ungekuerzt im grund", ".trim().slice(0, 160)", ".trim()"),
("verbrauch", "Brueckensatz fehlt", "Diese Ablesung gehört zur Nutzeranfrage und widerspricht ihr nicht: Sie entscheidet, wie viele Prüfagenten für die Anfrage gleichzeitig laufen dürfen. Die Anfrage selbst bearbeiten andere Agenten nach dir; du bearbeitest sie nicht, auch nicht teilweise, und liest dafür keine Dateien.\n", ""),
("plankritik", "Muster-Satz fehlt (N5)", "musterModus\n ? ' Kein Mutant ist gefahren; OK heißt hier nur, dass das Muster genau einmal in der Datei steht; ob ein Test fällt, ist unbelegt.'\n : ", ""),
("plankritik", "Exit 2 wird wie 0 behandelt (N7)", "exitCode === 2 || exitCode === 3", "false"),
("quorum", "Mehrheit schon bei einer Stimme", "mehrheit: beteiligt.length >= 2", "mehrheit: beteiligt.length >= 1"),