From a3a1eab69d9aed56c106b01489f9ff30c3fd8d1a Mon Sep 17 00:00:00 2001 From: Cuarroc <47299143+Cuarroc@users.noreply.github.com> Date: Thu, 22 Oct 2026 14:02:53 +0200 Subject: [PATCH 1/5] test(diagrams): reproduce comment loss inside SVG CDATA Exercise the public stripper with literal expected SVG strings and retain the observed removal behavior for malformed comment openers. Test-First: docs/diagrams/strip-comments.test.mjs::stripComments preserves literal comment text in CDATA Test-First: docs/diagrams/strip-comments.test.mjs::stripComments retains removal behavior outside CDATA Co-Authored-By: GPT-6.1 Sol --- docs/diagrams/strip-comments.test.mjs | 44 +++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/diagrams/strip-comments.test.mjs diff --git a/docs/diagrams/strip-comments.test.mjs b/docs/diagrams/strip-comments.test.mjs new file mode 100644 index 00000000..addf1cb2 --- /dev/null +++ b/docs/diagrams/strip-comments.test.mjs @@ -0,0 +1,44 @@ +import { test } from 'node:test'; +import assert from 'node:assert/strict'; +import { stripComments } from './strip-comments.mjs'; + +test('stripComments preserves literal comment text in CDATA', () => { + const cases = [ + [ + 'A <!-- literal --> B', + 'A <!-- literal --> B', + ], + [ + '<!-- unfinished', + '<!-- unfinished', + ], + [ + '<!<!---->-->', + '<!<!---->-->', + ], + [ + '<!-- keep -->', + '<!-- keep -->', + ], + [ + 'left <!-- a --><!-- b --> right', + 'left <!-- a --><!-- b --> right', + ], + ]; + for (const [input, expected] of cases) assert.equal(stripComments(input), expected); +}); + +test('stripComments retains removal behavior outside CDATA', () => { + const cases = [ + ['', ''], + ['', ''], + ['<!-- literal -->', '<!-- literal -->'], + ['-->', '>'], + ['--', ''], + ['', ''], + ['<!-- x -->', ''], + ['aDATA[--x]]>', ''], + ]; + for (const [input, expected] of cases) assert.equal(stripComments(input), expected); +}); From 417eec28c40acde3a83a31059dd96d612dfca354 Mon Sep 17 00:00:00 2001 From: Cuarroc <47299143+Cuarroc@users.noreply.github.com> Date: Thu, 22 Oct 2026 14:04:26 +0200 Subject: [PATCH 2/5] fix(diagrams): preserve literal SVG comments inside CDATA Protect original CDATA spans before applying the existing fixed-point comment removal to surrounding markup. Ignore CDATA-looking text in real comments, and keep removing openers assembled by earlier removals. Test-First: docs/diagrams/strip-comments.test.mjs::stripComments preserves literal comment text in CDATA Test-First: docs/diagrams/strip-comments.test.mjs::stripComments retains removal behavior outside CDATA Co-Authored-By: GPT-6.1 Sol --- docs/diagrams/strip-comments.mjs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/diagrams/strip-comments.mjs b/docs/diagrams/strip-comments.mjs index 544abd6a..890c3a4c 100644 --- a/docs/diagrams/strip-comments.mjs +++ b/docs/diagrams/strip-comments.mjs @@ -1,8 +1,21 @@ // Separate from export-svg.mjs so tests can import it without Chromium or argv. +export function stripComments(s) { + const parts = []; + let start = 0; + // Match comments too, so CDATA-looking text inside a comment is not protected. + for (const match of s.matchAll(/|)?/g)) { + if (!match[0].startsWith('-->`), so none survives (CodeQL js/incomplete-multi-character-sanitization). -export function stripComments(s) { +function stripMarkupComments(s) { let prev; do { prev = s; s = s.replace(/)?/g, ''); } while (s !== prev); return s; From 9208233c0c67a25c7dd3b71df32001a9464d5b57 Mon Sep 17 00:00:00 2001 From: Cuarroc <47299143+Cuarroc@users.noreply.github.com> Date: Thu, 22 Oct 2026 19:25:36 +0200 Subject: [PATCH 3/5] test(diagrams): reproduce comment leak after a processing instruction Assert literal public API output for CDATA-looking processing instruction content before real comments and genuine CDATA. Regression-For: 417eec28c40acde3a83a31059dd96d612dfca354 Co-Authored-By: GPT-6.1 Sol --- docs/diagrams/strip-comments.test.mjs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/diagrams/strip-comments.test.mjs b/docs/diagrams/strip-comments.test.mjs index addf1cb2..f6a28854 100644 --- a/docs/diagrams/strip-comments.test.mjs +++ b/docs/diagrams/strip-comments.test.mjs @@ -2,6 +2,24 @@ import { test } from 'node:test'; import assert from 'node:assert/strict'; import { stripComments } from './strip-comments.mjs'; +test('stripComments treats processing instructions as opaque before CDATA', () => { + const cases = [ + [ + 'x', + 'x', + ], + [ + ' ?><!-- keep -->', + ' ?><!-- keep -->', + ], + [ + '<?probe <!-- keep --> ?>', + '<?probe <!-- keep --> ?>', + ], + ]; + for (const [input, expected] of cases) assert.equal(stripComments(input), expected); +}); + test('stripComments preserves literal comment text in CDATA', () => { const cases = [ [ From 9cf8738d1b5afc7a597697b3cfa193c9898ca9a8 Mon Sep 17 00:00:00 2001 From: Cuarroc <47299143+Cuarroc@users.noreply.github.com> Date: Thu, 22 Oct 2026 19:27:13 +0200 Subject: [PATCH 4/5] fix(diagrams): preserve processing instructions before scanning CDATA Consume processing instructions as opaque spans before recognizing CDATA. Remove following markup comments and preserve genuine CDATA bytes. Reconcile only the FU-1015 plan row with the partial delivery and outstanding siblings. Regression-For: 417eec28c40acde3a83a31059dd96d612dfca354 Co-Authored-By: GPT-6.1 Sol --- docs/PLAN.md | 2 +- docs/diagrams/strip-comments.mjs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/PLAN.md b/docs/PLAN.md index 86ab7b5a..b71a5a19 100644 --- a/docs/PLAN.md +++ b/docs/PLAN.md @@ -362,7 +362,7 @@ Quelle: `opt-ci-merge-20261015.md` (pa-orch); Dispatch laut Root, Ereignisse 16: | OPT-PIPE-0 | Durchlauf ausschließlich lesend messen | srv-opt-pipeline; Root klärt Basis | korrekte Auftragsbasis | Server | C (Bericht) | Blockiert: geplant nach Basisklärung; Server-Auftrag srv-opt-pipeline endete 16:12 MESZ wegen HEAD-Abweichung | Messbericht mit Methode und Einheiten; keine Implementierung | OPT-PIPE-0 | | CI-SEC-CODEQL | [Archiv][pakete] | Root | – | – | B | Erledigt: #1581 (merged 2026-10-15T18:25:41Z, `ded1eef5`); Alarm 57 laut GitHub Code Scanning `fixed` | siehe Archiv | – | | CI-SEC-CODEQL-2 | [Archiv][pakete] | Root; `.github/` gehört laut CODEOWNERS dem Nutzer | Nutzerentscheid CODEQL-59-60 | – | B | Erledigt: CodeQL-Alarme 59/60 am 16.10.2026 nach Owner-Entscheid K1 (A: als Fehlalarm abweisen) als false positive abgewiesen (GitHub: `dismissed`, 00:08:30/31 UTC); neu prüfen bei Änderungen an Cache/Event-Konfiguration in `ci.yml` | siehe Archiv | – | -| FU-1015 | Nachläufer aus den Reviews vom 15.10.: #1551 G3 (KR-09m), #1556 K4 und toter CSS-Rest (KR-08a), #1560 K2 (CI-SPLIT-LINUX), #1561 G2 (DS-01), #1568 Lows (FABRIK-TAB-1), #1569 B1/B3 (KR-04a), #1581 K1/K3–K5 (CI-SEC-CODEQL) | Root disponiert | jeweiliger Eltern-PR gemergt | – | je Punkt | Geplant: nicht disponiert (laut Root, Stand 15.10.) | je Punkt eigenes Paket ≤ 300 Zeilen mit eigener Abnahme | – | +| FU-1015 | Nachläufer aus den Reviews vom 15.10.: #1551 G3 (KR-09m), #1556 K4 und toter CSS-Rest (KR-08a), #1560 K2 (CI-SPLIT-LINUX), #1561 G2 (DS-01), #1568 Lows (FABRIK-TAB-1), #1569 B1/B3 (KR-04a), #1581 K1/K3–K5 (CI-SEC-CODEQL) | Root disponiert | jeweiliger Eltern-PR gemergt | – | je Punkt | In Arbeit: Teillieferung #1581 K1 durch diesen PR #1835 nach Merge; K3 durch #1833 gemergt (`72ae3f75`); K4/K5 separat in #1839, Merge offen; #1551/#1556/#1560/#1561/#1568/#1569 bleiben offen | je Punkt eigenes Paket ≤ 300 Zeilen mit eigener Abnahme | – | | OPS-CLOUD-PREFLIGHT | Vorabprüfung für den Codex-Cloud-Weg vor jedem Auftrag (laut Root 15.10.; Quelle: nur diese Mitteilung belegt, Datei geprüft 16.10. und nicht gefunden: weder Auftrag noch Bericht noch Ereignislog des Server-Auftragsordners nennt die ID; Wortlaut und Zielort liefert Root, sonst Zeile streichen) | Root disponiert | – | – | – | Geplant: nicht disponiert (15.10.) | Abnahme vor Dispatch festlegen | – | | OPS-JOB-ENDZEILE | Endzeile jedes Auftrags nennt private Abrechnungs- und Token-Messwerte; keine Werte im öffentlichen Repo (laut Root 15.10.; Quelle: nur diese Mitteilung belegt, Datei geprüft 16.10. und nicht gefunden; Wortlaut und Zielort liefert Root, sonst Zeile streichen) | Root disponiert | – | – | – | Geplant: nicht disponiert (15.10.) | Abnahme vor Dispatch festlegen | – | | OPS-AUTO-LOCK | Auto-Skript: doppelte Sperre (laut Root 15.10. „duplicate lock“; Quelle: nur diese Mitteilung belegt, Datei geprüft 16.10. und nicht gefunden; Bedeutung bleibt Unbekannt, Root liefert Wortlaut und Zielort, sonst Zeile streichen) | Root disponiert | – | – | – | Geplant: nicht disponiert (15.10.) | Abnahme vor Dispatch festlegen | – | diff --git a/docs/diagrams/strip-comments.mjs b/docs/diagrams/strip-comments.mjs index 890c3a4c..74396046 100644 --- a/docs/diagrams/strip-comments.mjs +++ b/docs/diagrams/strip-comments.mjs @@ -2,9 +2,9 @@ export function stripComments(s) { const parts = []; let start = 0; - // Match comments too, so CDATA-looking text inside a comment is not protected. - for (const match of s.matchAll(/|)?/g)) { - if (!match[0].startsWith('||)?/g)) { + if (match[0].startsWith('