.vault-tools (ohne trading-plattform-pruefung und watermarks-remover), .claude/agents, .claude/skills, .claude/workflows, .claude/settings.json. Co-Authored-By: Claude Opus 5.5 <[email protected]>
28 KiB
type, title, status, summary, tags, created, updated, modell, effort, modell_begruendung
| type | title | status | summary | tags | created | updated | modell | effort | modell_begruendung | |||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| plan-task | Task 06 — Nachbesserung: Bericht entschärft Obsidian-Syntax aus Stimmen und Nachprüfung | draft | quorum.js schickt jeden Freitext aus Stimmen, Zusammenführen und Nachprüfung durch eine neue Funktion klartext(), damit zitierte Wikilinks, Einbettungen und Tags im Bericht lesbarer Klartext bleiben; Hub-Zeile und Frontmatter bleiben unverändert. |
|
2026-10-05 | 2026-10-05 | sonnet | low | Abschrift per plan_materialisiere.py mit genannten Zieldateien und Verboten, ohne Fließtext und ohne typografische Zeichen in Codeblöcken; sonnet mit effort low statt haiku, weil der Mutantenlauf länger dauert als ein Aufruf des Bash-Werkzeugs und im Hintergrund gestartet und abgefragt werden muss. |
Übersicht: 00-uebersicht.md
Task 06 — Nachbesserung: Bericht entschärft Obsidian-Syntax aus Stimmen und Nachprüfung
Die globalen Vorgaben stehen in 00-uebersicht.md im selben Ordner, Abschnitt „Globale Vorgaben“. Arbeitsverzeichnis ist D:/Claude.
Voraussetzung: Task 01 bis 05 sind angewendet und committet. Dieser Task ist ein Delta gegen den heutigen Baum; die Taskdateien 01 bis 05 bleiben unverändert.
Anlass
quorum.jsübernimmt Freitext aus Stimmen, Zusammenführen und Nachprüfung ungefiltert inbericht_md.- Zitiert eine Stimme Obsidian-Syntax, wird sie im Vault lebendig. Beleg: Der erste echte Bericht enthält zwei tote Wikilinks, einen unter „Nicht prüfbar“, einen in einer Befundaussage; der Linkcheck meldet beide, im Graphen entstehen Geisterknoten.
- Ein zitierter Tag wie
#needs-reviewwürde den Bericht als Review-Notiz zählen lassen, eine Einbettung wie![[c]]eine fremde Datei einbetten. - Der erste echte Bericht selbst wird hier nicht angefasst (offener Punkt unten).
Entscheidung: Backslash vor Klammer und Raute
Eine neue Funktion klartext() setzt einen Backslash vor jede öffnende eckige Klammer in einer Folge von zwei oder mehr und vor jede Raute, die einen Tag beginnen könnte. Die Leseansicht zeigt den Text wie zitiert.
| Zitat der Stimme | im Quelltext des Berichts | Regel |
|---|---|---|
[[a/b]] |
\[\[a/b]] |
Klammerfolge |
![[c]] |
!\[\[c]] |
Klammerfolge, das ! bleibt |
#needs-review |
\#needs-review |
Raute am Wortanfang vor einem Zeichen, das kein Leerraum und keine Raute ist |
[[#x]] |
\[\[\#x]] |
beides; vor der Raute steht eine Klammer, kein Buchstabe |
x = 1 # Kommentar |
unverändert | Raute vor Leerzeichen |
C#, seite.md#abschnitt |
unverändert | am Wortende bzw. Buchstabe davor |
Warum diese Form:
- Backslash ist das Markdown-Escape für
[und#(CommonMark erlaubt es für jedes ASCII-Satzzeichen). Es wirkt je Zeichen, braucht keine Grenzen eines Links und ändert bei zweiter Anwendung nichts mehr. - Backticks um das Zitat scheiden aus: Freitext trägt selbst Backticks, dann bricht die Code-Spanne, und Anfang und Ende jedes Links müssten erkannt werden.
- Gelesen im Quelltext der Vault-Werkzeuge:
linkcheck.pyundwaisen.pysehen in\[\[x]]keinen Link (Befund des Koordinators).sitzungsstart.pyzählt#needs-reviewnur nach Leerraum oder am Zeilenanfang (Regex(?<!\S)#needs-review, Zeile 66),\#needs-reviewalso nicht. - Nicht gemessen: Ob Obsidian 1.13.7 den Backslash vor Wikilink, Einbettung und Tag beachtet (Leseansicht, Live-Vorschau, Graph, Tag-Index,
Review-Queue.base). Das bestätigen Pascal oder der Koordinator in der App, siehe „Offene Punkte“. - Die Tag-Regel ist bewusst weiter als die, die Obsidian vermutlich anwendet (nur nach Leerraum): Sie entschärft auch eine Raute hinter
[,(oder einem Anführungszeichen. Kostet nur einen Backslash im Quelltext.
Wo klartext() greift und wo nicht:
Stelle in bericht_md |
Quelle | entschärft |
|---|---|---|
| Stimmentabelle, Spalte abgegeben, Grund | Codex-Hilfsagent (job_status), Absturzmeldung |
ja |
| Gruppenüberschrift, Stelle | Stimme | ja |
| Befundzeile, Stelle und Aussage; Beleg | Stimme | ja |
| Nachprüfung, Fundstelle und Begründung | Nachprüfung | ja |
| Unbelegt, Stelle und Aussage | Stimme | ja |
| Nicht prüfbar | Stimme | ja |
| Hinweise des Laufs | Paket, Zusammenführen (IDs, Stellen), Codex-Grund | ja |
Hub-Zeile (Projekt: … bzw. Übersicht: …) |
Workflow | nein, bleibt Link |
| Frontmatter, Urteil-Zeile, Basis und Stand | Workflow, Paket | nein |
| Datei in Backticks | Stimme | nein, Obsidian lässt Code-Spannen in Ruhe |
Felder des JSON-Ergebnisses (gruppen, hinweise) |
alle | nein, sie gehen nicht in den Vault |
Die Fälle und Mutanten unten binden genau diese Form. Fällt die Bestätigung in Obsidian negativ aus, braucht es eine neue Nachbesserung mit anderer Form, anderen Erwartungstexten und anderen Mutanten.
Zieldateien
D:\Claude\.vault-tools\workflow-pruefung\faelle_workflows.mjs(geändert)D:\Claude\.vault-tools\workflow-pruefung\mutanten_workflows.py(geändert)D:\Claude\.claude\workflows\quorum.js(geändert)
Verbote
- Keine andere Datei im Vault, auch nicht
attrappe.mjs, die übrigen Workflows, die Taskdateien 01 bis 05 und kein Bericht unterdocs/quorum/eines Projekts. - Außerhalb des Vaults nur der Arbeitsordner
/tmp/quorum-task06in der Git-Bash. Ihn nicht löschen; der Koordinator räumt ihn nach der Prüfung. - Kein Lauf eines echten Workflows, kein Aufruf des Codex-Plugins.
- Nichts von Hand schreiben oder umformulieren; die Blöcke wendet nur
plan_materialisiere.pyan, in den Baum kommen sie nur percpaus dem Arbeitsordner. Ein Widerspruch zwischen Plan und Baum wird gemeldet. - Während der Mutantenlauf läuft, keine Datei unter
.claude/workflows/und.vault-tools/workflow-pruefung/ändern. - Kein Commit, kein
git add.
Schritt 1 — Vorprüfung
python D:/Claude/.vault-tools/plan-kopie/plan_bloecke.py vor D:/Claude/.vault-tools/workflow-pruefung/docs/plans/2026-09-29-quorum/task-06-bericht-entschaerfen.md --projekt D:/Claude
Erwartet: 0 Befund(e). Merk dir die Zahl hinter geprueft:, Schritt 2 vergleicht damit. Bei einem Befund anhalten und melden.
GIT_OPTIONAL_LOCKS=0 git -C D:/Claude status --porcelain -- .claude/workflows .vault-tools/workflow-pruefung; echo "ENDE"; node D:/Claude/.vault-tools/workflow-pruefung/faelle_workflows.mjs | tail -n 1; echo "EXIT ${PIPESTATUS[0]}"
Erwartet: direkt ENDE (beide Ordner sauber), dann eine Zeile mit 0 gescheitert, dann EXIT 0. Steht vor ENDE eine Zeile oder scheitert ein Fall: anhalten und melden.
Schritt 2 — Blöcke in einem Arbeitsordner anwenden
Der Arbeitsordner trägt Kopien der drei Zieldateien. So kommen Fälle und Mutanten in Schritt 3 vor der Umsetzung in Schritt 4 in den Baum.
A="$(cygpath -m -l /tmp)/quorum-task06" && mkdir "$A" && mkdir -p "$A/k/.claude/workflows" "$A/k/.vault-tools/workflow-pruefung" && cp D:/Claude/.claude/workflows/quorum.js "$A/k/.claude/workflows/" && cp D:/Claude/.vault-tools/workflow-pruefung/faelle_workflows.mjs D:/Claude/.vault-tools/workflow-pruefung/mutanten_workflows.py "$A/k/.vault-tools/workflow-pruefung/" && python D:/Claude/.vault-tools/plan-kopie/plan_materialisiere.py D:/Claude/.vault-tools/workflow-pruefung/docs/plans/2026-09-29-quorum "$A/k" task-06-bericht-entschaerfen.md; echo "EXIT $?"
Erwartet: In der Zählerzeile 'neu': 0, 'angehaengt': 0, 'geloescht': 0 und 'ersetzt' gleich der Zahl hinter geprueft: aus Schritt 1; dann 0 Befund(e). und EXIT 0. Scheitert mkdir "$A", weil der Ordner schon da ist: anhalten und melden, nichts löschen.
Fälle in .vault-tools/workflow-pruefung/faelle_workflows.mjs
Neue Fälle am Ende des Abschnitts quorum. Jeder lässt Stimmen, Nachprüfung oder Hilfsagenten Wikilink, Einbettung, Tag und Abschnittslink zitieren und verlangt: im Bericht keins davon, der Text steht lesbar in der Form aus der Tabelle oben, die Linkzeile des Workflows bleibt ein Link.
Aus:
// ---------------------------------------------------------------- Lauf
wird:
// 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
Mutanten in .vault-tools/workflow-pruefung/mutanten_workflows.py
Drei bestehende Mutanten zielen auf Stellen, die jetzt klartext() tragen; ohne Anpassung meldet der Lauf sie als veraltet.
Aus:
("quorum", "Stelle fehlt in der Befundzeile", ", ${b.schwere}, Stelle ${b.stelle}): ${b.aussage}", ", ${b.schwere}): ${b.aussage}"),
wird:
("quorum", "Stelle fehlt in der Befundzeile", ", ${b.schwere}, Stelle ${klartext(b.stelle)}): ${klartext(b.aussage)}", ", ${b.schwere}): ${klartext(b.aussage)}"),
Aus:
("quorum", "Nachpruefung ohne Fundstelle", "${g.nachpruefung.urteil}, ${g.nachpruefung.fundstelle}.", "${g.nachpruefung.urteil}."),
wird:
("quorum", "Nachpruefung ohne Fundstelle", "${g.nachpruefung.urteil}, ${klartext(g.nachpruefung.fundstelle)}.", "${g.nachpruefung.urteil}."),
Aus:
("quorum", "Stelle fehlt in der Gruppenueberschrift", ", Stelle ${erste.stelle}", ""),
wird:
("quorum", "Stelle fehlt in der Gruppenueberschrift", ", Stelle ${klartext(erste.stelle)}", ""),
Neue Mutanten, alle mit dem Namensanfang Klartext:. Die ersten bauen eine falsche Regel in klartext() ein (Klammerfolge, erste Klammer, Einbettung, Tag, Abschnittslink), die folgenden lassen je eine Stelle roh, der letzte entschärft den ganzen Bericht samt Hub-Zeile. Muster mit Backslash stehen als Python-Raw-String mit Präfix r, damit der Backslash wörtlich bleibt.
Aus:
("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."),
]
wird:
("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'))"),
]
Welcher Fall welchen Mutanten fängt:
| Mutant | rot wird mindestens |
|---|---|
| Regel-Mutanten (Klammerfolge, erste Klammer, Einbettung, Tag, Tag nach Leerraum) | jeder neue Fall |
| Gruppenüberschrift, Befundzeile, Beleg | Stelle, Aussage und Beleg einer Gruppe |
| Nachprüfung, Fundstelle und Begründung | Fundstelle und Begründung der Nachprüfung |
| Unbelegt, Nicht prüfbar | Unbelegt und Nicht prüfbar |
| Hinweise, Stimmentabelle | Hinweise des Laufs und Grund der Codex-Stimme |
| ganzer Bericht | Bericht eines Kundendokuments (Hub-Zeile), dazu die bestehenden Hub-Fälle mit Wikilink |
Umsetzung in .claude/workflows/quorum.js
Kopfkommentar:
Aus:
// Laufzeit: Date.now() und new Date() gibt es im Laufzeitsystem nicht. Die Codex-Laufzeit kommt
// aus dem Job, die der Claude-Stimmen steht im Bericht als nicht gemessen.
wird:
// Laufzeit: Date.now() und new Date() gibt es im Laufzeitsystem nicht. Die Codex-Laufzeit kommt
// aus dem Job, die der Claude-Stimmen steht im Bericht als nicht gemessen.
// Bericht: Freitext aus Stimmen, Zusammenführen und Nachprüfung geht nur durch klartext() in
// bericht_md. Ein zitierter Wikilink, eine Einbettung oder ein Tag würde im Vault sonst lebendig;
// Hub-Zeile und Frontmatter baut der Workflow selbst, sie bleiben echte Links bzw. Felder.
Neue Funktion klartext() vor berichtVoll():
Aus:
function berichtVoll(a, p, x) {
wird:
// Freitext als Klartext für Obsidian: Jede öffnende eckige Klammer in einer Folge von zwei oder
// mehr bekommt einen Backslash, damit kein Wikilink und keine Einbettung entsteht. Eine Raute
// bekommt einen Backslash, wenn ihr kein Buchstabe, keine Ziffer, kein Unterstrich und kein
// Backslash vorausgeht und weder Leerraum noch eine zweite Raute folgt; so entsteht kein Tag.
// Die Leseansicht zeigt den Text wie zitiert. Zweimal angewendet ändert sich nichts mehr.
function klartext(s) {
return String(s)
.replace(/\[{2,}/g, folge => folge.replace(/\[/g, '\\['))
.replace(/(^|[^\p{L}\p{N}_\\])#(?=[^\s#])/gu, '$1\\#')
}
function berichtVoll(a, p, x) {
Stimmentabelle, Grund einer nicht abgegebenen Stimme:
Aus:
z.push(`| ${name} | ${s.abgegeben ? 'ja' : 'nein: ' + s.grund} | ${c.gesamt} | ${c.belegt} | ${c.bestaetigt} | ${c.alleinfunde} | ${laufzeit(s.dauer_s)} |`)
wird:
z.push(`| ${name} | ${s.abgegeben ? 'ja' : 'nein: ' + klartext(s.grund)} | ${c.gesamt} | ${c.belegt} | ${c.bestaetigt} | ${c.alleinfunde} | ${laufzeit(s.dauer_s)} |`)
Gruppenüberschrift, Befundzeilen, Beleg und Nachprüfung:
Aus:
z.push(`### G${g.nr}: ${g.schwere}, ${STATUS_TEXT[g.status]} (${g.stimmen.map(n => NAMEN[n]).join(', ')})`, '', `\`${erste.datei}\`, Stelle ${erste.stelle}`, '')
for (const b of g.mitglieder) z.push(`- ${b.id} (${NAMEN[b.stimme]}, ${b.schwere}, Stelle ${b.stelle}): ${b.aussage}`, ` Beleg: ${b.beleg}`)
if (g.nachpruefung) z.push('', `Nachprüfung: ${g.nachpruefung.urteil}, ${g.nachpruefung.fundstelle}. ${g.nachpruefung.begruendung}`)
wird:
z.push(`### G${g.nr}: ${g.schwere}, ${STATUS_TEXT[g.status]} (${g.stimmen.map(n => NAMEN[n]).join(', ')})`, '', `\`${erste.datei}\`, Stelle ${klartext(erste.stelle)}`, '')
for (const b of g.mitglieder) z.push(`- ${b.id} (${NAMEN[b.stimme]}, ${b.schwere}, Stelle ${klartext(b.stelle)}): ${klartext(b.aussage)}`, ` Beleg: ${klartext(b.beleg)}`)
if (g.nachpruefung) z.push('', `Nachprüfung: ${g.nachpruefung.urteil}, ${klartext(g.nachpruefung.fundstelle)}. ${klartext(g.nachpruefung.begruendung)}`)
Unbelegt:
Aus:
for (const b of x.unbelegt) z.push(`- ${b.id} (${NAMEN[b.stimme]}, ${b.schwere}) \`${b.datei}\`, Stelle ${b.stelle}: ${b.aussage}`)
wird:
for (const b of x.unbelegt) z.push(`- ${b.id} (${NAMEN[b.stimme]}, ${b.schwere}) \`${b.datei}\`, Stelle ${klartext(b.stelle)}: ${klartext(b.aussage)}`)
Nicht prüfbar:
Aus:
const offen = Object.keys(x.stimmen).flatMap(n => (x.stimmen[n].nicht_pruefbar || []).map(t => `- ${NAMEN[n]}: ${t}`))
wird:
const offen = Object.keys(x.stimmen).flatMap(n => (x.stimmen[n].nicht_pruefbar || []).map(t => `- ${NAMEN[n]}: ${klartext(t)}`))
Hinweise des Laufs:
Aus:
z.push(...(alleHinweise.length ? alleHinweise.map(h => '- ' + h) : ['keine']), '')
wird:
z.push(...(alleHinweise.length ? alleHinweise.map(h => '- ' + klartext(h)) : ['keine']), '')
Schritt 3 — Fälle und Mutanten in den Baum, Rot im Wortlaut
quorum.js im Baum ist noch die alte Fassung; sie ist die falsche Umsetzung, an der jeder neue Fall rot werden muss.
A="$(cygpath -m -l /tmp)/quorum-task06" && cp "$A/k/.vault-tools/workflow-pruefung/faelle_workflows.mjs" "$A/k/.vault-tools/workflow-pruefung/mutanten_workflows.py" D:/Claude/.vault-tools/workflow-pruefung/ && node D:/Claude/.vault-tools/workflow-pruefung/faelle_workflows.mjs > "$A/rot.txt"; echo "EXIT $?"; grep -A 1 --no-group-separator '^FEHLER' "$A/rot.txt"; grep '^HINWEIS' "$A/rot.txt"; echo "ENDE"
Erwartet genau diese Ausgabe, Zeile für Zeile:
EXIT 1
FEHLER quorum: Klartext im Bericht: Stelle, Aussage und Beleg einer Gruppe ohne Wikilink, Einbettung und Tag, README-Link bleibt
Obsidian-Syntax im Bericht: Wikilink, Einbettung, Tag
FEHLER quorum: Klartext im Bericht: Fundstelle und Begründung der Nachprüfung ohne Wikilink, Einbettung und Tag
Obsidian-Syntax im Bericht: Wikilink, Einbettung, Tag
FEHLER quorum: Klartext im Bericht: Unbelegt und Nicht prüfbar ohne Wikilink, Einbettung und Tag
Obsidian-Syntax im Bericht: Wikilink, Einbettung, Tag
FEHLER quorum: Klartext im Bericht: Hinweise des Laufs und Grund der Codex-Stimme ohne Wikilink, Einbettung und Tag
Obsidian-Syntax im Bericht: Wikilink, Einbettung, Tag
FEHLER quorum: Klartext im Bericht eines Kundendokuments: Hub-Zeile bleibt Wikilink, Frontmatter bleibt, zitierte Syntax nicht
Obsidian-Syntax im Bericht: Wikilink, Einbettung, Tag
ENDE
- Jede Zeile unter einer
FEHLER-Zeile beginnt mit sieben Leerzeichen. - Keine Zeile
HINWEIS: Die Grundlinie des Quorums bleibt grün. - Weicht die Ausgabe ab: nichts anpassen, anhalten,
rot.txtvollständig melden.
Schritt 4 — Umsetzung in den Baum, grün, Byte-Vergleich
A="$(cygpath -m -l /tmp)/quorum-task06" && cp "$A/k/.claude/workflows/quorum.js" D:/Claude/.claude/workflows/ && node D:/Claude/.vault-tools/workflow-pruefung/faelle_workflows.mjs > "$A/gruen.txt"; echo "EXIT $?"; grep -E '^(FEHLER|HINWEIS)' "$A/gruen.txt"; tail -n 1 "$A/gruen.txt"; echo "ENDE"
Erwartet: EXIT 0, dann genau eine Zeile, die 0 gescheitert enthält, dann ENDE.
A="$(cygpath -m -l /tmp)/quorum-task06" && cmp "$A/k/.claude/workflows/quorum.js" D:/Claude/.claude/workflows/quorum.js && cmp "$A/k/.vault-tools/workflow-pruefung/faelle_workflows.mjs" D:/Claude/.vault-tools/workflow-pruefung/faelle_workflows.mjs && cmp "$A/k/.vault-tools/workflow-pruefung/mutanten_workflows.py" D:/Claude/.vault-tools/workflow-pruefung/mutanten_workflows.py; echo "EXIT $?"; GIT_OPTIONAL_LOCKS=0 git -C D:/Claude status --porcelain -- .claude/workflows .vault-tools/workflow-pruefung; echo "ENDE"
Erwartet: EXIT 0 ohne Ausgabe von cmp, dann je eine Zeile M .claude/workflows/quorum.js, M .vault-tools/workflow-pruefung/faelle_workflows.mjs und M .vault-tools/workflow-pruefung/mutanten_workflows.py in der Reihenfolge, die git ausgibt, keine weitere, dann ENDE.
python D:/Claude/.vault-tools/plan-kopie/plan_bloecke.py nach D:/Claude/.vault-tools/workflow-pruefung/docs/plans/2026-09-29-quorum/task-06-bericht-entschaerfen.md --projekt D:/Claude
Erwartet: 0 Befund(e).
Schritt 5 — Mutantenlauf im Hintergrund
Der Lauf fährt für jeden Mutanten alle Fälle; zuletzt dauerte er etwa 25 Minuten, mit den neuen Mutanten etwas länger. Das ist länger als ein Aufruf des Bash-Werkzeugs, deshalb im Hintergrund.
Starten, im Bash-Werkzeug mit run_in_background: true:
A="$(cygpath -m -l /tmp)/quorum-task06" && PYTHONIOENCODING=utf-8 python -u D:/Claude/.vault-tools/workflow-pruefung/mutanten_workflows.py > "$A/mutanten.txt" 2>&1; echo "EXIT $?" >> "$A/mutanten.txt"
Abfragen, im Bash-Werkzeug mit timeout 400000; wiederholen, bis die letzte Zeile mit EXIT beginnt:
sleep 300; A="$(cygpath -m -l /tmp)/quorum-task06" && tail -n 2 "$A/mutanten.txt"
Auswerten:
A="$(cygpath -m -l /tmp)/quorum-task06" && grep -E '^(UEBERLEBT|VERALTET)' "$A/mutanten.txt"; echo "---"; grep -E 'quorum: (Klartext: |Stelle fehlt in der Befundzeile|Nachpruefung ohne Fundstelle|Stelle fehlt in der Gruppenueberschrift)' "$A/mutanten.txt"; echo "---"; tail -n 2 "$A/mutanten.txt"
Erwartet:
- Vor dem ersten
---keine Zeile. - Zwischen den beiden
---je eine Zeile für jeden Mutanten mit dem NamensanfangKlartext:aus dem Block oben und für die drei angepassten; jede beginnt mitGEFANGEN. - Danach eine Zeile, die auf
0 ueberlebt, 0 veraltetendet, undEXIT 0.
Meldung
Melde alle Ausgaben der Schritte 1 bis 5 vollständig, dazu die Zahl hinter geprueft: aus Schritt 1 und den Wert von 'ersetzt' aus Schritt 2. Läuft etwas anders als erwartet: nichts anpassen, melden, mit jeder FEHLER-, UEBERLEBT- oder VERALTET-Zeile und ihrem Text.
Offene Punkte
- Obsidian-Bestätigung (Pascal oder Koordinator, vor der Abnahme): In Obsidian 1.13.7 bestätigen, dass die gewählte Form keinen Link, keine Einbettung und keinen Tag erzeugt. Vorschlag: eine Probenotiz mit den vier Zeilen
\[\[a/b]],!\[\[c]],\#needs-review,\[\[\#x]]als Fließtext anlegen, dann Leseansicht und Live-Vorschau ansehen, ausgehende Links, Tag-Bereich, Graph undReview-Queue.baseprüfen und die Notiz wieder löschen. Fällt die Probe negativ aus, ist eine neue Nachbesserung nötig (andere Form, andere Erwartungstexte, andere Mutanten). - Der erste echte Bericht behält seine zwei toten Wikilinks. Ob sie von Hand in dieselbe Form gebracht werden, entscheidet der Koordinator; dieser Task fasst keinen Bericht an.
- Lauf mit echten Daten: Beim nächsten echten Quorum den abgelegten Bericht mit
linkcheck.pyprüfen; erwartet ist kein toter Link aus dem Bericht. Zitiert dort eine Stimme Obsidian-Syntax, ist das zugleich die Probe in der App. - Übersicht: Tasktabelle um Task 06 ergänzen; das zieht der Koordinator nach.
Risiken
- Weitere Markdown-Syntax im Freitext bleibt lebendig: ein Markdown-Link der Form Klammer-Text-Klammer mit Pfad dahinter (relativ zum Berichtsordner meist tot), eine Raute mit Leerzeichen am Zeilenanfang eines mehrzeiligen Texts (Überschrift), ein senkrechter Strich im Grund der Stimmentabelle (zerlegt die Zeile). Nicht im Umfang; der Linkcheck meldet tote Markdown-Links nicht.
- Backslash in Code-Spannen sichtbar: Steht zitierte Syntax im Freitext selbst zwischen Backticks, zeigt die Leseansicht dort den Backslash mit. Lesbar, aber nicht wörtlich.
- Lauf über 10 Minuten: Bricht die Abfrage ab oder endet
mutanten.txtohneEXIT-Zeile, ist der Lauf nicht fertig oder gestorben; dann nicht neu starten, sondern melden.