fix: Judge-Urteil auch mit Markdown erkennen („## Urteil: **PASS**“)

parseVerdict und das SHIP-Urteil erwarteten „Urteil: PASS“ ohne Markup.
Der Judge schrieb „## Urteil: **PASS WITH CONCERNS**“; jede Runde galt als
unklar, --approve-concerns griff nie. Neu: parseShipVerdict, Tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-10-15 03:16:30 +02:00
commit 65555b25f1
3 changed files with 31 additions and 2 deletions

View file

@ -860,6 +860,13 @@ Die Checkboxen werden automatisch abgehakt:
## 12. Fehlermeldungen und Lösungen
### "Urteil unklar: … Judge-Urteil nicht erkennbar"
**Ursache:** In der Judge-Antwort steht keine Zeile „Urteil: PASS | PASS WITH CONCERNS | FAIL“. Markdown dazwischen
wird erkannt (`## Urteil: **PASS**`, `**Urteil:** FAIL`); fehlt das Wort ganz, gilt die Runde als nicht bestanden.
**Lösung:** Antwort im Chat lesen, dann `/judge` erneut oder `/fix` mit der Kritik.
### "Modell-Datei nicht gefunden"
```

View file

@ -664,10 +664,17 @@ function normalizeForComparison(s: string): string {
}
function parseVerdict(text: string): string {
const m = text.match(/Urteil:\s*(PASS WITH CONCERNS|PASS|FAIL)/i);
// Markdown zwischen „Urteil“ und dem Wort ist erlaubt: „## Urteil: **PASS**“, „**Urteil:** FAIL“.
const m = text.match(/Urteil[\s*_`:]*(PASS WITH CONCERNS|PASS|FAIL)/i);
return m ? m[1].toUpperCase() : "UNREADABLE";
}
// SHIP-Urteil der Freigabe-Runde; Markdown wie bei parseVerdict erlaubt. "" wenn nicht erkennbar.
function parseShipVerdict(text: string): string {
const m = text.match(/Urteil[\s*_`:]*(NO-SHIP|SHIP)/i);
return m ? m[1].toUpperCase() : "";
}
// Extrahiert den Blocker-Abschnitt für die Loop-Erkennung.
// Erkennt Bullet-Listen (- / – / *), Bold (**Blocker**) und Headings (## Blocker).
function parseBlockers(text: string): string {
@ -1226,7 +1233,7 @@ export default function (pi: ExtensionAPI) {
currentActivity = "Judge: finale Freigabe…";
await sendAndWait(pi, ctx, shipitPrompt(args || ""));
const shipText = getLastAssistantText(ctx);
const shipVerdict = shipText.match(/Urteil:\s*(SHIP|NO-SHIP)/i)?.[1]?.toUpperCase() ?? "";
const shipVerdict = parseShipVerdict(shipText);
if (shipVerdict === "SHIP") {
await autoCommitIfDirty(pi, ctx);
notifyShipSuccess(ctx);

View file

@ -10,6 +10,7 @@ const parseBlockers = extractFn("parseBlockers");
const normalizeForComparison = extractFn("normalizeForComparison");
const licenceMd = extractFn("licenceMd");
const loopKey = extractFn("loopKey");
const parseShipVerdict = extractFn("parseShipVerdict");
test("parseVerdict: klares PASS", () => {
assert.equal(parseVerdict("Review fertig.\nUrteil: PASS\nKeine Blocker."), "PASS");
@ -102,3 +103,17 @@ test("loopKey: weder Blocker noch Major → ganzer Text", () => {
assert.equal(loopKey("Urteil: FAIL\nirgendwas"), "Urteil: FAIL\nirgendwas");
assert.equal(loopKey("## Blocker\nNone\n## Major\n-"), "## Blocker\nNone\n## Major\n-");
});
test("parseVerdict: Urteil in Markdown-Fett (Strata-Judge 15.10.)", () => {
assert.equal(parseVerdict("## Urteil: **PASS WITH CONCERNS**\n### Blocker"), "PASS WITH CONCERNS");
assert.equal(parseVerdict("**Urteil:** FAIL"), "FAIL");
assert.equal(parseVerdict("## Urteil: **PASS**"), "PASS");
assert.equal(parseVerdict("Urteil: `PASS`"), "PASS");
});
test("parseShipVerdict: SHIP, NO-SHIP, Markdown, unklar", () => {
assert.equal(parseShipVerdict("Urteil: SHIP"), "SHIP");
assert.equal(parseShipVerdict("## Urteil: **NO-SHIP**"), "NO-SHIP");
assert.equal(parseShipVerdict("**Urteil:** ship"), "SHIP");
assert.equal(parseShipVerdict("kein Urteil"), "");
});