Six-skill presentation system: ingest talks into a rhetoric vault, run interactive clarification, generate a speaker profile, create presentations that match your documented patterns, produce the deck illustrations + thumbnail visual layer, and publish talk pages to a Jekyll shownotes site. Includes a 102-entry Presentation Patterns taxonomy (91 observable, 11 unobservable go-live items) for scoring, brainstorming, and go-live preparation.
86
92%
Does it follow best practices?
Impact
86%
1.24xAverage score across 26 eval scenarios
Advisory
Suggest reviewing before use
"""Tests for generate-talk-timings.py — chapter-driven timing files from outline.yaml."""
import copy
from pathlib import Path
import pytest
import yaml
FIXTURE = Path(__file__).parent / "fixtures" / "outline-example.yaml"
@pytest.fixture(scope="session")
def outline(outline_schema):
return outline_schema.load_outline(FIXTURE)
@pytest.fixture(scope="session")
def base_data():
return yaml.safe_load(FIXTURE.read_text(encoding="utf-8"))
def test_format_seconds(generate_talk_timings):
assert generate_talk_timings.format_seconds(0) == "0:00"
assert generate_talk_timings.format_seconds(59) == "0:59"
assert generate_talk_timings.format_seconds(60) == "1:00"
assert generate_talk_timings.format_seconds(125) == "2:05"
def test_emits_chapter_line_per_chapter(generate_talk_timings, outline):
lines = generate_talk_timings.generate_timings(outline.chapters)
# 3 chapters + FINISH
assert len(lines) == 4
assert lines[0].endswith("The Setup")
assert lines[1].endswith("The Turn")
assert lines[2].endswith("The Close")
assert lines[3].endswith("FINISH")
def test_cumulative_times(generate_talk_timings, outline):
"""Fixture: ch1=6 min, ch2=12 min, ch3=12 min. Cumulative: 0, 6, 18, 30."""
lines = generate_talk_timings.generate_timings(outline.chapters)
assert lines[0].startswith("0:00 ")
assert lines[1].startswith("6:00 ")
assert lines[2].startswith("18:00 ")
assert lines[3].startswith("30:00 ") # FINISH at 30 min
def test_qa_adds_chapter_before_finish(generate_talk_timings, outline):
lines = generate_talk_timings.generate_timings(outline.chapters, qa_minutes=5)
assert "Q&A" in lines[-2]
assert lines[-2].startswith("30:00 ")
assert lines[-1].startswith("35:00 FINISH")
def test_zero_qa_omits_qa_line(generate_talk_timings, outline):
lines = generate_talk_timings.generate_timings(outline.chapters, qa_minutes=0)
assert not any("Q&A" in line for line in lines)
def test_subminute_chapter(generate_talk_timings, outline_schema, base_data):
"""target_min: 0.5 → 30 seconds; cumulative arithmetic still correct."""
data = copy.deepcopy(base_data)
data["chapters"][0]["target_min"] = 0.5
o = outline_schema.Outline.model_validate(data)
lines = generate_talk_timings.generate_timings(o.chapters)
# ch1 starts at 0:00, ch2 starts at 0:30
assert lines[0].startswith("0:00 ")
assert lines[1].startswith("0:30 ")
def test_finish_equals_chapter_sum(generate_talk_timings, outline):
"""The FINISH timestamp equals the sum of chapter durations."""
total_s = sum(round(c.target_min * 60) for c in outline.chapters)
lines = generate_talk_timings.generate_timings(outline.chapters)
expected = generate_talk_timings.format_seconds(total_s)
assert lines[-1].startswith(f"{expected} FINISH").github
eval-resources
humor-postmortem-blind-spots
qr-bitly-slug-from-outline
qr-missing-shortener-detection
shownotes-publisher-omit-placeholder
shownotes-publisher-publish-no-date
shownotes-publisher-publish-with-date
shownotes-publisher-update-add-video
video-extraction-diagnostics
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
scenario-11
scenario-12
scenario-13
scenario-14
scenario-15
scenario-16
scenario-17
scenario-18
scenario-19
scenario-20
scenario-21
scenario-22
scenario-23
scenario-24
scenario-25
scenario-26
rules
scripts
skills
illustrations
presentation-creator
references
patterns
build
deliver
prepare
scripts
shownotes-publisher
vault-clarification
vault-ingress
vault-profile
tests