Conversation
zdnemz
marked this pull request as ready for review
September 20, 2026 10:45
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1142
What
Adds
lib/export/narration.tsexporting a singlecollectSpeechText(scene, options)walk.collectSceneScripts(script .md/.docx export) andbuildSpeakerNotes(PPTX speaker notes) now both delegate to it, so the two cannot drift on what counts as narration.Why
use-export-script.tsre-implemented the speech-text traversal that already existed inuse-export-pptx.ts, and the two had already drifted — see #1142.Correction to the issue's premise
The issue names
use-download-subtitles.tsas a third walk site. It isn't: it callscompileSubtitlesfrom./build-export-zip, which has no speech walk either. There were only ever two genuine narration walks inlib/export(the two above). Thetype === 'speech'checks inclassroom-zip-utils.tsare manifest transformation, not narration collection, and were left alone.The drift is bigger than the issue describes
The issue describes the difference as a trim filter. There are actually two independent knobs, and the second one changes output even for well-formed scenes:
collectSceneScripts(before)text.trim()pushedbuildSpeakerNotes(before)The script exporter didn't just filter whitespace-only speech — it pushed the trimmed text. So for
text: ' Hello 'the script export emittedHellowhile the PPTX notes emittedHello. Collapsing this to a singlekeepWhitespaceOnlyflag (as the issue and the original plan suggested) would have silently changed the script exporter's output and broken the existing assertion intests/export/narration-script-export.test.ts:92('omits whitespace-only speech text and trims kept text').Both knobs are therefore preserved explicitly as
keepWhitespaceOnlyandtrim, defaulting to the PPTX behaviour:collectSceneScriptskeeps its name, signature,SceneScriptshape and its trim semantics;buildSpeakerNoteskeeps its name and output. No callers change.Behavior change
None for output. Two deliberate robustness changes:
collectSpeechTexttolerates aspeechaction with a missingtextfield (the old script walk didaction.text.trim()and threwTypeError: Cannot read properties of undefined— verified againstmain). The helper now readsaction.text ?? ''.readonly Scene[]is accepted.Verification
npx prettier --checkclean,npx eslint --fixclean (no changes),npx tsc --noEmitclean (needsNODE_OPTIONS=--max-old-space-size=8192— default heap OOMs on this repo)npx vitest run tests/export— 16 files, 230 tests passed (was 15/217; +13 in the newtests/export/narration.test.ts)keepWhitespaceOnlyvalues (whitespace-only and empty string), bothtrimvalues, per-part independent trimming, internal newlines preserved, single-newline joinmain) against the new helper over 11 action-shape cases × both call-site option sets: 21/22 byte-identical. The single non-match is themissing text fieldcase where the old code crashes and the new one returns a string — the intended robustness fix above, not a regression.Notes