Comprehensive 9-phase QA reviewer for AI/ML technical training decks (.pptx). Performs deck inventory, content accuracy checks (with web research), visual/diagram verification, animation testing via Chrome, technology gap analysis, content flow review, report generation, AND applies fixes directly to the deck. Produces three deliverables: qa-report.md, a _reviewed.pptx (typos fixed, years updated, broken animation references cleaned, gap-fill slides added, change summary slide, speaker notes, backup slides), and anticipated-qa.md with likely attendee Q&A. Trigger on: "review this deck", "QA the slides", "check the training materials", "audit the presentation", "verify the deck is up to date", or any request to review, QA, audit, or check a training deck, presentation, or course slides for accuracy, completeness, or quality. Also triggers on "review" or "check" in context of a training deck. Do NOT use for creating slides from scratch or general slide editing — use pptx or training-course-builder instead.
You are performing a comprehensive QA review of an AI/ML technical training deck. This is a systematic 9-phase process that catches content errors, visual issues, missing topics, and flow problems — then produces BOTH a structured report AND a modified copy of the deck with fixes applied.
CRITICAL — This review produces THREE deliverables:
qa-report.md — the written QA report (Phase 7)<deck>_reviewed_<TIMESTAMP>.pptx — the modified deck with all changes applied (Phase 8). Always use a timestamped filename to avoid cloud sync caching issues.anticipated-qa.md — likely audience questions and suggested answers (Phase 9)You are NOT done until Phase 9 is complete and all three files have been saved. The report alone is not sufficient. The whole point of this skill is that the deck gets updated — not just analyzed.
Read the pptx skill at the sibling pptx/SKILL.md path (same parent directory as this skill).
You'll need its tools for reading slides, extracting text, converting to images, unpacking XML,
and editing content.
Get the deck. The user will provide a .pptx file. Copy it to your working directory so you have a local copy to work with.
Ask about time allocation. Before starting the review, ask the user:
Pre-flight inspection:
python -m markitdown <deck>.pptx for a content overviewpython scripts/thumbnail.py <deck>.pptx for a visual overviewScope boundary — post-closing slides:
Any slides that appear AFTER the closing/thanks slide are out of scope for review. These
are typically extras, reserves, or leftovers from previous reviews. During Phase 1 inventory,
note them briefly (slide number, title) but tag them as post-closing and skip them in all
subsequent phases — no accuracy checks, no visual review, no animation analysis, no gap
placement, no flow analysis. They should not appear in issue tables, gap recommendations, or
action items. If a post-closing slide is relevant to a gap identified in Phase 5, mention it
as "an existing slide after the closing slide may partially address this" but do not evaluate
it further.
Proceed through all 9 phases in order. Each phase builds on the previous ones. Phases 1-6 are analysis. Phase 7 writes the report. Phase 8 applies changes to the deck. Phase 9 generates the anticipated Q&A document. You are not finished until Phase 9 is complete and all three deliverable files have been saved.
Catalog every slide so you have a complete map of the deck before diving into details. Process in batches of 10-15 slides.
For each slide, record:
content (bullets/text), diagram (visual/flowchart/infographic),
lab (hands-on exercise), section (section divider/header), title (title slide),
code (code samples), table (tabular data)Additionally, during inventory, scan for year references across the deck:
This year scan feeds directly into the Year/Date Update step (see below).
Group slides into logical sections based on section dividers and topic flow. The output of this phase is a complete inventory table and a section map showing how the deck is organized.
Post-closing slides: When you reach the closing/thanks slide identified in pre-flight, mark
all subsequent slides as post-closing in the inventory. List them with slide number and title
but do NOT analyze them further in any subsequent phase. Add a note in the inventory:
"Slides [N+1]-[end] are post-closing and excluded from review scope."
This inventory becomes your reference for every subsequent phase — you'll use it to know which slides need visual inspection, which have animations, where the lab slides are, etc.
Extract every verifiable technical claim from the deck and research it. This is where you catch outdated version numbers, renamed products, deprecated APIs, and factual errors.
Use web search against current documentation and authoritative sources. For each claim, search for the latest information and compare. Don't assume something is correct just because it sounds reasonable — actually check it.
Flag each problem using one of these categories:
Record the slide number, the specific claim, what's wrong, and what the correct information is.
This phase checks that every visual element accurately represents its accompanying content and looks good. There are two sub-workflows depending on whether slides have animations.
python scripts/office/soffice.py --headless --convert-to pdf <deck>.pptx
pdftoppm -jpeg -r 150 <deck>.pdf slide
For slides with animations, static images only show the initial state. To properly verify these, you need to click through the animation sequence in a live presentation.
Workflow:
Known PowerPoint Online limitations:
Prioritization for click-through testing:
If Chrome/OneDrive access isn't available, fall back to the XML-based animation analysis in Phase 4 and flag these slides for manual click-through testing.
This phase examines the raw XML structure of animations for technical issues that visual inspection might miss.
Unpack the deck and look for animation elements in each slide's XML:
python scripts/office/unpack.py <deck>.pptx unpacked/
Search for <p:timing>, <p:anim>, <p:seq> elements in each slide*.xml file.
presetID / presetClass attributes)clickEffect, afterEffect, withEffect<p:spTgt spid="X"/>) references a
shape that actually exists on that slide. Orphaned targets pointing to deleted shapes are
a common problem when slides get edited — they cause silent failures during presentation.Animation XML analysis tells you what animations exist and whether they're structurally sound, but it can't tell you how they feel during delivery. Always recommend manual click-through for animated slides, even if the XML looks clean.
Broken references identified here will be auto-cleaned in Phase 8 — orphaned animation targets are removed from the timing XML so they no longer cause silent "dead clicks" during presentation. Record the full list of broken references (slide number, orphaned shape IDs, count) so Phase 8 can action them and the report can document what was removed.
Compare what the deck covers against the current AI/ML landscape. This is where you identify topics the deck is missing or where coverage is too thin.
For each gap, suggest a specific placement — which section it belongs in, roughly which existing slides it should follow. Also note any covered topics that have become obsolete or significantly less relevant since the deck was last updated.
Evaluate how well the deck works as a learning experience, independent of whether individual facts are correct.
For each issue, suggest a specific fix — move slide X after slide Y, add a bridge slide between sections A and B, split this dense slide into two, etc.
As a separate sub-analysis, identify slides that could be removed or consolidated if the deck needs to be shortened (e.g., for a tighter time slot or to make room for new content). For each candidate, explain WHY it's a removal candidate and what, if anything, would be lost.
What to look for:
What to IGNORE (never flag as reduction candidates):
How to identify lab intros and section headers: These slides typically have visually distinct backgrounds (colored/gradient fills, images, or patterns) rather than the standard content slide background (white with subtle decorative curved lines). They usually contain minimal text — just a title or section name. When in doubt, compare the slide's background to the majority content slides; if it's visually different, skip it.
For each candidate, provide:
Using the Phase 1 inventory and the time allocation provided by the user, estimate how long the deck will take to deliver and whether it fits within the allotted time.
How to estimate:
Total = slide presentation time + (number of labs × 11 min) + buffer
Produce a breakdown by section:
For each major section of the deck, estimate its time contribution:
Compare to allocated time:
If over time, suggest specific ways to trim. Reference the Slide Reduction Candidates analysis above, and additionally suggest:
IMPORTANT: Do NOT make any changes to the deck based on timing analysis. This is advisory only — present the estimate and trimming suggestions in the report and let the author decide what to cut.
Compile everything from Phases 1-6 into a structured qa-report.md file.
# QA Report: [Deck Title]
**Reviewed**: [date]
**Deck version**: [version/date from title slide if present]
**Total slides**: [count] ([in-scope count] in scope, [post-closing count] post-closing)
**Allocated time**: [time from user, or "Not specified"]
**Overall quality score**: [X/10]
## Executive Summary
[2-3 paragraph high-level assessment. What's strong, what needs work, overall readiness
for delivery.]
## Issues by Category and Priority
### Critical Issues
[Table: Slide # | Phase | Category | Description | Recommended Fix]
### Important Issues
[Table: same format]
### Minor Issues
[Table: same format]
### Informational Notes
[Table: same format]
## Visual Accuracy Ratings
[Table: Slide # | Title | Rating | Notes]
## Animation Inventory
[Table: Slide # | Title | Animation Types | Click Steps | Broken Refs? | Notes]
[List of slides recommended for manual click-through testing]
## Technology Gap Analysis
[Table: Gap | Priority | Suggested Placement | Rationale]
[List of obsolete/declining topics still covered]
## Content Flow Issues
[Table: Issue | Location | Suggested Fix]
## Slide Reduction Candidates
[If the deck needs to be shortened, these slides are candidates for removal or consolidation.
Lab intro slides and section headers are excluded from this analysis.]
[Table: Slide # | Title | Reason | Impact if Removed | Alternative]
## Timing Estimate
**Allocated time**: [time provided by user, or "No constraint specified"]
**Estimated delivery time**: [total estimate]
**Verdict**: [Fits comfortably / Tight / Over time]
### Breakdown by Section
[Table: Section | Content Slides | Labs | Est. Time]
### Trimming Suggestions (if over time)
[Specific suggestions referencing slide reduction candidates, optional labs, etc.
Note: These are recommendations only — no changes are made to the deck based on timing.]
## Year/Date Updates Applied
[Table: Location | Old Value | New Value | Update Method (master/slide/python-pptx)]
## Changes Applied (Phase 8)
[Comprehensive list of ALL modifications made to the deck during Phase 8. This section must be
added after Phase 8 is complete and should include:]
### New Slides Created
[Table: Slide # | Title | Positioned After | Gap Addressed | Visual Elements Used]
### Visual Enhancements
[Table: Slide # | Title | Visual Type Added | Description | Backup Slide #]
### Year/Date Updates
[Table: Slide # | Location | Old Value | New Value]
### Animation Reference Cleanup
[Table: Slide # | Broken Refs Removed | Orphaned Shape IDs | Remaining Valid Steps]
### Backup Slides
[Table: Backup Slide # | Original Slide # | Original Title | Reason (modified/enhanced)]
### Speaker Notes Added
[Table: Slide # | Note Summary]
### Other Modifications
[Any typo fixes, formatting corrections, etc.]
## Slide-by-Slide Quick Reference
[Condensed per-slide summary from Phase 1 with any issues flagged inline]
## Prioritized Action Items
### Immediate (fix before next delivery)
- [Critical errors, broken content, misleading information]
### Short-term (next revision)
- [Important improvements, missing content, inconsistencies]
### Long-term (future updates)
- [Nice-to-haves, emerging topics, structural improvements]
Use these severity indicators in the tables:
Save the report to qa-report.md in the working directory, then copy it to the outputs folder
so the user can access it.
This phase is MANDATORY. After generating the report, you must now apply all identified changes to a copy of the actual .pptx file. The report tells the author what was found; this phase actually fixes the deck.
⚠️ MANDATORY ENFORCEMENT — READ BEFORE PROCEEDING ⚠️
Phase 8 contains steps that are frequently skipped or done incorrectly. The following are NON-NEGOTIABLE and must be completed correctly before saving the final deck:
Duplicated slide cleanup: When using
add_slide.py, you MUST remove ALL inherited content (icons, text, shapes, animations) from the source slide before adding new content. Failure to do this produces slides with random leftover elements from other slides.Visual enhancement — restructure first: When adding visual elements to text-heavy slides, you MUST resize/reposition existing text boxes to make room FIRST. Never drop shapes on top of existing content — they WILL overlap and obscure text.
Title slide verification: After updating version/date, render slide 1 to an image and visually confirm the changes took effect. Text replacement can silently fail.
Step 6 — Visual Enhancement of Text-Heavy Slides: You MUST run a PROGRAMMATIC SCAN of ALL slides (not just Phase 1 tags) to find every slide lacking images/charts/tables. Look especially for GROUPS of related slides (tool categories, model types, etc.). Enhance 20-40% of candidates with diagrams, charts, icons, code blocks, or images. Do NOT skip this. If you reach step 7 without having done visual enhancements, STOP and go back to step 6.
Step 7 — Visual QA with subagent: ALL modified slides must be rendered to images and inspected by a SUBAGENT with fresh eyes. You cannot self-verify — you will see what you expect, not what's actually rendered.
Step 8 — Renumber Slide References: After inserting new slides, ALL slide numbers in
qa-report.mdANDanticipated-qa.mdMUST be updated to reflect final positions in the reviewed deck. Do NOT save the report with original slide numbers.These are not optional polish steps. They are core deliverable requirements.
📋 LESSONS LEARNED FROM PAST REVIEWS:
Visual enhancements get missed on "non-obvious" slides. Slides that have AutoShapes with text (not plain TextBoxes) can look like they have visual elements in the Phase 1 inventory but are actually just text in styled boxes. ALWAYS run a programmatic scan checking
shape.shape_typefor PICTURE/CHART/TABLE presence, not just the Phase 1 tags.Groups of related slides are the easiest wins. A series of 5 slides each covering a different tool/category/concept (e.g., "Chatbot Interfaces", "Python & Programming", "IDE Integration", "APIs", "No-Code Platforms") benefits enormously from consistent icon or visual treatment across the group. Look for these patterns explicitly.
Cloud sync services cache aggressively. When saving the reviewed deck to a OneDrive, Google Drive, or Dropbox-synced folder, the old version may persist even after overwriting. ALWAYS use a unique timestamped filename. Never reuse or overwrite a previous output name.
Visual enhancements stripped during fixes are NOT automatically re-added. If you fix overlapping shapes by rebuilding from an earlier intermediate file, you LOSE all enhancements that were added after that intermediate. Always track your file lineage and verify that the final output contains ALL enhancements from ALL rounds of work.
Removing shapes by shrinking to 1×1 EMU does NOT work. Text inside a 1×1 shape renders as a vertical single-character column. To truly remove a shape, use
slide.shapes._spTree.remove(shape._element). To remove a paragraph, usetxBody.remove(para._p)viapptx.oxml.ns.qn('a:p').
Make a working copy of the original deck:
# Use a timestamped filename to avoid cloud sync caching issues (OneDrive, etc.)
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
cp <deck>.pptx <deck>_reviewed_${TIMESTAMP}.pptx
All modifications go into this timestamped copy. Never overwrite the original. The timestamp in the filename prevents cloud storage services (OneDrive, Google Drive, Dropbox) from serving a cached version of a previous file with the same name. Use this timestamped filename consistently throughout all subsequent steps.
Apply auto-fixes to the deck (see Auto-Fix Policy below for the full list):
Create new slides for technology gaps identified in Phase 5:
Update year/date references across the deck:
Create a Change Summary slide and insert it as slide 2 (immediately after the title slide) so the reviewer/instructor sees it first:
add_slide.py duplicate-and-edit workflow (see New Slide Guidelines)🔴 MANDATORY — Enhance text-heavy slides with visuals (see Visual Enhancement of Text-Heavy Slides section below for full details):
DO NOT SKIP THIS STEP. This is a core deliverable, not optional polish.
content (bullets/text) that
have no images, diagrams, charts, or other visual elements — just text and bullets.
Count the total number of text-heavy candidate slides.add_slide.py duplicate-and-edit workflow.Self-check: Before proceeding to step 7, confirm you have enhanced at least 20% of text-heavy slides. If you haven't, go back and do it now.
🔴 MANDATORY — Verify ALL modified slides visually:
DO NOT SKIP THIS STEP. Every previous issue with this skill (overlapping shapes, inherited icons, wrong text, broken layouts) would have been caught by visual inspection. This is your last line of defense.
pdftoppm to get individual slide images.Visually inspect these slides. Assume there are issues — find them.
For each slide, look for:
- Leftover content from a source slide (icons, images, text that doesn't belong)
- Overlapping elements (shapes placed on top of text, text through shapes)
- Text overflow or cut off at edges
- Version/date still showing old values on the title slide
- Empty or placeholder text
- Elements that look out of place or inconsistent with the deck's theme
Report ALL issues found, even minor ones.
🔴 MANDATORY — Renumber slide references in the QA report and anticipated Q&A:
DO NOT SKIP THIS STEP. The report is unusable if slide numbers don't match the reviewed deck. This must be done BEFORE saving the final deliverables.
After adding the Change Summary slide (slide 2), gap-fill slides, visually enhanced
slides, and backup slides, the original slide numbers in the QA report no longer match
actual positions in the reviewed deck. Every slide reference in BOTH qa-report.md AND
anticipated-qa.md must be updated to reflect the final slide positions in
<deck>_reviewed.pptx.
How to build the mapping:
original_slide_number → new_slide_number. For example, if the Change Summary was
inserted at position 2, every original slide shifts down by 1. If a gap-fill slide
was inserted at position 15 (in the new numbering), every original slide after that
shifts down by another 1, and so on.How to apply the mapping:
qa-report.md for all slide number references. These appear in patterns like:
Slide #N, Slide N, slide N, Slides N-M, (slide N), after slide N, or in
table cells containing just a number in a "Slide #" column.anticipated-qa.md) section headers that
reference slide ranges (e.g., "Section: Neural Networks (Slides 8-15)" → updated)._reviewed.pptx), not the original."Tip: Write a small Python script that takes the mapping dictionary and does regex-based replacement across the report file. Replace in descending order of slide number (largest first) to avoid double-replacement issues (e.g., replacing "1" inside "15").
🛑 STOP AND VERIFY before saving. Before proceeding to step 9, confirm ALL of the following. If any answer is NO, go back and fix it:
qa-report.md in step 8?anticipated-qa.md section headers?# Use the timestamped filename from step 1 — NEVER reuse a previous filename
cp <deck>_reviewed_${TIMESTAMP}.pptx /path/to/outputs/<deck>_reviewed_${TIMESTAMP}.pptx
🔴 IMPORTANT — Always use a NEW filename. Do not overwrite or reuse the filename
of a previously saved reviewed deck. Cloud sync services (OneDrive, Google Drive, Dropbox)
may cache the old file and serve it instead of the new one, making it appear as though
your changes were lost. The timestamped filename from step 1 ensures every save is unique.| Action | Phase 8 does it? | Notes |
|---|---|---|
| Fix typos/spelling | ✅ Yes | Auto-fix with backup + speaker note |
| Fix formatting | ✅ Yes | Auto-fix with backup + speaker note |
| Clean broken animation refs | ✅ Yes | Auto-fix: remove orphaned targets + speaker note |
| Update stale years | ✅ Yes | Auto-fix via slide master or direct edit |
| Create gap-fill slides | ✅ Yes | New slides with speaker notes |
| Enhance text-heavy slides | ✅ Yes | Add diagrams/charts/code/images with backup |
| Create change summary slide | ✅ Yes | Inserted as slide 2, lists all changes |
| Renumber report slide refs | ✅ Yes | Update all slide #s to final positions |
| Technical content rewrites | ❌ No | Flagged in report for author |
| Reorder/remove slides | ❌ No | Flagged in report for author |
| Existing diagram changes | ❌ No | Flagged in report for author |
| Content restructuring | ❌ No | Flagged in report for author |
At the end of Phase 8, you MUST have saved all three:
qa-report.md — from Phase 7<deck>_reviewed_<TIMESTAMP>.pptx — the modified deck with all changes applied (timestamped filename)anticipated-qa.md — from the Anticipated Q&A step belowIf you have not saved a modified .pptx file, the review is incomplete. Go back and do it.
This phase is MANDATORY. After completing the deck modifications, generate a document of likely audience questions and suggested answers. This serves as an instructor preparation aid — attendees will inevitably ask questions that go beyond what's on the slides, and having prepared answers helps the instructor deliver confidently.
Save as anticipated-qa.md in the outputs folder:
# Anticipated Q&A: [Deck Title]
**Generated**: [date]
**Deck version**: [version]
## Section: [Section Name] (Slides X-Y)
**Q: [Question]?**
A: [Answer]
**Q: [Question]?**
A: [Answer]
## Section: [Next Section] (Slides X-Y)
...
## General / Cross-Cutting Questions
**Q: [Question]?**
A: [Answer]
If any year references in the deck are not the current year, update them automatically. This is a common issue when decks are reused across semesters or years.
Approach 1: Slide master footer (preferred for footers)
The footer copyright text is typically inherited from the slide master or slide layout. Updating it there fixes every slide at once.
# Unpack the deck to access XML
python scripts/office/unpack.py <deck>.pptx
# Look for footer text in slide masters
grep -r "© " <deck>_unpacked/ppt/slideMasters/
grep -r "© " <deck>_unpacked/ppt/slideLayouts/
# Also check slide-level overrides
grep -r "© " <deck>_unpacked/ppt/slides/
In the XML files, footer text lives inside <a:t> elements within <p:sp> shapes that have
placeholder type ftr (footer) or dt (date). Find the <a:t> element containing the old
year and replace it with the current year.
After editing the XML:
# Repack the deck
python scripts/office/pack.py <deck>_unpacked <deck>_updated.pptx
Approach 2: Direct slide-level text replacement
If the footer/year is embedded in regular text boxes rather than master placeholders, you'll need
to update the individual slide XML files directly. Use the same unpack/grep/edit/pack workflow,
but target the specific <ppt/slides/slideN.xml> files.
Approach 3: python-pptx library
For programmatic updates across many slides:
from pptx import Presentation
from pptx.util import Inches, Pt
import datetime
prs = Presentation('<deck>.pptx')
current_year = str(datetime.datetime.now().year)
old_year = '2025' # detected from Phase 1 scan
for slide in prs.slides:
for shape in slide.shapes:
if shape.has_text_frame:
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
if old_year in run.text:
run.text = run.text.replace(old_year, current_year)
# Also check slide masters
for master in prs.slide_masters:
for shape in master.shapes:
if shape.has_text_frame:
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
if old_year in run.text:
run.text = run.text.replace(old_year, current_year)
# And slide layouts
for layout in master.slide_layouts:
for shape in layout.shapes:
if shape.has_text_frame:
for paragraph in shape.text_frame.paragraphs:
for run in paragraph.runs:
if old_year in run.text:
run.text = run.text.replace(old_year, current_year)
prs.save('<deck>_updated.pptx')
© 2025 → © 2026v2.2 11/30/25 → update version date to currentWorkshop - December 2025 → update to current delivery datePhase 4 identifies animation targets that reference shapes no longer on the slide. These "broken references" cause invisible dead clicks during presentation — the presenter clicks, nothing happens, and the audience wonders if something went wrong. Cleaning them up is safe and non-destructive: valid animations are untouched, only orphaned targets are removed.
For each slide that Phase 4 flagged with broken references:
<p:timing> element.<p:spTree> for all <p:cNvPr id="X">
entries — these are the shapes that actually exist on the slide.<p:spTgt spid="X"/> element. If X is not in the
valid shape set, it's an orphan.<p:spTgt> to its containing
animation element (typically a <p:par> inside a <p:childTnLst>) and remove the entire
<p:par> block. This removes the dead click step cleanly without disturbing sibling
animations.<p:childTnLst>, remove that parent too. Continue
up the tree until you reach a node that still has children. If the entire <p:timing> element
ends up empty (all animations were orphaned), remove it entirely.python-pptx doesn't expose animation internals, so work directly on the slide's XML via lxml. Here's the pattern:
from pptx import Presentation
from lxml import etree
prs = Presentation('deck.pptx')
nsmap = {
'p': 'http://schemas.openxmlformats.org/presentationml/2006/main',
'a': 'http://schemas.openxmlformats.org/drawingml/2006/main',
}
for slide in prs.slides:
slide_element = slide._element
# 1. Collect valid shape IDs on this slide
valid_ids = set()
for cNvPr in slide_element.findall('.//p:cSld/p:spTree//p:cNvPr', nsmap):
sid = cNvPr.get('id')
if sid:
valid_ids.add(sid)
# 2. Find the timing element
timing = slide_element.find('.//p:timing', nsmap)
if timing is None:
continue
# 3. Find orphaned animation targets
orphaned_pars = []
for spTgt in timing.findall('.//p:spTgt', nsmap):
spid = spTgt.get('spid')
if spid and spid not in valid_ids:
# Walk up to the containing <p:par> block
node = spTgt
while node is not None:
if node.tag.endswith('}par'):
orphaned_pars.append(node)
break
node = node.getparent()
# 4. Remove orphaned nodes
for par in orphaned_pars:
parent = par.getparent()
if parent is not None:
parent.remove(par)
# 5. Clean up empty parent containers
# Walk up removing empty childTnLst/par elements
for empty_check in timing.findall('.//p:childTnLst', nsmap):
if len(empty_check) == 0:
parent = empty_check.getparent()
if parent is not None:
parent.remove(empty_check)
# If timing is now empty, remove it entirely
if len(timing) == 0:
slide_element.remove(timing)
prs.save('deck_cleaned.pptx')
For each slide where orphans are removed, add a speaker note:
[QA Review - YYYY-MM-DD HH:MM] ANIMATION CLEANUP: Removed N broken animation
reference(s) targeting non-existent shape IDs [list IDs]. These caused dead clicks
during presentation. Valid animations preserved.
Create a backup of the original slide before cleaning (same as any other auto-fix).
Record all animation cleanup in the "Changes Applied" section of qa-report.md:
### Animation Reference Cleanup
| Slide # | Broken Refs Removed | Orphaned Shape IDs | Remaining Valid Steps |
|---------|--------------------|--------------------|----------------------|
| 14 | 15 | 5, 8, 11, ... | 32 |
The skill can fix certain things during the review, but leaves substantive changes to the author.
Every slide that gets modified must have a note added to its speaker notes section with:
[QA Review - YYYY-MM-DD HH:MM] Changed: <short description of what was fixed>
This creates an audit trail so the author knows exactly what was touched.
Before modifying any slide, duplicate the original slide and append it at the end of the deck as a backup. Add a speaker note to the backup slide:
[BACKUP - QA Review YYYY-MM-DD] Original version of slide [N]: [slide title]
This way the author can always compare or revert if they disagree with a fix.
For newly created slides (gap-filling), no backup is needed — just add a speaker note explaining what was added and why.
When creating new slides to fill content gaps identified in Phase 5:
[QA Review - YYYY-MM-DD] NEW SLIDE: Added to address [gap description].
Placed after slide [N] to maintain logical flow.
DO NOT use python-pptx to create new slides. The prs.slide_layouts[N] API often selects
the wrong slide master, causing new slides to have completely different backgrounds, colors, and
fonts from existing content slides. Decks with multiple slide masters (common when imported from
Google Slides) are particularly prone to this.
Instead, use the add_slide.py duplicate-and-edit workflow:
Identify the correct template slide — find an existing content slide that uses the layout and visual style you want to replicate. Render thumbnails to compare.
Duplicate it using add_slide.py:
python scripts/add_slide.py <deck_unpacked>/ <source_slide_number> <new_slide_number>
This copies the slide XML, all relationships (including background image refs), and ensures the new slide uses the same slide layout and slide master as the source.
🔴 CRITICAL — Clean up ALL inherited content from the source slide. add_slide.py
duplicates EVERYTHING from the source — all text, images, icons, shapes, animations, and
relationships. You MUST remove all source-specific content before adding new content.
This is the #1 source of broken slides. Perform ALL of the following:
<p:pic> elements (pictures/icons) that are NOT the background image.
The background image is typically the full-slide-size picture referencing rId3 — keep
that one, delete all others.<p:sp> shape that contains
source slide text. Do not just overwrite the first text box and leave others behind.<p:sp> shapes from the source (colored boxes, icon labels,
callout shapes, grey background rectangles, etc.).<p:timing> element if present — this carries over source slide
animations that will not make sense on the new slide.Self-check after editing each duplicated slide:
□ All source slide pictures (except background) removed?
□ All source slide text boxes removed or fully replaced?
□ All source slide decorative shapes removed?
□ Source slide animations (<p:timing>) removed?
□ New content added and verified?
Edit the duplicated XML directly — add your new titles, body text, and shapes while
preserving the background image reference (typically rId3 for the full-slide background
PNG) and the relationship file structure.
Insert into presentation.xml — add a <p:sldId> entry at the correct position in the
<p:sldIdLst> to control where the slide appears in the deck order.
🔴 Render the new slide to an image and visually verify — confirm no leftover content from the source slide is visible. If you see ANY inherited content (icons, text fragments, decorative shapes, animations), go back to step 3 and remove it before proceeding.
Why this matters: Many training decks (especially those converted from Google Slides) have
multiple slide masters. Master 0 might be a generic white theme while Master 1 has the branded
background, colors, and footer elements. Using python-pptx defaults to Master 0, producing
slides that look completely out of place. The duplicate-and-edit approach guarantees visual
consistency because the new slide inherits everything from its source.
Many decks use full-slide background PNGs (covering the entire 12192000 x 6858000 EMU slide area)
referenced as rId3 in the slide XML. These background images contain the branded header, footer,
decorative curves/lines, and color scheme. When editing slide XML:
<p:pic> element that references the background image.rels file to confirm which rId maps to the background imageBut NOT for creating new slides or duplicating slides — always use add_slide.py for that.
When python-pptx saves a modified .pptx file, PowerPoint may show a repair warning on open
("PowerPoint couldn't read some content"). This is common and usually does not affect content.
It happens because python-pptx may introduce minor XML schema differences (e.g., missing
xml:space attributes, slightly different namespace declarations). Always verify after repair
that all content survived by checking slide count and key slide content.
Training slides that are mostly bullets and text are harder to engage with and less memorable than slides with supporting visuals. This step identifies text-heavy slides and adds visual elements to improve their instructional quality and visual appeal.
🔴 CRITICAL — SCAN EVERY SLIDE, NOT JUST OBVIOUS ONES. Do NOT limit your scan to slides tagged
contentin the Phase 1 inventory. The Phase 1 categories are rough guides, not definitive. You MUST visually inspect or programmatically check EVERY non-skipped slide for visual enhancement opportunities. Specifically:
- Slides with only auto-shapes containing text (e.g., title + subtitle + bullets in AutoShape/TextBox elements) count as text-heavy even if Phase 1 didn't tag them
content.- Groups of related slides (e.g., a series of 5 slides each covering a different tool category, or a set of slides each describing a different model architecture) are PRIME candidates — they benefit from consistent visual treatment across the group.
- Look for slides where
shape.shape_typeis only TEXT_BOX, PLACEHOLDER, or AUTO_SHAPE with text — if there are no PICTURE, CHART, TABLE, or FREEFORM shapes, it's a candidate.- When in doubt, include the slide in your candidate list. It's better to have too many candidates and select the best 20-40% than to miss obvious opportunities.
How to build the candidate list:
for i, slide in enumerate(prs.slides):
has_image = any(s.shape_type == 13 for s in slide.shapes) # PICTURE
has_chart = any(s.shape_type == 3 for s in slide.shapes) # CHART
has_table = any(s.shape_type == 19 for s in slide.shapes) # TABLE
if not has_image and not has_chart and not has_table:
print(f"Slide {i+1}: CANDIDATE — no images/charts/tables")
Skip these even if text-heavy:
For each candidate slide, read its content and pick the visual type that best reinforces the material. The goal is to complement the text, not replace it — the slide should still be readable and the visual should add understanding, not just decoration.
Decision guide:
| Content pattern | Best visual type | Example |
|---|---|---|
| Process or sequence (steps, pipeline, workflow) | Flowchart / process diagram | "Steps to fine-tune a model" → horizontal flow with arrows |
| Comparison (X vs Y, pros/cons, trade-offs) | Comparison chart or table | "Supervised vs Unsupervised" → side-by-side cards with key differences |
| Hierarchy or categories (types, layers, taxonomy) | Tree diagram or nested boxes | "Types of neural networks" → branching tree |
| Architecture or system (components, connections) | Architecture diagram | "RAG pipeline" → blocks with arrows showing data flow |
| Numeric data (statistics, benchmarks, metrics) | Bar/column chart or infographic | "Model sizes over time" → bar chart |
| Code-related (API usage, syntax, configuration) | Styled code block | "LangChain chain example" → syntax-highlighted code snippet |
| Concept explanation (definition, how X works) | Icon + callout layout | "What is attention?" → icon with key concept callout cards |
| List of tools/technologies | Icon grid or card layout | "Popular embedding models" → cards with logo/icon per tool |
| General topic, mood, or context setting | Stock photo | "Introduction to Cloud Computing" → professional photo of server room or cloud imagery |
| Real-world application or scenario | Stock photo | "AI in Healthcare" → medical professional using a tablet |
If none of the structured visual types above fits naturally, a well-chosen stock photo can still dramatically improve a text-heavy slide. Even a single professional image placed alongside condensed bullets makes the slide more engaging and memorable.
For diagrams, charts, code blocks, and icon layouts, create them directly in the slide XML as PowerPoint shapes (rectangles, rounded rectangles, arrows, connectors, text boxes, grouped shapes). This keeps everything editable for the instructor. For stock photos, download high-quality images from royalty-free sources and embed them in the slide (see below).
For diagrams, flowcharts, and architecture visuals:
<a:rect>, <a:roundRect>, <a:cxnSp> (connectors),
<a:grpSp> (groups), and <a:ln> (lines/arrows).<a:solidFill>) with the deck's accent colors.<a:prstGeom prst="roundRect"/>), drop shadows
(<a:effectLst> with <a:outerShdw>), and consistent border weights.For charts (bar charts, comparisons):
For styled code blocks:
#1E1E1E or #2D2D2D
like a code editor theme).For icon + callout layouts:
For stock photos:
Stock photos work best for slides where the content is conceptual, introductory, or context-setting — places where a concrete image helps the audience connect with the topic emotionally or visually, rather than places where a precise technical diagram is needed.
Find a suitable image — use web search to find royalty-free stock photos from sources like Unsplash, Pexels, or Pixabay. Search for terms related to the slide's topic (e.g., "machine learning data science", "cloud computing server", "team collaboration software"). Choose images that are:
Download the image using curl or wget:
curl -L -o stock_photo_slideN.jpg "https://images.unsplash.com/photo-XXXX?w=1920"
Embed in the slide — add the image to the unpacked deck structure:
<deck>_unpacked/ppt/media/ directory.rels file pointing to the new media file:
<Relationship Id="rIdN" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
Target="../media/stock_photo_slideN.jpg"/>
<p:pic> element in the slide XML referencing that relationship ID, with
appropriate position and size coordinatesStyle the embedded photo for a polished look:
<a:prstGeom prst="roundRect"/> on the picture shapeAdd attribution in speaker notes — even though the images are royalty-free, it's good practice to note the source:
[QA Review] Stock photo source: Unsplash (unsplash.com/photos/XXXX) - Free to use
When to prefer stock photos over shape-based visuals:
When NOT to use stock photos:
🔴 CRITICAL — RESTRUCTURE BEFORE ADDING. You cannot simply drop new shapes on top of an existing slide and expect them not to overlap. The existing text boxes, bullets, and shapes already occupy the slide area. You MUST resize/reposition existing elements FIRST to make room, THEN add new visual elements into the freed space. Never add shapes on top of existing content. This is the #1 cause of overlapping elements in enhanced slides.
When adding a visual to a text-heavy slide, restructure the slide layout:
Mandatory workflow for each enhanced slide:
The visual should fill its allocated space fully — avoid tiny diagrams floating in a sea of whitespace. Aim for the visual to occupy at least 35-45% of the usable slide area.
Every visual element should look professional and polished, as if created by a presentation designer — not hastily thrown together:
For each visually enhanced slide:
[BACKUP - QA Review YYYY-MM-DD] Original text-only version of slide [N]: [slide title]
[QA Review - YYYY-MM-DD] VISUAL ENHANCEMENT: Added [diagram type/chart/code block/etc.]
to improve visual engagement. Original text-only version preserved as backup slide [M].
Don't try to enhance every single text-heavy slide — that would be excessive and could overwhelm the deck with inconsistent visuals. Aim to enhance the slides where a visual would have the most instructional impact:
This skill relies on tools from the pptx skill (sibling directory). Make sure these are