From 689e9bc6c74c04bbd964829858e0f9f6aac170b3 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 11 Sep 2026 13:29:12 +0200 Subject: [PATCH] fix: the slide prompt carries the rules the renderer actually enforces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Generated a deck with ds-deepseek-v4-flash and rendered it to look at. The model produced exactly the six headings it was asked for; the deck came out with eight slides. The extra ones were pandoc's, not the model's. Two rules, both found by rendering rather than reading: - pandoc splits a slide after a table. Anything following one becomes a new slide with no title — that was the stray "Key differentials to consider:" slide floating with no heading. - A table with no blank line before it is not parsed as a table at all. It renders as literal pipe characters in the preceding paragraph. And one that was visible on the slide itself: a nested ordered list inside a bullet ran off the bottom. None of these are the model failing. A cheap model writes perfectly good slide markdown — bold, italics, nested lists and a table with a subscript all came through correctly. It just needs to be told the shape the renderer wants. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU --- src/routes/learningAI.js | 7 +++++++ test/backend-hardening.test.js | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/routes/learningAI.js b/src/routes/learningAI.js index 4f2baab5..b079eb3e 100644 --- a/src/routes/learningAI.js +++ b/src/routes/learningAI.js @@ -167,6 +167,13 @@ Then each slide separated by ---. Guidelines: - First slide: title slide with presentation name and brief subtitle - Use # for slide titles - Use bullet points (- ) for lists, keep them concise (max 5 bullets per slide) +- A slide that contains a table must contain ONLY that table and its heading. + Anything after a table starts a new, untitled slide when the deck is built. +- Leave a blank line before and after every table, or it is not read as a table + at all and appears as literal pipe characters on the slide. +- Do not nest lists more than one level deep, and do not put an ordered list + inside a bullet: it overfills the slide. +- Prefer more slides with less on each. A slide should hold one idea. - Include a summary/key takeaways slide at the end - Do NOT include HTML tags or inline styles`; } diff --git a/test/backend-hardening.test.js b/test/backend-hardening.test.js index c8f88025..e44adfe2 100644 --- a/test/backend-hardening.test.js +++ b/test/backend-hardening.test.js @@ -330,3 +330,17 @@ test('a deck can only embed images the requester owns', () => { assert.match(src, /workdir = await fsp\.mkdtemp\(/); assert.match(src, /\} finally \{[\s\S]{0,200}rm\(workdir, \{ recursive: true, force: true \}\)/); }); + +test('the slide prompt carries the rules pandoc actually enforces', () => { + // Found by generating a deck with ds-deepseek-v4-flash and rendering it: the + // model produced exactly the 6 headings asked for, but the deck came out with + // 8 slides. pandoc splits a slide after a table, and the remainder becomes an + // untitled orphan. A table with no blank line before it is not parsed as a + // table at all — it renders as literal pipe characters. + const src = read('src/routes/learningAI.js'); + assert.match(src, /A slide that contains a table must contain ONLY that table/); + assert.match(src, /Leave a blank line before and after every table/); + // And the overfull slide in that same test: a nested ordered list inside a + // bullet ran past the bottom of the slide. + assert.match(src, /do not put an ordered list\s*\n\s*inside a bullet/); +});