diff --git a/skill/scripts/serve-question.mjs b/skill/scripts/serve-question.mjs index 225025bd6..fde5285fc 100644 --- a/skill/scripts/serve-question.mjs +++ b/skill/scripts/serve-question.mjs @@ -907,8 +907,10 @@ function page() { const textOnlyFacts = m.querySelector('template.text-only-facts'); const choose = body?.querySelector(':scope > button.choose'); if (body && textOnlyFacts && choose) { + const plainDetail = body.querySelector(':scope > .detail:not(.more)'); [...body.children].filter((el) => el.classList.contains('fact') || el.matches('.detail.more')).forEach((el) => el.remove()); choose.before(textOnlyFacts.content.cloneNode(true)); + if (plainDetail) choose.before(plainDetail); } card?.classList.remove('flipped'); front?.classList.add('text-only'); diff --git a/tests/new-work-e2e.test.mjs b/tests/new-work-e2e.test.mjs index 54de1043f..52bdd3406 100644 --- a/tests/new-work-e2e.test.mjs +++ b/tests/new-work-e2e.test.mjs @@ -343,6 +343,12 @@ describe('new-work-e2e: serve-question decision page', () => { body: 'Body copy must remain present exactly once.', comp: path.join(cwd, '.impeccable', 'mocks', 'decision', 'body-missing.webp'), }, + { + id: 'plain-body', label: 'Plain Body', + body: 'Plain body follows the promoted facts.', + viewport: 'A compact neighborhood notice fills the first viewport.', + comp: path.join(cwd, '.impeccable', 'mocks', 'decision', 'plain-body-missing.webp'), + }, { id: 'board-only', label: 'Board Fallback', board, @@ -366,7 +372,7 @@ describe('new-work-e2e: serve-question decision page', () => { await page.waitForSelector('.card[data-id="assigned"] .media.comp-pending'); await page.evaluate(() => window.__advanceDecisionClock(241000)); - await page.waitForFunction(() => ['assigned', 'kept-only', 'body-only'].every((id) => + await page.waitForFunction(() => ['assigned', 'kept-only', 'body-only', 'plain-body'].every((id) => !document.querySelector(`.card[data-id="${id}"] .media`)), null, { timeout: 6000 }); await page.waitForSelector('.card[data-id="board-only"] .media.stand-in'); @@ -375,6 +381,8 @@ describe('new-work-e2e: serve-question decision page', () => { const frontRead = await page.$eval('.card[data-id="assigned"] .face.front', (el) => el.textContent); const keptOnlyRead = await page.$eval('.card[data-id="kept-only"] .face.front', (el) => el.textContent); const bodyOnlyRead = await page.$eval('.card[data-id="body-only"] .face.front', (el) => el.textContent); + const plainBodyOrder = await page.$$eval('.card[data-id="plain-body"] .body > .fact, .card[data-id="plain-body"] .body > .detail', + (els) => els.map((el) => el.className)); const boardFallbackLabel = await page.$eval('.card[data-id="board-only"] .stand-in-label', (el) => el.textContent); await context.close(); @@ -387,6 +395,8 @@ describe('new-work-e2e: serve-question decision page', () => { assert.match(keptOnlyRead, /Keep the hand-painted timetable/, 'kept-only content survives without a back face'); assert.equal(bodyOnlyRead.match(/Body copy must remain present exactly once\./g)?.length, 1, 'body prose already on a no-back front is not duplicated'); + assert.deepEqual(plainBodyOrder, ['fact', 'detail'], + 'thesis-less body prose follows the facts promoted from the missing comp'); assert.equal(boardFallbackLabel, 'inspiration ยท comp pending', 'board-only art remains as the labeled fallback'); } finally { await stopDaemon(cwd, key);