fix(story-mode): no celebration when the turn is not a clean finish

From review round 8: "Mission complete!" with confetti and cheering
helpers sat over balloons saying the page will not work as opened, a
helper's tests have not run, or a problem is left. The final panel is now
calm (no confetti, a neutral robot) whenever work was still out at the
turn's end, nothing worked, or Claude's last words name an open problem
(`page.openNote`: a key point about something wrong, not done, not
checked or not fixed); the last of these reads "Done, with a catch".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-10-18 15:23:19 +02:00
1 parent faca7571e2
commit 88040c997d
17 files changed
+80 -7

No files matched your search

@@ -12,6 +12,7 @@
"helpers": 2,
"helpersRunning": 0,
"finishedLater": 2,
"openNote": true,
"panels": [
{
"kind": "mission",
@@ -81,6 +82,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -127,6 +129,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -176,6 +179,7 @@
"helpers": 1,
"helpersRunning": 0,
"finishedLater": 2,
"openNote": true,
"panels": [
{
"kind": "mission",
@@ -242,6 +246,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -291,6 +296,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -337,6 +343,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -396,6 +403,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -432,6 +440,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 1,
"helpersRunning": 0,
"finishedLater": 1,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -108,6 +109,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -164,6 +166,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -101,6 +102,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -147,6 +149,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -155,6 +156,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -227,6 +229,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -306,6 +309,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -104,6 +105,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -160,6 +161,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": true,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 2,
"helpersRunning": 0,
"finishedLater": 2,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -111,6 +112,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": true,
"panels": [
{
"kind": "mission",
@@ -167,6 +169,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -226,6 +229,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -318,6 +322,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": false,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 1,
"helpersRunning": 0,
"finishedLater": 1,
"openNote": true,
"panels": [
{
"kind": "mission",
@@ -121,6 +122,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": true,
"panels": [
{
"kind": "mission",
@@ -12,6 +12,7 @@
"helpers": 0,
"helpersRunning": 0,
"finishedLater": 0,
"openNote": true,
"panels": [
{
"kind": "mission",
+3
View File
@@ -40,6 +40,7 @@ function pagesOf(name: string) {
helpers: p.helpers,
helpersRunning: p.helpersRunning,
finishedLater: p.finishedLater ?? 0,
openNote: p.openNote ?? false,
panels: p.panels.map((x) => ({
kind: x.kind,
ok: x.ok ?? null,
@@ -159,6 +160,8 @@ describe('Story Mode on real sessions', () => {
const last = (name: string, turn: number) => pagesOf(name)[turn].panels.at(-1)!;
// An open problem, said further into the final message than its first sentence.
expect(last('web-page-node-test', 0).balloon).toMatch(/won't work if you double-click index\.html/);
// ...and the turn is not drawn as a clean finish.
expect(pagesOf('web-page-node-test')[0].openNote).toBe(true);
expect(last('text-plan-dry-run-helper', 1).balloon).toMatch(/doesn't fix it/);
// What you expected, and what you asked for mid-turn.
expect(last('errors-push-append', 2).balloon).toMatch(/As you expected, git describe --tags then failed/);
+15
View File
@@ -851,6 +851,21 @@ describe('story-mode.js overlay', () => {
expect($$('.story-ln--add').map((l) => l.textContent)).toEqual(['+more']);
});
it('a turn whose last words name an open problem ends "Done, with a catch", not "Mission complete!"', async () => {
const words = [
'I built the pomodoro timer and its tests, and all of them pass.',
'It keeps the time in memory and redraws the clock every second while it runs. '.repeat(3),
"Opening the page: it won't work if you double-click index.html.",
].join(' ');
boot(storyOf([prompt('build it'), ...edit('e1', '/work/demo-shop/t.js', ['+x']), said(words), end(1000)]));
app.openStoryMode(SID);
await settle();
expect($('.story-panel[data-kind="complete"] .story-splash-title')!.textContent).toBe('Done, with a catch');
expect($('.story-panel[data-kind="complete"] .story-balloon-text')!.textContent).toMatch(
/won't work if you double-click/
);
});
it('the final panel counts the commits of the whole turn, and says when the work was uploaded', async () => {
boot(
storyOf([