Skip to content

docs: rewrite the README around one worked example - #21

Merged
abrichr merged 3 commits into
mainfrom
docs-readme-human-rewrite
Aug 28, 2026
Merged

docs: rewrite the README around one worked example#21
abrichr merged 3 commits into
mainfrom
docs-readme-human-rewrite

Conversation

@abrichr

@abrichr abrichr commented Aug 28, 2026

Copy link
Copy Markdown
Member

The README opened with six bolded-lead feature bullets and then spent a third of its length on things this package does not do. I replaced it with one worked example that produces an HTML file, and everything in the new file was run against an editable install of this branch.

What was structurally wrong

The old opening was a category description followed by a bullet list ("Component-based", "Composable", "Standalone HTML"). A reader could not picture anything until line 40, and the first runnable thing was a snippet that built an HTML fragment nobody could see. Now the second command in the file writes a viewer and the next line is a picture of it.

The rest of the length came from nobody deciding what mattered. Two tables of 22 components, a source tree, four screenshot captions, and a Documentation list of eight files. The signatures moved to docs/COMPONENTS.md, read out of the installed package with inspect.signature rather than transcribed. The source tree went; git ls-files answers that better.

What was inaccurate

None of this survives into the new file:

  • The Audio Transcript Feature section, about 40 lines describing timestamped transcription synced to playback. The string transcript does not appear anywhere in src/. It is a feature of openadapt-capture, whose create_html reads transcript.json out of a capture directory.
  • The four screenshots and their captions. scripts/generate_readme_screenshots.py calls openadapt_capture.visualize.html.create_html, so those images are openadapt-capture's viewer, not this one, and the captions point at an "audio transcript (right sidebar bottom)" that is not visible in any of them. The PNGs stay in docs/images/; they are just no longer presented as this package's output.
  • The Synthetic Demo Viewer section. It tells you to open synthetic_demo_viewer.html, which does not exist, and links SYNTHETIC_DEMOS_EXPLAINED.md, which also does not exist. It carried an unsourced "33% -> 100% accuracy" claim I could not check.
  • SEARCH_FUNCTIONALITY.md was linked from the repository root and lives at docs/SEARCH_FUNCTIONALITY.md.
  • "Standalone HTML: Generated files work offline, no server required." The page fetches Alpine from cdn.jsdelivr.net. I aborted that request in a headless browser: the summary cards and the filter dropdowns paint, the task list renders empty, and nothing responds to a click.
  • "5 production viewers available". There are generators for benchmark, capture and segmentation. The other two entries were the examples/ modules for openadapt-ml and openadapt-retrieval.

What I verified

I first ran everything against openadapt-viewer==0.2.0 from PyPI in an empty venv, which was a mistake worth recording: the wheel still carries the hardcoded DEFAULT_CAPTURE_PATH and the capture.db reader, both of which #15, #17 and #19 have already fixed on main. Writing that up as current behaviour also tripped tests/test_no_hardcoded_paths.py, which bans an absolute home path in any tracked file including docs. The second commit re-runs everything against an editable install of this branch.

Every command and snippet in the README was executed there and the output blocks are that run's stdout: openadapt-viewer demo, the PageBuilder example, generate_capture_html, benchmark --data against a directory holding episodes.json plus recording.db, the $OPENADAPT_CAPTURE_RECORDING form, and catalog stats. Signatures come from inspect.signature against the install rather than from the source tree. Every external URL returns 200 and every relative link resolves to a file that exists. pytest tests/ is 154 passed, 79 skipped locally, and ruff check . is clean.

The screenshot is a real openadapt-viewer demo run. scripts/generate_demo_screenshot.py regenerates it, and because the demo data is an unseeded random.random() a rerun will not match task for task. The README says so.

Four things the "What it doesn't do" section documents

Written down rather than fixed, because this is a docs change.

  1. The page is not offline-safe, as above.
  2. generate_capture_html writes <link href="src/openadapt_viewer/styles/episode_timeline.css"> and a matching <script src=...episode_timeline.js> into the page. Both files ship inside the installed package. Resolved relative to the output HTML they are 404s, so the episode timeline is unstyled and inert unless the output lands at a source checkout root.
  3. benchmark --data on a directory holding a pre-2026-07-17 capture.db prints Generated: and writes a viewer with zero tasks. LegacyCaptureError subclasses FileNotFoundError, so the except (FileNotFoundError, ValueError, KeyError) in generate_benchmark_html swallows it and falls through to load_benchmark_data. The migration command that recording_db took the trouble to name never reaches the user. Reproduced against a real legacy directory.
  4. openadapt_viewer.__version__ is "0.1.0" while pyproject.toml says 0.2.0.

One more, visible in the committed screenshot but not called out in the README: the task detail panel renders below the task list rather than in the second column of the 1fr 2fr grid, which stays empty.

Could not verify

The --open flag on demo, benchmark, capture and segmentation calls webbrowser.open; I did not exercise it headless. uv sync --all-extras in the Development section comes from .github/workflows/test.yml rather than a local run, so CI on this PR is the check on it.

abrichr and others added 3 commits August 28, 2026 11:36
The old README opened with six bolded-lead feature bullets, then documented
capabilities this package does not have. The audio-transcript section described
a feature of openadapt-capture: the string "transcript" appears nowhere in
openadapt-viewer's source or in the 0.2.0 wheel. The four README screenshots
were produced by scripts/generate_readme_screenshots.py, which calls
openadapt_capture.visualize.html.create_html, so they showed another package's
output with captions pointing at a transcript panel that is not in the images.
The synthetic-demo section told the reader to open synthetic_demo_viewer.html
and linked SYNTHETIC_DEMOS_EXPLAINED.md; neither file exists in the repository.
SEARCH_FUNCTIONALITY.md was linked at the root and lives under docs/.

Everything in the new file was run against openadapt-viewer==0.2.0 installed
from PyPI into an empty venv, and the pasted output is that run's output. The
component signatures move to docs/COMPONENTS.md, read out of the installed
package with inspect.signature rather than copied from the source tree.

The screenshot is the real output of `openadapt-viewer demo`, regenerated by
scripts/generate_demo_screenshot.py.

Four behaviours that the old README's "works offline, no server required" claim
covered up are now written down: the page fetches Alpine from jsdelivr and the
task list does not render without it; `benchmark` with no --data resolves an
absolute path on one developer's machine; the capture viewer emits
repo-relative href/src for episode_timeline.css and .js; and __version__ still
reports 0.1.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The first pass verified everything against openadapt-viewer==0.2.0 from PyPI
and documented two bugs that main has already fixed. #15 replaced the
hardcoded DEFAULT_CAPTURE_PATH with $OPENADAPT_CAPTURE_RECORDING, and #17 and
#19 moved the readers from the pre-#28 capture.db to recording.db. Reciting
the wheel's behaviour also tripped tests/test_no_hardcoded_paths.py, which
bans an absolute home path in any tracked file including documentation.

Everything is now re-run against an editable install of this branch: the demo
screenshot, the component signatures in docs/COMPONENTS.md, the benchmark
invocation, and the offline behaviour with cdn.jsdelivr.net aborted in a
headless browser.

The legacy-capture path replaces the stale hardcoded-path bullet, because it is
a live failure: LegacyCaptureError subclasses FileNotFoundError, so the
fallback in generate_benchmark_html catches it, load_benchmark_data returns a
run with zero tasks, and the CLI prints "Generated:". The migration command
that recording_db raises never reaches the person who needs it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The offline section said benchmark --standalone embeds Plotly. The flag is
dead: cli.py passes it to generate_benchmark_html, which passes it into
_generate_viewer_html, whose body never reads it. PageBuilder is built with
include_alpine=True and no include_plotly, so the Plotly branch never runs
and the two renderings are byte identical. Claiming an offline escape hatch
inside the section about not being offline-safe is the worst place for it.

dark_mode is stored in PageBuilder.__init__ and never read again. The sun
button in the header is what switches the palette. Say that instead.

Add the screenshot-path bullet: the benchmark viewer writes a real
recording's screenshots as absolute local paths, so mailing that file loses
the images. Only demo inlines them as data URIs.

The demo's pass and fail values come from an unseeded random.random(), so
90.0% is not impossible, only unlikely. Soften the caption.
@abrichr
abrichr merged commit 6cfad96 into main Aug 28, 2026
4 checks passed
@abrichr
abrichr deleted the docs-readme-human-rewrite branch August 28, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant