docs: rewrite the README around one worked example - #21
Merged
Conversation
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
Documentationlist of eight files. The signatures moved todocs/COMPONENTS.md, read out of the installed package withinspect.signaturerather than transcribed. The source tree went;git ls-filesanswers that better.What was inaccurate
None of this survives into the new file:
transcriptdoes not appear anywhere insrc/. It is a feature ofopenadapt-capture, whosecreate_htmlreadstranscript.jsonout of a capture directory.scripts/generate_readme_screenshots.pycallsopenadapt_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 indocs/images/; they are just no longer presented as this package's output.open synthetic_demo_viewer.html, which does not exist, and linksSYNTHETIC_DEMOS_EXPLAINED.md, which also does not exist. It carried an unsourced "33% -> 100% accuracy" claim I could not check.SEARCH_FUNCTIONALITY.mdwas linked from the repository root and lives atdocs/SEARCH_FUNCTIONALITY.md.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.examples/modules for openadapt-ml and openadapt-retrieval.What I verified
I first ran everything against
openadapt-viewer==0.2.0from PyPI in an empty venv, which was a mistake worth recording: the wheel still carries the hardcodedDEFAULT_CAPTURE_PATHand thecapture.dbreader, both of which #15, #17 and #19 have already fixed on main. Writing that up as current behaviour also trippedtests/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, thePageBuilderexample,generate_capture_html,benchmark --dataagainst a directory holdingepisodes.jsonplusrecording.db, the$OPENADAPT_CAPTURE_RECORDINGform, andcatalog stats. Signatures come frominspect.signatureagainst 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, andruff check .is clean.The screenshot is a real
openadapt-viewer demorun.scripts/generate_demo_screenshot.pyregenerates it, and because the demo data is an unseededrandom.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.
generate_capture_htmlwrites<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.benchmark --dataon a directory holding a pre-2026-07-17capture.dbprintsGenerated:and writes a viewer with zero tasks.LegacyCaptureErrorsubclassesFileNotFoundError, so theexcept (FileNotFoundError, ValueError, KeyError)ingenerate_benchmark_htmlswallows it and falls through toload_benchmark_data. The migration command thatrecording_dbtook the trouble to name never reaches the user. Reproduced against a real legacy directory.openadapt_viewer.__version__is"0.1.0"whilepyproject.tomlsays0.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 2frgrid, which stays empty.Could not verify
The
--openflag ondemo,benchmark,captureandsegmentationcallswebbrowser.open; I did not exercise it headless.uv sync --all-extrasin the Development section comes from.github/workflows/test.ymlrather than a local run, so CI on this PR is the check on it.