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