@@ -109,7 +109,9 @@ PRESENTATION STRUCTURE REQUIREMENTS:
109109✓ DO: Preserve important code examples as slide content
110110✓ DO: Identify which visual components to use (CapabilityMatrix, UShapeAttentionCurve, WorkflowCircle, GroundingComparison, ContextWindowMeter, AbstractShapesVisualization, etc.)
111111✓ DO: Generate exactly 4 learning objectives (no more, no less)
112- ✓ DO: Keep each learning objective to 5 words or fewer
112+ ✓ DO: Keep each learning objective to 5 words or fewer - THIS IS STRICTLY ENFORCED
113+ - Good: "Master active context engineering" (4 words) ✓
114+ - Bad: "Learn how to master active context" (6 words) ✗
113115
114116✗ AVOID: Long paragraphs on slides (slides are visual anchors, not reading material)
115117✗ AVOID: More than 5 bullet points per slide
@@ -626,11 +628,20 @@ STEP 2: Then, condense to the 3-5 MOST critical takeaways
626628- Prioritize by impact and generality (what will matter most in production?)
627629- Combine related points into higher-level insights when possible
628630- Remove redundant or overly specific points
629- - Ensure each takeaway is actionable and memorable
631+ - **STRICT REQUIREMENT: Each takeaway MUST be 5 words or fewer**
632+ - Use active verbs and eliminate filler words
633+ - Examples:
634+ ✓ "Tests ground agent code quality" (5 words)
635+ ✓ "Context management improves agent reliability" (5 words)
636+ ✓ "Prompt versioning prevents regression bugs" (5 words)
637+ ✗ "Tests are critical for agent workflows in production" (8 words)
638+ ✗ "You should manage context to improve reliability" (7 words)
630639
631640IMPORTANT: The final takeaway slide MUST have exactly 3-5 items, even if the source material lists more.
632641Quality over quantity—choose the most impactful insights.
633642
643+ WORD COUNT VALIDATION: This is strictly enforced. The build will fail if any takeaway exceeds 5 words.
644+
634645CRITICAL REQUIREMENTS:
635646
6366471. The output MUST be valid JSON - no preamble, no explanation, just the JSON object
@@ -640,6 +651,8 @@ CRITICAL REQUIREMENTS:
6406515. Code examples must be actual code from the lesson, not pseudocode
6416526. Content arrays MUST have 3-5 items (except title slide) - THIS IS STRICTLY ENFORCED
6426537. PROMPT EXAMPLES: Use "code" or "codeComparison" slide types, NEVER bullet points
654+ 8. Learning objectives MUST be 5 words or fewer - THIS IS STRICTLY ENFORCED
655+ 9. Takeaway items MUST be 5 words or fewer - THIS IS STRICTLY ENFORCED
643656
644657BEFORE YOU GENERATE - CHECKLIST:
645658
@@ -1162,6 +1175,73 @@ function validateCodeExamplesExistInSource(content, presentation) {
11621175 } ;
11631176}
11641177
1178+ /**
1179+ * Validate that takeaway items have 5 words or fewer
1180+ *
1181+ * Takeaways are final memorable insights displayed prominently on conclusion slides.
1182+ * Enforcing brevity ensures they're memorable and impactful for the audience.
1183+ */
1184+ function validateTakeawayWordCount ( presentation ) {
1185+ const MAX_WORDS = 5 ;
1186+ const issues = [ ] ;
1187+
1188+ const takeawaySlides = presentation . slides . filter ( s => s . type === 'takeaway' ) ;
1189+
1190+ for ( const slide of takeawaySlides ) {
1191+ if ( slide . content && Array . isArray ( slide . content ) ) {
1192+ slide . content . forEach ( ( item , index ) => {
1193+ const wordCount = item . trim ( ) . split ( / \s + / ) . length ;
1194+ if ( wordCount > MAX_WORDS ) {
1195+ issues . push ( {
1196+ slide : slide . title ,
1197+ index : index + 1 ,
1198+ wordCount,
1199+ content : item . substring ( 0 , 60 ) + ( item . length > 60 ? '...' : '' ) ,
1200+ excess : wordCount - MAX_WORDS
1201+ } ) ;
1202+ }
1203+ } ) ;
1204+ }
1205+ }
1206+
1207+ return {
1208+ valid : issues . length === 0 ,
1209+ issues,
1210+ totalTakeawaysChecked : takeawaySlides . reduce ( ( sum , s ) => sum + ( s . content ?. length || 0 ) , 0 )
1211+ } ;
1212+ }
1213+
1214+ /**
1215+ * Validate that learning objectives have 5 words or fewer
1216+ *
1217+ * Learning objectives appear on the title slide and set expectations for the lesson.
1218+ * Brief objectives are more memorable and easier for students to internalize.
1219+ */
1220+ function validateLearningObjectivesWordCount ( presentation ) {
1221+ const MAX_WORDS = 5 ;
1222+ const issues = [ ] ;
1223+
1224+ const objectives = presentation . metadata ?. learningObjectives || [ ] ;
1225+
1226+ objectives . forEach ( ( objective , index ) => {
1227+ const wordCount = objective . trim ( ) . split ( / \s + / ) . length ;
1228+ if ( wordCount > MAX_WORDS ) {
1229+ issues . push ( {
1230+ index : index + 1 ,
1231+ wordCount,
1232+ content : objective . substring ( 0 , 60 ) + ( objective . length > 60 ? '...' : '' ) ,
1233+ excess : wordCount - MAX_WORDS
1234+ } ) ;
1235+ }
1236+ } ) ;
1237+
1238+ return {
1239+ valid : issues . length === 0 ,
1240+ issues,
1241+ totalObjectivesChecked : objectives . length
1242+ } ;
1243+ }
1244+
11651245/**
11661246 * Generate presentation for a file
11671247 */
@@ -1288,6 +1368,44 @@ async function generatePresentation(filePath, manifest, config) {
12881368 console . log ( ` ✅ All ${ codeSourceValidation . codeSlidesChecked } code slide(s) verified against source` ) ;
12891369 }
12901370
1371+ // Validate takeaway word count (5 words or fewer)
1372+ // CRITICAL: This validation is intentionally strict and throws an error because
1373+ // takeaways are displayed prominently on conclusion slides and must be memorable.
1374+ // Verbose takeaways defeat the purpose of distilling key insights.
1375+ const takeawayValidation = validateTakeawayWordCount ( presentation ) ;
1376+ if ( ! takeawayValidation . valid ) {
1377+ console . log ( ` ❌ BUILD FAILURE: ${ takeawayValidation . issues . length } takeaway word limit violation(s):` ) ;
1378+ takeawayValidation . issues . forEach ( issue => {
1379+ console . log ( ` - "${ issue . slide } " item ${ issue . index } : ${ issue . wordCount } words (${ issue . excess } over limit)` ) ;
1380+ console . log ( ` "${ issue . content } "` ) ;
1381+ } ) ;
1382+ console . log ( ` ℹ️ All takeaway items MUST be 5 words or fewer for memorability` ) ;
1383+ console . log ( ` ℹ️ Examples: "Tests ground agent code quality" (5) ✓ | "Tests are critical for agent workflows" (6) ✗` ) ;
1384+ console . log ( ` ℹ️ The presentation was not saved. Fix the generation and try again.` ) ;
1385+ throw new Error ( 'Takeaway validation failed - items exceed 5-word limit' ) ;
1386+ } else if ( takeawayValidation . totalTakeawaysChecked > 0 ) {
1387+ console . log ( ` ✅ All ${ takeawayValidation . totalTakeawaysChecked } takeaway item(s) are 5 words or fewer` ) ;
1388+ }
1389+
1390+ // Validate learning objectives word count (5 words or fewer)
1391+ // CRITICAL: This validation is intentionally strict and throws an error because
1392+ // learning objectives appear on the title slide and set learner expectations.
1393+ // Brief objectives are more memorable and easier to internalize.
1394+ const objectivesValidation = validateLearningObjectivesWordCount ( presentation ) ;
1395+ if ( ! objectivesValidation . valid ) {
1396+ console . log ( ` ❌ BUILD FAILURE: ${ objectivesValidation . issues . length } learning objective word limit violation(s):` ) ;
1397+ objectivesValidation . issues . forEach ( issue => {
1398+ console . log ( ` - Objective ${ issue . index } : ${ issue . wordCount } words (${ issue . excess } over limit)` ) ;
1399+ console . log ( ` "${ issue . content } "` ) ;
1400+ } ) ;
1401+ console . log ( ` ℹ️ All learning objectives MUST be 5 words or fewer for clarity` ) ;
1402+ console . log ( ` ℹ️ Examples: "Master active context engineering" (4) ✓ | "Learn how to master active context" (6) ✗` ) ;
1403+ console . log ( ` ℹ️ The presentation was not saved. Fix the generation and try again.` ) ;
1404+ throw new Error ( 'Learning objectives validation failed - items exceed 5-word limit' ) ;
1405+ } else if ( objectivesValidation . totalObjectivesChecked > 0 ) {
1406+ console . log ( ` ✅ All ${ objectivesValidation . totalObjectivesChecked } learning objective(s) are 5 words or fewer` ) ;
1407+ }
1408+
12911409 // Apply deterministic line breaking (AFTER validation passes)
12921410 console . log ( ' 🔧 Applying line breaking...' ) ;
12931411 const { presentation : processedPresentation , stats } = processPresentation ( presentation ) ;
0 commit comments