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:
Pascal MichelandClaude Opus 5.5 committed 2026-10-05 06:36:34 +02:00
1 parent 7a74a8acb9
commit ed55848b00
6 files changed
+212 -21

No files matched your search

+24 -9
View File
@@ -41,10 +41,14 @@ export const meta = {
// verfälschen; dass der Agent keine Datei liest, sagt nur sein Auftrag, ein Fall sichert den Satz.
// Nachprüfen: quorum-stimme auf sonnet für Gruppen ohne Mehrheit mit Schwere blockierend oder
// wichtig. Ein blockierender Einzelbefund ohne Urteil sperrt wie ein bestätigter.
// Urteil: frei heißt kein bestätigter und kein ungeprüfter blockierender Befund. Mit weniger als
// Urteil: frei heißt kein bestätigter und kein ungeprüfter blockierender Befund mit Beleg; ein
// blockierender Befund ohne Beleg sperrt nicht (Plan, Offener Punkt 8), der Grund nennt ihn. Mit weniger als
// zwei abgegebenen Stimmen gibt es kein Urteil und keinen Bericht, die Basis bleibt die alte.
// 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.
const ANLAESSE = ['einspielen', 'version', 'kundendokument']
const RANG = { blockierend: 0, wichtig: 1, hinweis: 2 }
const KUERZEL = { opus: 'O', sonnet: 'S', codex: 'C', haiku: 'H' }
@@ -482,6 +486,17 @@ function berichtLeer(a, p, urteil, grund) {
return [kopf(a, p, urteil, `Urteil ${urteil}: ${grund}.`, 'nicht gelaufen'), '', `# Quorum ${p.nummer}: ${a.anlass}`, '', hubZeile(a), '', '## Urteil', '', `**${urteilText(urteil)}**: Seit dem letzten Quorum hat sich nichts geändert. Das Urteil stammt aus ${vorher}; keine Stimme ist gelaufen.`, ''].join('\n')
}
// 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) {
const namen = Object.keys(x.stimmen).filter(n => x.stimmen[n].abgegeben).map(n => NAMEN[n]).join(', ')
const codexFeld = x.stimmen.codex.abgegeben ? 'abgegeben' : 'ersetzt'
@@ -492,7 +507,7 @@ function berichtVoll(a, p, x) {
const s = x.stimmen[n]
const c = x.zaehlung[n]
const name = n === 'haiku' ? 'Haiku (Ersatz für Codex)' : NAMEN[n]
z.push(`| ${name} | ${s.abgegeben ? 'ja' : 'nein: ' + s.grund} | ${c.gesamt} | ${c.belegt} | ${c.bestaetigt} | ${c.alleinfunde} | ${laufzeit(s.dauer_s)} |`)
z.push(`| ${name} | ${s.abgegeben ? 'ja' : 'nein: ' + klartext(s.grund)} | ${c.gesamt} | ${c.belegt} | ${c.bestaetigt} | ${c.alleinfunde} | ${laufzeit(s.dauer_s)} |`)
}
z.push('')
if (x.stimmen.haiku) z.push('Haiku stand statt Codex im Quorum. Dieses Quorum war nur mit Claude besetzt.', '')
@@ -501,20 +516,20 @@ function berichtVoll(a, p, x) {
if (!x.gruppen.length) z.push('keine belegten Befunde', '')
for (const g of x.gruppen) {
const erste = g.mitglieder[0]
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}`)
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)}`)
z.push('')
}
z.push('## Unbelegt', '')
if (!x.unbelegt.length) z.push('keine')
for (const b of x.unbelegt) z.push(`- ${b.id} (${NAMEN[b.stimme]}, ${b.schwere}) \`${b.datei}\`, Stelle ${b.stelle}: ${b.aussage}`)
for (const b of x.unbelegt) z.push(`- ${b.id} (${NAMEN[b.stimme]}, ${b.schwere}) \`${b.datei}\`, Stelle ${klartext(b.stelle)}: ${klartext(b.aussage)}`)
z.push('', '## Nicht prüfbar', '')
const offen = Object.keys(x.stimmen).flatMap(n => (x.stimmen[n].nicht_pruefbar || []).map(t => `- ${NAMEN[n]}: ${t}`))
const offen = Object.keys(x.stimmen).flatMap(n => (x.stimmen[n].nicht_pruefbar || []).map(t => `- ${NAMEN[n]}: ${klartext(t)}`))
z.push(...(offen.length ? offen : ['keine']))
z.push('', '## Hinweise des Laufs', '')
const alleHinweise = [...p.hinweise, ...laufHinweise]
z.push(...(alleHinweise.length ? alleHinweise.map(h => '- ' + h) : ['keine']), '')
z.push(...(alleHinweise.length ? alleHinweise.map(h => '- ' + klartext(h)) : ['keine']), '')
return z.join('\n')
}
@@ -621,7 +636,7 @@ const sperrend = gruppen.filter(g => g.schwere === 'blockierend' && (gilt(g) ||
const urteil = sperrend.length ? 'nicht_frei' : 'frei'
const grund = sperrend.length
? `${sperrend.filter(gilt).length} bestätigte und ${sperrend.filter(g => !gilt(g)).length} ungeprüfte blockierende Befunde`
: 'kein bestätigter und kein ungeprüfter blockierender Befund'
: 'kein bestätigter und kein ungeprüfter blockierender Befund mit Beleg' + (unbelegt.some(b => b.schwere === 'blockierend') ? `; ${unbelegt.filter(b => b.schwere === 'blockierend').length} blockierende ohne Beleg stehen unter Unbelegt und sperren nicht` : '')
await ablesen('Ende', 0)
const zaehlung = {}
for (const n of Object.keys(stimmen)) {