Skip to content

Consumability: add a docgen demo-function mode that renders one short, single-purpose MP4 per function (Playwright-shaped) #47

@cursor

Description

@cursor

Context. I'm wiring docgen into the courseforge/infrastructure suite as a Tekton Task (smoke landed in deploy/kubernetes/tekton-dag/base/docgen-task.yaml — uses docgen init today as a no-dep wiring smoke). The medium-term plan is to drive docgen from course-builder's annotated Playwright tests so each documented function gets a short, single-purpose video that demonstrates exactly one behavior — the same way a Playwright test('…') describes one scenario.

The full design lives in docs/per-function-video-docs.md (the file you're reading from inside this repo, or the rendered version on courseforge.github.io once published).

PoC results that informed this ask (2026-05-03). I drove today's docgen playwright against a course-builder-shaped stub on a Cloud Agent VM. End-to-end run worked (~100 KB recording produced in ~5 s), but it surfaced five concrete sharp edges that docgen demo-function should smooth out — full write-up in docs/per-function-video-docs.md § PoC. The asks below are the asks those findings translate into.

Ask. Add a new CLI subcommand:

docgen demo-function \
  --manifest <path-to-test-or-yaml> \
  --output <out-dir>

that:

  1. Reads one manifest entry matching the contract documented in per-function-video-docs.md § Contract. Two acceptable input shapes: (a) a Playwright spec file with a { type: "docgen", description: <JSON-encoded contract> } annotation, (b) a sibling *.docgen.yaml. Either is fine; pick whichever is easiest to support first and document the other as TODO.
  2. Runs the referenced demonstration:
    • kind: playwright → reuse the existing docgen playwright plumbing, but driven by --grep "<test_name>" against the spec file, against a dev server URL passed in (or auto-detected from playwright.config.ts).
    • kind: cli → reuse the existing docgen vhs plumbing against the referenced .tape.
  3. Renders narration from the contract's intent field via the existing TTS path (no new TTS code).
  4. Composes one short MP4 (target 15–60 s, single segment, no docgen concat) plus:
    • a poster frame (PNG, last frame of the demo by default),
    • a stable URL fragment of the form #fn-{repo-slug}-{symbol} so consumer docs can deep-link.
  5. Surfaces the contract's assertions_to_surface lines as on-screen highlights / closing caption (whatever your existing overlay system supports — visual treatment is your call).

Concrete asks the PoC turned up (each maps to a finding in the PoC section linked above):

  • (F1) Either accept .webm recordings as a first-class output format, or transcode to .mp4 via the existing ffmpeg runtime dep before validating the output path. Today, playwright_runner.PlaywrightRunner.capture() just checks output_path.exists() against an .mp4 filename, so users have to shutil.copy .webm bytes to the .mp4 path to make the validator happy.
  • (F2) Take a Playwright test + --grep "<test_name>" filter as input, not a Python capture script that has to read DOCGEN_PLAYWRIGHT_OUTPUT / _URL from env. Run the test under your own recording context internally. This is what makes the contract author's life easy: they write a normal Playwright test, you record it.
  • (F3) Default the recording viewport from the manifest entry's output_budget.resolution, not from docgen.yaml's playwright.default_viewport. Today the env-var contract leaks the resolution decision to the script.
  • (F5) Accept either the Node @playwright/test annotation shape or a Python pytest.mark.docgen(...) marker (course-builder uses pytest + playwright.sync_api, so the Node-only shape excludes it). A sibling *.docgen.yaml lookup keyed by {file, test_name} is also fine for non-Playwright projects.

Asks discovered while building the Round-2 shim (newly recorded in docs/per-function-video-docs.md § Round 2 → new findings):

  • (F6) Use Playwright's native locator API (page.locator(sel).filter(has_text=text).first.wait_for(...)) when waiting on text — page.wait_for_function JS predicates break when the selector contains ", and the obvious json.dumps-the-selector workaround interacts badly with Python triple-quoted strings.
  • (F7) Implement marker discovery via ast.parse + decorator walking, not a regex over the source. A regex matches text inside module docstrings that talk about the marker (e.g. doc comments saying "the @pytest.mark.docgen(...) decorator below").

A working reference implementation lives at tools/docgen-shim/demo_function.py — feel free to crib from it. Total ~400 lines, MIT-licensed (matches documentation-generator's own license per pyproject.toml).

Caching. Re-renders should be skipped when the cache key documented in per-function-video-docs.md § Caching (sha256(fn_source_sha + intent_sha + fixture_sha)) matches a previous run. Existing docgen cache infra is fine; just key it on those three SHAs instead of the project-level segment IDs.

Out of scope (please do not implement here). Hosting / CDN choices for the MP4s, S3 layout, GitHub Pages publishing of per-function videos. Those land in the suite's Tekton orchestration Task (courseforge/infrastructure) once the upstream subcommand exists. This issue is about the CLI surface.

Why this is upstream and not a fork. The whole reason documentation-generator is a separate project is that the rendering pipeline (TTS → Manim → VHS → ffmpeg → validate → concat → pages) is the hard part and we do not want a second implementation. Adding demo-function upstream means every consumer (course-builder is the first; others will follow) gets the same shape. We orchestrate from courseforge/infrastructure; the implementation belongs to you.

Happy to PR a draft once the shape is agreed. Open to bikeshedding the subcommand name (demo-function is a working title; per-function, func, case all work).


Tracked from courseforge/infrastructureper-function-video-docs.md § Upstream issue draft.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions