Abgleich mit dem Vault-Stand 7f484f9

38 Datei(en) geändert.
Erzeugt von .vault-tools/auto-push/werkzeuge_spiegel.py.
This commit is contained in:
Pascal Michel committed 2026-11-02 03:00:03 +01:00
1 parent f5747605c7
commit 9e506ff588
38 files changed
+2325 -24

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-10-17
updated: 2026-10-30
---
# Workflow-Prüfung
@@ -41,9 +41,11 @@ Stand 2026-09-24 nach Plankritik, Prüfung und Nachbesserung. Die Zahlen gelten
- **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.
- **Ableser als Agententyp** (2026-10-17, Task 02 desselben Plans): Der Ableser läuft als `agentType: verbrauch-ableser` (Haiku, `effort: low`, nur ToolSearch und `get_usage`). Ein Startfehler, etwa ein in der Sitzung noch unbekannter Typ, kommt als `nicht_gelesen` mit `WARNUNG` zurück, nie als Rückfall auf einen Agenten mit allen Werkzeugen. Echtläufe: Vor der Registrierung warf `agent()` „agent type 'verbrauch-ableser' not found“ ohne Agent (`wf_63cb007d-71b`); danach lasen vier von vier Ablesern richtig, mit Effort `low` und nur ToolSearch, `get_usage` und StructuredOutput (`wf_1901f51f-dd3`, `wf_4d8a69f9-51a`). Die Sitzung kannte die neue Agentendatei nach etwa zehn Minuten. 261 Fälle grün, drei neue gegen den alten Stand rot; 157 Mutanten, alle gefangen oder als wirkungslos geführt. **Ungemessen:** ein Ableser, der eine abweichende Nutzeranfrage sieht. Alle vier Echtläufe starteten in Zügen ohne Nutzernachricht, der Harness reichte keine Anfrage durch.
- **Eichung der Stufen** (2026-10-30, Workflow-Review S-11): `verbrauch_reihe.py` über den ganzen Speicher ergab 1.245 Ablesungen und 647 Paare. Getrennt wurde mit einem Wegwerfskript, das die Funktionen von `verbrauch_reihe.py` importiert: Plan aus dem Feld `plan` der Ablesung, Konto aus Wochentag und Stunde des Wochen-`resetsAt`, auf die volle Stunde gerundet, weil der Wert über die Stundengrenze zittert. Zwei Konten: Reset montags 00:00 UTC (Pro bis 2026-09-30, Max ab 2026-10-05) und mittwochs 20:00 UTC (Max ab 2026-10-09). 340 Ablesungen ohne Plan waren gescheiterte oder abgewichene Ablesungen. Max: 9,2 bzw. 10,1 % des 5-Stunden-Fensters und 2,5 bzw. 2,6 % der Woche je Opus-Agentenstunde (187 und 205 Paare, 107 und 125 Opus-Stunden), Median je Paar ab 15 Opus-Minuten 8,6 bzw. 9,0, P90 rund 19. Pro: 14 Paare, zu wenig. Anstieg des Fensters je Paar nach gleichzeitig laufenden Opus-Agenten: einer Median 3, P90 13, Spitze 33 Punkte (211 Paare); zwei 4, 14, 42 (134); drei 5, 9, 18 (45); vier nur 2 Paare. Pascal hat die Stufen daraufhin unverändert bestätigt und Stufe 3 freigegeben. **Ungemessen:** Max zeigt je Opus-Stunde mehr Prozent als Pro; als reiner Planeffekt ist das unplausibel, wahrscheinlich liefen im Max-Zeitraum mehr Sitzungen parallel. Die Kontentrennung kann `verbrauch_reihe.py` selbst nicht.
- **`planung` mit `effort`** (2026-10-30, für die Messung A2): Das Argument wird geprüft (`low` bis `max`), an jeden Planer neben `agentType` weitergereicht und in der Rückgabe genannt, ohne Argument `(Frontmatter)`. Drei neue Fälle, alle drei gegen den alten Stand rot; drei neue Mutanten, einzeln gefahren und alle gefangen. Der volle Mutantenlauf ist dafür nicht gelaufen.
**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
Den Verbrauch anderer Sitzungen und der Hauptsitzung: Er steckt in jeder Differenz mit drin. Ablesungen über `probe` starten keinen Agenten und fehlen in der Messreihe. `get_usage` gibt es nur in der Desktop-App; anderswo gilt über den Rückfall die Zwei, und die Messreihe bleibt leer. Die Stufen in `verbrauch.js` sind vorläufig. Sie sind ein Fangnetz und kein Nachweis dafür, dass ein Lauf das Fenster nicht reißt.
Den Verbrauch anderer Sitzungen und der Hauptsitzung: Er steckt in jeder Differenz mit drin. Ablesungen über `probe` starten keinen Agenten und fehlen in der Messreihe. `get_usage` gibt es nur in der Desktop-App; anderswo gilt über den Rückfall die Zwei, und die Messreihe bleibt leer. Die Stufen in `verbrauch.js` sind am 2026-10-30 geeicht, aber an einer Messreihe mit dem Verbrauch paralleler Sitzungen. Sie sind ein Fangnetz und kein Nachweis dafür, dass ein Lauf das Fenster nicht reißt.
@@ -614,6 +614,18 @@ fall('plankritik', 'mit kopie, mutanten in Vorgabe: ein Agent werkzeug:mutanten,
return fehler
})
fall('plankritik', 'Modell je Hilfslabel: kopie haiku/low, planwerkzeuge und mutanten sonnet/low', async () => {
const { fehler, soll } = pruefe()
const args = { projekt: 'D:/x', planordner: 'D:/x/plan', materialisieren: { ohne: ['config/secrets.toml'] } }
const { fehler: f, protokoll: p } = await PK(args, {})
soll(f === null, 'Fehler: ' + f)
for (const [l, m] of [['werkzeug:kopie', 'haiku'], ['werkzeug:planwerkzeuge', 'sonnet'], ['werkzeug:mutanten', 'sonnet']]) {
const a = mitLabel(p, l)
soll(a.length === 1 && a[0].modell === m && a[0].effort === 'low' && !a[0].agentType, l + ' ' + JSON.stringify(a.map(x => [x.modell, x.effort, x.agentType])))
}
return fehler
})
fall('plankritik', 'mutanten "aus": kein Agent werkzeug:mutanten', async () => {
const { fehler, soll } = pruefe()
const { protokoll: p } = await PK({ ...PK_ARGS, mutanten: 'aus' }, {})
@@ -832,6 +844,18 @@ fall('welle-mit-pruefung', 'Grundlinie: Welle, Vergleich, Ablesung um die Prüfu
return fehler
})
fall('welle-mit-pruefung', 'Modell je Hilfslabel: kopie haiku/low, vergleich sonnet/low', async () => {
const { fehler, soll } = pruefe()
const { kopie, ...ohneKopie } = WM_ARGS
const { fehler: f, protokoll: p } = await WM({ ...ohneKopie, ohne: ['config/secrets.toml'] }, {})
soll(f === null, 'Fehler: ' + f)
for (const [l, m] of [['werkzeug:kopie', 'haiku'], ['werkzeug:vergleich', 'sonnet']]) {
const a = mitLabel(p, l)
soll(a.length === 1 && a[0].modell === m && a[0].effort === 'low' && !a[0].agentType, l + ' ' + JSON.stringify(a.map(x => [x.modell, x.effort, x.agentType])))
}
return fehler
})
fall('welle-mit-pruefung', 'bis vergleich: keine Prüfung, pruefung_args mit Rohbelegen', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, fehler: f, protokoll: p } = await WM({ ...WM_ARGS, bis: 'vergleich' }, {})
@@ -1065,6 +1089,7 @@ for (const [name, aendern, text] of [
['nr als Text', a => ({ ...a, tasks: [{ ...T(1, [], 1), nr: '1' }] }), /nr muss/],
['voraussetzungen fehlen', a => ({ ...a, tasks: [{ ...T(1, [], 1), voraussetzungen: undefined }] }), /voraussetzungen muss/],
['gemeinsam fehlt', a => ({ ...a, gemeinsam: '' }), /args fehlen: gemeinsam/],
['effort ungültig', a => ({ ...a, effort: 'mittel' }), /effort "mittel" ungültig/],
]) {
fall('planung', `${name} wirft vor dem ersten Agenten`, async () => {
const { fehler, soll } = pruefe()
@@ -1087,6 +1112,25 @@ fall('planung', 'Auftrag nennt die Voraussetzungen und ersetzt alle Platzhalter'
return fehler
})
fall('planung', 'effort medium: alle Planer auf medium, Ableser unverändert', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, fehler: f, protokoll: p } = await PL({ ...PL_ARGS, effort: 'medium' }, {})
soll(f === null && e.status === 'fertig', 'Fehler/status: ' + f + ' ' + (e && e.status))
const pl = p.agents.filter(x => x.label.startsWith('planer:'))
soll(pl.length === 7 && pl.every(x => x.effort === 'medium' && x.agentType === 'planer' && x.modell === 'opus'), 'Planer: ' + JSON.stringify(pl.map(x => [x.effort, x.agentType])))
soll(mitLabel(p, 'verbrauch:').every(x => x.effort === undefined), 'Ableser mit effort')
soll(e.effort === 'medium', 'Rückgabe effort ' + e.effort)
return fehler
})
fall('planung', 'ohne effort: Planer ohne effort, Rückgabe nennt das Frontmatter', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await PL(PL_ARGS, {})
soll(p.agents.filter(x => x.label.startsWith('planer:')).every(x => x.effort === undefined), 'Planer mit effort')
soll(e.effort === '(Frontmatter)', 'Rückgabe effort ' + e.effort)
return fehler
})
fall('planung', 'alles erledigt: kein Agent, keine Ablesung', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await PL({ ...PL_ARGS, erledigt: DAG.map(t => t.nr) }, {})
@@ -1187,7 +1231,7 @@ fall('quorum', 'Grundlinie: Paket, drei Stimmen gleichzeitig, Mehrheit sperrt, E
soll(f === null, 'Fehler: ' + f)
soll(e && e.status === 'fertig' && e.urteil === 'nicht_frei', 'status/urteil ' + JSON.stringify(e && [e.status, e.urteil, e.grund]))
const erst = p.agents.slice().sort((x, y) => x.start - y.start)[0]
soll(erst && erst.label === 'werkzeug:paket' && erst.modell === 'sonnet' && erst.effort === 'low', 'erster Agent ' + JSON.stringify(erst && [erst.label, erst.modell, erst.effort]))
soll(erst && erst.label === 'werkzeug:paket' && erst.modell === 'haiku' && erst.effort === 'low' && !erst.agentType,'erster Agent ' + JSON.stringify(erst && [erst.label, erst.modell, erst.effort]))
const ab = mitLabel(p, 'verbrauch:').map(x => x.label)
soll(JSON.stringify(ab) === JSON.stringify(['verbrauch:quorum:vor Stimmen', 'verbrauch:quorum:Ende']), 'Ablesungen: ' + JSON.stringify(ab))
const opus = mitLabel(p, 'stimme:opus')[0]
@@ -1198,7 +1242,7 @@ fall('quorum', 'Grundlinie: Paket, drei Stimmen gleichzeitig, Mehrheit sperrt, E
soll(mitLabel(p, 'stimme:haiku').length === 0, 'Haiku trotz gültiger Codex-Stimme')
const start = mitLabel(p, 'codex:start')[0]
soll(start && laufendBeiStart(p, start, 'stimme:') === 2, 'Codex startete nicht neben Opus und Sonnet')
soll(mitLabel(p, 'codex:').length === 3 && mitLabel(p, 'codex:').every(x => x.modell === 'sonnet' && x.effort === 'low' && !x.agentType), 'Codex-Hilfsagenten: ' + JSON.stringify(mitLabel(p, 'codex:').map(x => [x.label, x.modell, x.effort])))
soll(mitLabel(p, 'codex:').length === 3 && mitLabel(p, 'codex:').every(x => x.modell === 'haiku' && x.effort === 'low' && !x.agentType), 'Codex-Hilfsagenten: ' + JSON.stringify(mitLabel(p, 'codex:').map(x => [x.label, x.modell, x.effort])))
const zf = mitLabel(p, 'zusammenfuehren')[0]
const np = mitLabel(p, 'nachpruefung')[0]
soll(zf && zf.modell === 'sonnet' && zf.effort === 'medium' && !zf.agentType, 'Zusammenführen ' + JSON.stringify(zf && [zf.modell, zf.effort, zf.agentType]))
@@ -1436,6 +1480,27 @@ fall('quorum', 'Codex nie fertig: so viele Warterunden wie codex_runden, dann Ab
return fehler
})
fall('quorum', 'Modell je Hilfslabel: paket und alle codex-Labels haiku/low ohne agentType, zusammenfuehren sonnet/medium', async () => {
const { fehler, soll } = pruefe()
const { fehler: f, protokoll: p } = await QR(Q_ARGS, {})
soll(f === null, 'Fehler: ' + f)
for (const l of ['werkzeug:paket', 'codex:start', 'codex:warten:1', 'codex:ende']) {
const a = mitLabel(p, l)[0]
soll(a && a.modell === 'haiku' && a.effort === 'low' && !a.agentType, l + ' ' + JSON.stringify(a && [a.modell, a.effort, a.agentType]))
}
const zf = mitLabel(p, 'zusammenfuehren')[0]
soll(zf && zf.modell === 'sonnet' && zf.effort === 'medium' && !zf.agentType, 'zusammenfuehren ' + JSON.stringify(zf && [zf.modell, zf.effort, zf.agentType]))
return fehler
})
fall('quorum', 'Modell codex:abbruch: haiku/low ohne agentType', async () => {
const { fehler, soll } = pruefe()
const { protokoll: p } = await QR({ ...Q_ARGS, codex_runden: 1 }, { codexWarten: () => Q_WARTEN_OFFEN })
const ab = mitLabel(p, 'codex:abbruch')[0]
soll(ab && ab.modell === 'haiku' && ab.effort === 'low' && !ab.agentType, 'codex:abbruch ' + JSON.stringify(ab && [ab.modell, ab.effort, ab.agentType]))
return fehler
})
fall('quorum', 'Codex nie fertig ohne codex_runden: Vorgabe drei Warterunden', async () => {
const { fehler, soll } = pruefe()
const { ergebnis: e, protokoll: p } = await QR(Q_ARGS, { codexWarten: () => Q_WARTEN_OFFEN })
@@ -41,6 +41,8 @@ MUTANTEN = [
("plankritik", "Rueckfall ohne Ablesung 3", "const OHNE_ABLESUNG = 2", "const OHNE_ABLESUNG = 3"),
("plankritik", "Testort fehlt in der Widerlegung", "Du änderst keine Datei im Projekt und keine im Plan. ${testort(ctx)}\n- ", "Du änderst keine Datei im Projekt und keine im Plan.\n- "),
("plankritik", "Testort fehlt bei den Linsen", "Executer-Bericht, dessen Testlauf du wiederholen könntest. ${testort(ctx)}", "Executer-Bericht, dessen Testlauf du wiederholen könntest. ${linse === 'arithmetik' ? testort(ctx) : ''}"),
("plankritik", "werkzeug:kopie wieder auf sonnet", "den Plan darauf anwenden', '', 'haiku')", "den Plan darauf anwenden', '', 'sonnet')"),
("plankritik", "Planwerkzeuge und Mutantenlauf auf haiku", "zusatz, modell = 'sonnet')", "zusatz, modell = 'haiku')"),
("plankritik", "keine Ablesung am Ende", "await ablesen('Ende', 0)\n", "\n"),
("plankritik", "gebremste Befunde ohne Hinweis", "'nicht geprüft (gebremst)'", "'nicht geprüft'"),
("plankritik", "gebremst auch unter der Schwelle", "gebremstVor && zuPruefen.includes(g) ?", "gebremstVor ?"),
@@ -50,6 +52,8 @@ MUTANTEN = [
("pruefung", "Ablesung nach der Pruefung fehlt", "await ablesen('nach Prüfung')\n", "\n"),
("welle-mit-pruefung", "Kind liest selbst", "{ ...pruefungArgs, verbrauch: false }", "{ ...pruefungArgs }"),
("welle-mit-pruefung", "bis vergleich wirkt nicht", "if (args.bis === 'vergleich') {", "if (false) {"),
("welle-mit-pruefung", "werkzeug:kopie wieder auf sonnet", "Taskdateien der Welle darauf anwenden', 'haiku')", "Taskdateien der Welle darauf anwenden', 'sonnet')"),
("welle-mit-pruefung", "Vergleich auf haiku", "zweck, modell = 'sonnet')", "zweck, modell = 'haiku')"),
("welle-mit-pruefung", "Ablesung vor der Pruefung fehlt", " await ablesen('vor Prüfung')\n", "\n"),
("planung", "Voraussetzung laufend genuegt", "['fertig', 'erledigt'].includes(status.get(n)))) starte(t)", "['fertig', 'erledigt', 'laeuft'].includes(status.get(n)))) starte(t)"),
("planung", "keine Blockade", "status.set(t.nr, 'blockiert')\n geaendert = true", "geaendert = false"),
@@ -68,6 +72,9 @@ MUTANTEN = [
("planung", "Datei ohne Pfadgrenze", "('/' + roh.datei.replace(/\\\\/g, '/')).endsWith('/' + jeNr.get(nr).datei)", "roh.datei.replace(/\\\\/g, '/').endsWith(jeNr.get(nr).datei)"),
("planung", "Nachlesezaehler nicht zurueckgesetzt", " fertigSeitAblesung = 0\n const v = await ablesen(", " const v = await ablesen("),
("planung", "nachlesen_alle ignoriert", "const nachlesenAlle = args.nachlesen_alle || NACHLESEN_ALLE", "const nachlesenAlle = NACHLESEN_ALLE"),
("planung", "effort nicht durchgereicht", " if (args.effort) opts.effort = args.effort\n", ""),
("planung", "effort ungeprueft", " if (a.effort !== undefined && !EFFORTS.includes(a.effort)) throw", " if (false) throw"),
("planung", "Rueckgabe ohne effort", " effort: args.effort || '(Frontmatter)',\n", ""),
("planung", "Lesehinweis fehlt", " Lies sie, bevor du einen Namen, eine Signatur oder einen Import daraus übernimmst.", ""),
("plankritik", "doppelte Linse erlaubt", " if (a.linsen && new Set(a.linsen).size !== a.linsen.length) throw", " if (false) throw"),
("plankritik", "Mutantenlauf-Rohausgabe geht nicht an arithmetik", "${mutantenText(ctx.mutantenLauf)}`,", "`,"),
@@ -92,6 +99,8 @@ MUTANTEN = [
("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"),
("quorum", "codex:ende wieder auf sonnet", "schema: CODEX, model: 'haiku'", "schema: CODEX, model: 'sonnet'"),
("quorum", "Werkzeug-Hilfsagenten wieder auf sonnet", "schema: LAUF, model: 'haiku'", "schema: LAUF, model: 'sonnet'"),
("quorum", "Bremse vor den Stimmen fehlt", "if (vorStimmen.gebremst) {", "if (false) {"),
("quorum", "Opus-Stimme ohne Ablesung", "const vorStimmen = await ablesen('vor Stimmen', 1)", "const vorStimmen = { gebremst: false, grund: '' }"),
("quorum", "keine Ablesung am Ende", "await ablesen('Ende', 0)\nconst zaehlung = {}", "const zaehlung = {}"),