Quorum: Task 06 (Freitext im Bericht entschaerft), Grund nennt blockierende ohne Beleg, Abschluss
quorum.js: klartext() schreibt Wikilinks, Einbettungen und Tags aus Freitext als Klartext (Fund aus dem ersten echten Lauf); der Grund eines freien Urteils nennt blockierende Befunde ohne Beleg. faelle_workflows.mjs 248 Faelle gruen, mutanten_workflows.py 145 Mutanten, 0 ueberlebt. codeworkflow.md: Regel zum Befund ohne Beleg und Ablageort beim Kundendokument praezisiert, Vermerk 'noch nicht abgenommen' entfernt. LIESMICH.md fuer .vault-tools/quorum/. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
7a74a8acb9
commit
ed55848b00
6 files changed
+212
-21
No files matched your search
@@ -1,7 +1,7 @@
|
||||
---
|
||||
type: plan
|
||||
title: "Quorum am Meilenstein: drei Stimmen, Mehrheit, Nachprüfung"
|
||||
status: draft
|
||||
status: done
|
||||
summary: "Nach dem Plan prüft ein neuer Workflow quorum vor Einspielen, neuer Version auf master und Abgabe eines Kundendokuments denselben Unterschied seit dem letzten Quorum mit Opus, Sonnet und Codex (Ersatz Haiku), zählt Mehrheiten, lässt Einzelbefunde von Sonnet nachprüfen und liefert Urteil und Bericht."
|
||||
tags: [plan, vault-tools, codeworkflow]
|
||||
created: 2026-09-29
|
||||
@@ -49,7 +49,7 @@ quorum.js (Args: anlass, projekt | ordner+dateien+uebersicht, basis?, kontext?,
|
||||
└─ Urteil, Zählung je Stimme, bericht_md; verbrauch.js am Ende (wunsch 0)
|
||||
```
|
||||
|
||||
Die Taskdateien 01 bis 04 enthalten den Code wörtlich.
|
||||
Die Taskdateien 01 bis 06 enthalten den Code wörtlich; 05 und 06 sind Nachbesserungen als Delta gegen den Baum.
|
||||
|
||||
## Codex: welcher Befehl, und warum so
|
||||
|
||||
@@ -108,7 +108,7 @@ Nachgelesen im Quelltext des Plugins `openai-codex/codex/1.0.6` (unter `~/.claud
|
||||
| 05 | `.vault-tools/quorum/quorum_werkzeug.py`, `faelle_quorum_werkzeug.py`, `mutanten_quorum_werkzeug.py`, `.claude/workflows/quorum.js` | Nachbesserung nach der Prüfung von Welle 1 (2026-09-30): Teilgruppen nach Datei und Zeilen mit Toleranz drei, `GIT_OPTIONAL_LOCKS=0`, `--summe` in `ablegen`; Delta gegen den Baum | sonnet, low | 2 |
|
||||
| 06 | `.claude/workflows/quorum.js`, `.vault-tools/workflow-pruefung/faelle_workflows.mjs`, `mutanten_workflows.py` | Nachbesserung nach dem ersten echten Lauf (2026-10-05): Freitext aus Stimmen und Nachprüfung erzeugt im Bericht keinen Wikilink, keine Einbettung und keinen Tag (`klartext()`); Delta gegen den Baum | sonnet, low | 4 |
|
||||
|
||||
Die Zieldateien sind disjunkt. **Welle 1** (Task 01, 02, 04) läuft parallel. **Welle 2** (Task 03) folgt, weil ihre Fälle und Mutanten gegen `quorum.js` aus Task 02 laufen.
|
||||
Die Zieldateien sind disjunkt. **Welle 1** (Task 01, 02, 04) läuft parallel, Task 04 wegen `CLAUDE.md` nach dem Regeltext-Task des Waisen-Plans. **Welle 2** ist Task 05, **Welle 3** Task 03, weil sein Rot-Nachweis die Sicherung aus Task 05 braucht, **Welle 4** Task 06.
|
||||
|
||||
## Messungen vor und nach den Wellen
|
||||
|
||||
@@ -130,6 +130,7 @@ Die Zieldateien sind disjunkt. **Welle 1** (Task 01, 02, 04) läuft parallel. **
|
||||
8. Byte-Vergleich: `welle_vergleich.py` je Welle gegen die Kopie mit angewendetem Plan, dazu `plan_bloecke.py nach` für Task 03 und 04 ohne Befund.
|
||||
9. M1 wie oben: Exit 0 und JSON.
|
||||
10. Lauf mit echten Daten wie unten: `status: fertig` mit Bericht, und die eingebaute Macke steht darin als Mehrheit oder als bestätigter Einzelbefund; danach ein Leerlauf mit `status: leer`.
|
||||
11. Task 06: Der erste echte Bericht und jeder folgende erzeugt im Linkcheck keinen toten Link aus zitiertem Freitext; in Obsidian zeigt eine Probenotiz mit `\[\[a/b]]`, `!\[\[c]]` und `\#tag` keinen Link, keine Einbettung und keinen Tag (Probe in der App, offen).
|
||||
|
||||
## Lauf mit echten Daten
|
||||
|
||||
@@ -186,3 +187,19 @@ Der erste echte Meilenstein eines Projekts ist der zweite Lauf mit echten Daten;
|
||||
14. **Codex-Modell und -Effort** setzt der Plan nicht; es gilt die Vorgabe der Codex-Konfiguration.
|
||||
15. **Messungen M1 bis M3** siehe oben; M2 und M3 gehen nur mit echtem Kontingent.
|
||||
16. **`updated` in `codeworkflow.md`** setzt der Koordinator beim Commit; Task 04 fasst das Frontmatter nicht an. `pending-review` entfällt, wenn Pascal Spec und Plan abnimmt, denn dann ist die Änderung angeordnet.
|
||||
|
||||
## Abschluss 2026-10-05
|
||||
|
||||
| Fertig heißt | Ergebnis | Beleg |
|
||||
|---|---|---|
|
||||
| 1 bis 3 Werkzeug | erfüllt | `faelle_quorum_werkzeug.py` 44 von 44; Rot gegen die gesicherte alte Fassung genau die 5 erwarteten Fehler; `mutanten_quorum_werkzeug.py` 46 Mutanten, 0 überlebt, 0 veraltet |
|
||||
| 4 bis 6 Workflow | erfüllt | `faelle_workflows.mjs` 248 Fälle, 0 gescheitert; Rot ohne `quorum.js` 88, mit alter Fassung 20, nach Task 06 5 erwartete Fehler; `mutanten_workflows.py` 145 Mutanten, 0 überlebt, 0 veraltet |
|
||||
| 7 regelwerk_check | erfüllt | nur der alte Befund zu `frontmatter.md` |
|
||||
| 8 Byte-Vergleich | erfüllt | je Welle Zieldateien byte-gleich mit der Kopie; `plan_bloecke nach` ohne Befund für Task 05 und 06 |
|
||||
| 9 M1 | erfüllt | im ersten echten Lauf: `status` vor dem Lauf gelesen, Stimme gültig |
|
||||
| 10 Lauf mit echten Daten | erfüllt | erster echter Lauf am 2026-09-30 in einem Code-Projekt des Vaults: drei gültige Stimmen, Codex 1 min 52 s, Urteil frei, Bericht über `ablegen` abgelegt |
|
||||
| 11 Task 06 | erfüllt bis auf die App-Probe | Linkcheck findet im ersten Bericht keinen toten Link mehr; die Probe in Obsidian steht bei Pascal |
|
||||
|
||||
- **Prüfungen:** Welle 1 (Task 01, 02) durch einen `pruefer`, dann Task 03 bis 06 zusammen: 0 blockierend, 1 wichtig, 9 klein. Der wichtige Befund (Regel und Berichtsgrund beim blockierenden Befund ohne Beleg) ist behoben: Regel in `codeworkflow.md` und Grund in `quorum.js` nennen den Fall; das Verhalten bleibt nach Offenem Punkt 8.
|
||||
- **Bewusst offen (klein):** Grenzen von `zeilen()`, `pfadnorm()` und `klartext()`, aufgeführt in `.vault-tools/quorum/LIESMICH.md`.
|
||||
- **Vermerk „noch nicht abgenommen“** in `codeworkflow.md` am 2026-10-05 entfernt; Auslöser und Sperre gelten.
|
||||
@@ -1535,6 +1535,91 @@ for (const [name, a, text] of [
|
||||
})
|
||||
}
|
||||
|
||||
// Klartext im Bericht (Nachbesserung Task 06): Stimmen, Nachprüfung und Hilfsagenten zitieren
|
||||
// Wikilink, Einbettung, Tag und Abschnittslink. Q_KLAR ist derselbe Text, wie er im Bericht
|
||||
// stehen muss: lesbar, aber ohne Link, Einbettung und Tag.
|
||||
const Q_ZITATE = '[[a/b]] ![[c]] #needs-review [[#x]]'
|
||||
const Q_KLAR = '\\[\\[a/b]] !\\[\\[c]] \\#needs-review \\[\\[\\#x]]'
|
||||
const qZ = schwere => ({ datei: 'src/a.py', stelle: Q_ZITATE, schwere, aussage: Q_ZITATE, beleg: Q_ZITATE })
|
||||
// Was Obsidian als Wikilink, Einbettung oder Tag lesen könnte. Der Tag zählt hier schon hinter
|
||||
// jedem Zeichen außer Buchstabe, Ziffer, Unterstrich und Backslash, nicht erst nach Leerraum.
|
||||
function qObsidian(text) {
|
||||
const funde = []
|
||||
if (/(^|[^!])\[\[/.test(text)) funde.push('Wikilink')
|
||||
if (text.includes('![[')) funde.push('Einbettung')
|
||||
if (/(^|[^\p{L}\p{N}_\\])#[^\s#]/u.test(text)) funde.push('Tag')
|
||||
return funde
|
||||
}
|
||||
const qSauber = (soll, text) => { const f = qObsidian(text); soll(f.length === 0, 'Obsidian-Syntax im Bericht: ' + f.join(', ')) }
|
||||
|
||||
fall('quorum', 'Klartext im Bericht: Stelle, Aussage und Beleg einer Gruppe ohne Wikilink, Einbettung und Tag, README-Link bleibt', async () => {
|
||||
const { fehler, soll } = pruefe()
|
||||
const { ergebnis: e } = await QR(Q_ARGS, { stimmen: { opus: [qZ('blockierend')], sonnet: [qZ('blockierend')], codex: [] } })
|
||||
const md = (e && e.bericht_md) || ''
|
||||
qSauber(soll, md)
|
||||
for (const z of [
|
||||
'### G1: blockierend, Mehrheit (Opus, Sonnet)\n\n`src/a.py`, Stelle ' + Q_KLAR + '\n',
|
||||
'- O1 (Opus, blockierend, Stelle ' + Q_KLAR + '): ' + Q_KLAR + '\n Beleg: ' + Q_KLAR + '\n',
|
||||
'\n\nProjekt: [README](../../README.md)\n\n',
|
||||
]) soll(md.includes(z), 'Bericht ohne ' + JSON.stringify(z))
|
||||
return fehler
|
||||
})
|
||||
|
||||
fall('quorum', 'Klartext im Bericht: Fundstelle und Begründung der Nachprüfung ohne Wikilink, Einbettung und Tag', async () => {
|
||||
const { fehler, soll } = pruefe()
|
||||
const stimmen = { opus: [qB('src/a.py', '10', 'blockierend')], sonnet: [qB('src/b.py', '5', 'hinweis')], codex: [] }
|
||||
const urteile = pr => ({ urteile: [...pr.matchAll(/^Befund ([A-Z]\d+):$/gm)].map(m => ({ id: m[1], urteil: 'bestaetigt', fundstelle: Q_ZITATE, begruendung: Q_ZITATE })) })
|
||||
const { ergebnis: e } = await QR(Q_ARGS, { stimmen, urteile })
|
||||
const md = (e && e.bericht_md) || ''
|
||||
qSauber(soll, md)
|
||||
const z = '\nNachprüfung: bestaetigt, ' + Q_KLAR + '. ' + Q_KLAR + '\n'
|
||||
soll(md.includes(z), 'Bericht ohne ' + JSON.stringify(z))
|
||||
return fehler
|
||||
})
|
||||
|
||||
fall('quorum', 'Klartext im Bericht: Unbelegt und Nicht prüfbar ohne Wikilink, Einbettung und Tag', async () => {
|
||||
const { fehler, soll } = pruefe()
|
||||
const stimmen = { opus: [{ ...qZ('wichtig'), beleg: '' }], sonnet: [qB('src/b.py', '5', 'hinweis')], codex: [] }
|
||||
const { ergebnis: e } = await QR(Q_ARGS, { stimmen, nichtPruefbar: { sonnet: [Q_ZITATE] } })
|
||||
const md = (e && e.bericht_md) || ''
|
||||
qSauber(soll, md)
|
||||
for (const z of [
|
||||
'## Unbelegt\n\n- O1 (Opus, wichtig) `src/a.py`, Stelle ' + Q_KLAR + ': ' + Q_KLAR + '\n',
|
||||
'## Nicht prüfbar\n\n- Sonnet: ' + Q_KLAR + '\n',
|
||||
]) soll(md.includes(z), 'Bericht ohne ' + JSON.stringify(z))
|
||||
return fehler
|
||||
})
|
||||
|
||||
fall('quorum', 'Klartext im Bericht: Hinweise des Laufs und Grund der Codex-Stimme ohne Wikilink, Einbettung und Tag', async () => {
|
||||
const { fehler, soll } = pruefe()
|
||||
const stimmen = { opus: [qB('src/a.py', '10', 'hinweis')], sonnet: [qB('src/b.py', '5', 'hinweis')] }
|
||||
const k = { stimmen, paket: { hinweise: [Q_ZITATE] }, codexEnde: { job_status: Q_ZITATE }, gruppen: () => ({ gruppen: [{ ids: [Q_ZITATE], begruendung: 'zitiert' }] }) }
|
||||
const { ergebnis: e } = await QR(Q_ARGS, k)
|
||||
const md = (e && e.bericht_md) || ''
|
||||
qSauber(soll, md)
|
||||
for (const z of [
|
||||
'| Codex | nein: Codex-Auftrag endete mit ' + Q_KLAR + ' |',
|
||||
'## Hinweise des Laufs\n\n- ' + Q_KLAR + '\n',
|
||||
'\n- Codex ohne gültige Stimme (Codex-Auftrag endete mit ' + Q_KLAR + '); Haiku ist eingesprungen\n',
|
||||
'\n- Zusammenführen: unbekannte ID ' + Q_KLAR + ' verworfen\n',
|
||||
]) soll(md.includes(z), 'Bericht ohne ' + JSON.stringify(z))
|
||||
return fehler
|
||||
})
|
||||
|
||||
fall('quorum', 'Klartext im Bericht eines Kundendokuments: Hub-Zeile bleibt Wikilink, Frontmatter bleibt, zitierte Syntax nicht', async () => {
|
||||
const { fehler, soll } = pruefe()
|
||||
const K = 'D:/Claude/IT Workspace/Beispiel/abgabe'
|
||||
const HUB = 'Übersicht: [[IT Workspace/Beispiel/abgabe/00 Übersicht|00 Übersicht.md]]'
|
||||
const args = { anlass: 'kundendokument', ordner: K, dateien: ['kapitel/01.md'], uebersicht: '00 Übersicht.md' }
|
||||
const paket = { anlass: 'kundendokument', art: 'doku', wurzel: K, basis: 'erstes Quorum', stand: 'sha256:' + 'c'.repeat(64), vorher: null, nummer: 1 }
|
||||
const { ergebnis: e } = await QR(args, { paket, stimmen: { opus: [qZ('blockierend')], sonnet: [qZ('blockierend')], codex: [] } })
|
||||
const md = (e && e.bericht_md) || ''
|
||||
qSauber(soll, md.replace(HUB, ''))
|
||||
soll(md.includes('\n\n' + HUB + '\n\n') && md.split('[[').length === 2, 'Hub-Zeile nicht genau einmal als Wikilink: ' + JSON.stringify(md.split('\n').filter(x => x.includes('Übersicht'))))
|
||||
for (const z of ['---\ntype: note\n', '\ntags: [quorum]\n', '- O1 (Opus, blockierend, Stelle ' + Q_KLAR + '): ' + Q_KLAR + '\n']) soll(md.includes(z), 'Bericht ohne ' + JSON.stringify(z))
|
||||
return fehler
|
||||
})
|
||||
|
||||
// ---------------------------------------------------------------- Lauf
|
||||
let gescheitert = 0
|
||||
const grundlinieGescheitert = new Set()
|
||||
|
||||
@@ -121,15 +121,15 @@ MUTANTEN = [
|
||||
("quorum", "Zeilenbereich nur erste Zeile", "const bis = m[2] === undefined ? von : Number(m[2])", "const bis = von"),
|
||||
("quorum", "Stelle ohne Zeilen zaehlt als Zeile 0", "if (!m) return null", "if (!m) return [0, 0]"),
|
||||
("quorum", "Befundzeilen der Gruppe fehlen", "for (const b of g.mitglieder) z.push(", "for (const b of []) z.push("),
|
||||
("quorum", "Stelle fehlt in der Befundzeile", ", ${b.schwere}, Stelle ${b.stelle}): ${b.aussage}", ", ${b.schwere}): ${b.aussage}"),
|
||||
("quorum", "Stelle fehlt in der Befundzeile", ", ${b.schwere}, Stelle ${klartext(b.stelle)}): ${klartext(b.aussage)}", ", ${b.schwere}): ${klartext(b.aussage)}"),
|
||||
("quorum", "Nachpruefungszeile fehlt", "if (g.nachpruefung) z.push(''", "if (false) z.push(''"),
|
||||
("quorum", "Nachpruefung ohne Fundstelle", "${g.nachpruefung.urteil}, ${g.nachpruefung.fundstelle}.", "${g.nachpruefung.urteil}."),
|
||||
("quorum", "Nachpruefung ohne Fundstelle", "${g.nachpruefung.urteil}, ${klartext(g.nachpruefung.fundstelle)}.", "${g.nachpruefung.urteil}."),
|
||||
("quorum", "Unbelegt-Liste leer", "for (const b of x.unbelegt)", "for (const b of [])"),
|
||||
("quorum", "Nicht pruefbar leer", "(x.stimmen[n].nicht_pruefbar || [])", "([])"),
|
||||
("quorum", "Hinweise des Laufs fehlen im Bericht", "const alleHinweise = [...p.hinweise, ...laufHinweise]", "const alleHinweise = []"),
|
||||
("quorum", "Lesemarke der Claude-Stimmen nicht geprueft", "lesemarke_ok: String(e.lesemarke).includes(p.lesemarke)", "lesemarke_ok: true"),
|
||||
("quorum", "Lesemarke exakt verglichen", "lesemarke_ok: String(e.lesemarke).includes(p.lesemarke)", "lesemarke_ok: String(e.lesemarke) === p.lesemarke"),
|
||||
("quorum", "Stelle fehlt in der Gruppenueberschrift", ", Stelle ${erste.stelle}", ""),
|
||||
("quorum", "Stelle fehlt in der Gruppenueberschrift", ", Stelle ${klartext(erste.stelle)}", ""),
|
||||
("quorum", "Stand statt PAKET im Frontmatter", "'stand: PAKET'", "'stand: ' + p.stand"),
|
||||
("quorum", "ablegen_befehl fehlt", "ablegen_befehl: md ? ablegenBefehl(paket) : null", "ablegen_befehl: null"),
|
||||
("quorum", "ablegen_befehl auch ohne Bericht", "ablegen_befehl: md ? ablegenBefehl(paket) : null", "ablegen_befehl: ablegenBefehl(paket)"),
|
||||
@@ -149,6 +149,23 @@ MUTANTEN = [
|
||||
("quorum", "Backslash im Ordner bleibt", "String(ordner).replace(/\\\\/g, '/')", "String(ordner)"),
|
||||
("quorum", "Stimmen kennen einander", "Die anderen Stimmen kennst du nicht.", "Die anderen Stimmen sind Opus, Sonnet und Codex."),
|
||||
("quorum", "Zusammenfuehren darf Dateien lesen", "Lies keine Dateien und fahre keine Befehle; du arbeitest nur mit dieser Liste.", "Lies die Dateien, wenn du sie brauchst."),
|
||||
("quorum", "Klartext: Klammerfolge bleibt", r".replace(/\[{2,}/g, folge => folge.replace(/\[/g, '\\['))", ""),
|
||||
("quorum", "Klartext: nur die erste Klammer entschaerft", r"folge => folge.replace(/\[/g, '\\['))", r"folge => '\\' + folge)"),
|
||||
("quorum", "Klartext: Einbettung ausgenommen", r".replace(/\[{2,}/g,", r".replace(/(?<!!)\[{2,}/g,"),
|
||||
("quorum", "Klartext: Tag bleibt", r".replace(/(^|[^\p{L}\p{N}_\\])#(?=[^\s#])/gu, '$1\\#')", ""),
|
||||
("quorum", "Klartext: Tag nur nach Leerraum", r"(^|[^\p{L}\p{N}_\\])#", r"(^|\s)#"),
|
||||
("quorum", "Klartext: Gruppenueberschrift, Stelle roh", ", Stelle ${klartext(erste.stelle)}", ", Stelle ${erste.stelle}"),
|
||||
("quorum", "Klartext: Befundzeile, Stelle roh", ", ${b.schwere}, Stelle ${klartext(b.stelle)})", ", ${b.schwere}, Stelle ${b.stelle})"),
|
||||
("quorum", "Klartext: Befundzeile, Aussage roh", "}): ${klartext(b.aussage)}", "}): ${b.aussage}"),
|
||||
("quorum", "Klartext: Beleg roh", " Beleg: ${klartext(b.beleg)}", " Beleg: ${b.beleg}"),
|
||||
("quorum", "Klartext: Nachpruefung, Fundstelle roh", "${klartext(g.nachpruefung.fundstelle)}", "${g.nachpruefung.fundstelle}"),
|
||||
("quorum", "Klartext: Nachpruefung, Begruendung roh", "${klartext(g.nachpruefung.begruendung)}", "${g.nachpruefung.begruendung}"),
|
||||
("quorum", "Klartext: Unbelegt, Stelle roh", "Stelle ${klartext(b.stelle)}: ", "Stelle ${b.stelle}: "),
|
||||
("quorum", "Klartext: Unbelegt, Aussage roh", ")}: ${klartext(b.aussage)}", ")}: ${b.aussage}"),
|
||||
("quorum", "Klartext: Nicht pruefbar roh", "- ${NAMEN[n]}: ${klartext(t)}", "- ${NAMEN[n]}: ${t}"),
|
||||
("quorum", "Klartext: Hinweise roh", "'- ' + klartext(h)", "'- ' + h"),
|
||||
("quorum", "Klartext: Stimmentabelle, Grund roh", "'nein: ' + klartext(s.grund)", "'nein: ' + s.grund"),
|
||||
("quorum", "Klartext: ganzer Bericht, Hub-Zeile entschaerft", r"return z.join('\n')", r"return klartext(z.join('\n'))"),
|
||||
]
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user