fix: remove hardcoded developer paths from shipped code - #14
Merged
Conversation
This is a public repository, and a path under one developer's home directory was baked into library code, tests, a test fixture and an example script. The worst of them was in shipped code. `real_data_loader.py` defaulted to `/Users/abrichr/oa/src/openadapt-capture/turn-off-nightshift`, so `openadapt-viewer benchmark` with no `--data` raised FileNotFoundError for every user who is not that developer. That directory is also gitignored in openadapt-capture, so the default could never resolve for anyone else even with both repositories checked out. Re-pointing it would have been theatre; the default is gone instead. A second path did real damage more quietly. Key frames in episodes.json are stored relative to the checkout root, as `../openadapt-capture/<rec>/...`, and the loader resolved them by prepending a literal `/Users/abrichr/oa/src`. Point it at a recording anywhere else and every screenshot path came back pointing at a machine you do not have. It now re-anchors on the capture directory the caller actually passed, which resolves identically for that developer and correctly for everyone else. Callers name a recording by argument or through $OPENADAPT_CAPTURE_RECORDING. That is deliberately a different variable from the $OPENADAPT_CAPTURE_DIR used by the screenshot scripts, which names the capture checkout holding many recordings, not one recording inside it. test_benchmark_refactored.html is deleted rather than edited. It is generated by `openadapt-viewer benchmark`, no code reads it, and it embedded both the absolute paths and the step text of a private gitignored recording. .gitignore already excluded `*_viewer.html`; this artifact only escaped because its name did not match. It now matches. tests/test_no_hardcoded_paths.py fails the build if such a path returns. Its allowlist holds exactly the two files fixed in PR #13 and is checked for stale entries, so it shrinks to nothing when that merges. Not fixed here, and worth separate changes: - The loader reads the legacy `capture.db` schema. openadapt-capture's recorder writes `recording.db` (recorder.py:1292), so this loads old recordings only. - Roughly 50 status documents at the repository root still carry these paths. They are prose, not code, so the guard skips markdown.
The guard has to spell out the prefixes it bans, so it flagged its own source and failed CI on all four matrix jobs. It passed locally for the wrong reason: the file was still untracked when I ran it, so `git ls-files` never returned it. Once committed it became tracked and started matching. Skipping it by path is the fix, and the stale-entry test now covers that path too, so a rename cannot leave the exclusion pointing at nothing. Re-verified by planting a violation in src/ and in tests/ with the file tracked this time. Both fail the guard; a clean tree passes.
The two `scripts/` files it exempted are fixed on main, so the guard covers every tracked file with no exceptions. Verified by planting a violation in scripts/generate_for_web.sh, which the allowlist used to hide.
abrichr
force-pushed
the
fix/hardcoded-founder-paths
branch
from
August 27, 2026 18:35
ab3afec to
a922ffb
Compare
Contributor
📸 Generated Screenshots PreviewScreenshots have been generated. Download the artifacts to preview them. Generated Files:
|
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.
This is a public repo, and a path under one developer's home directory was baked into library code, two tests, an example script, and a checked-in HTML artifact. PR #13 removed the two in the screenshot pipeline. This gets the rest.
The one that actually broke things
real_data_loader.pydefaulted to/Users/abrichr/oa/src/openadapt-capture/turn-off-nightshift, soopenadapt-viewer benchmarkwith no--dataraisedFileNotFoundErrorfor everyone who isn't that developer.Re-pointing that default at a sibling checkout would have looked like a fix and not been one.
turn-off-nightshift/is gitignored in openadapt-capture (.gitignore:56), so it's local data nobody else can obtain. There's no location the default could point to that would work. So the default is gone. Name a recording with--data, or set$OPENADAPT_CAPTURE_RECORDING. Missing config now prints one line and exits 1 instead of dumping a traceback.The one that was quieter and worse
Key frames in
episodes.jsonare stored relative to the checkout root, like../openadapt-capture/<rec>/screenshots/step_0.png. The loader resolved them by prepending a literal/Users/abrichr/oa/src. Copy a recording anywhere else and all six screenshot paths came back pointing at a machine you don't have, with no error, because nothing checks that a screenshot path exists.It now re-anchors on the capture directory the caller passed. I checked both directions:
/private/tmp/.../fakeroot/: 6 frames, 0 missing. The old code returned/Users/abrichr/...here.Deleting test_benchmark_refactored.html
I removed it rather than editing the paths inside it. It's generated by
openadapt-viewer benchmark --output test_benchmark_refactored.html, no code reads it, and it embedded both the absolute paths and the step text of that private gitignored recording..gitignorealready excluded*_viewer.html; this one only survived because its name doesn't match the glob. It's ignored by name now.verify_real_data.pyis the only script that mentions it, and it already handles the file being absent without failing.Say the word if you'd rather keep it and I'll regenerate it with portable paths instead.
Keeping it out
tests/test_no_hardcoded_paths.pyfails the build if/Users/or/home/shows up in tracked code. I verified it fails on a planted violation, not just that it passes.#13 merged while I was working on this, so the branch is rebased on it and the allowlist is now empty: the guard covers every tracked file with no exceptions. Re-verified by planting a violation in
scripts/generate_for_web.sh, which the allowlist used to hide.Markdown is out of scope here. About 50 status documents at the repo root still carry these paths. #15 sweeps them and drops that exemption.
Two variables, on purpose
$OPENADAPT_CAPTURE_DIR(PR #13, andtests/test_screenshot_generation.pyhere) names the openadapt-capture checkout that holds many recordings.$OPENADAPT_CAPTURE_RECORDINGnames one recording directory inside it. Overloading a single name with both meanings would have been a bug waiting to happen.Found but not fixed
The loader reads
capture.dbwithSELECT * FROM capture. openadapt-capture's recorder writesrecording.dbnow (recorder.py:1292,recorder.py:2368), so this path loads pre-PR-#28 recordings only. That's a schema change, not a path fix, so I left it alone. Worth an issue.Tests
CI is green on all five checks.
pytest tests/gives145 passed, 46 skipped, andruff check .passes. CLI verified end to end both with and without a recording configured.Running pytest over the whole tree instead of
tests/turns up one more failure,test_minimal_viewer.py::test_viewer_html. It asserts onviewers/benchmark/minimal_viewer.html, which.gitignore:15excludes, so it fails on any fresh clone. I reproduced it on a clean clone of main. CI only runstests/, so it never sees it. Untouched here.One thing worth calling out, since it's the kind of bug this PR is nominally about. The guard failed CI on first push because it flagged its own source, which has to spell out the prefixes it bans. It had passed locally only because the file was still untracked when I ran it, so
git ls-filesnever returned it. Fixed in the second commit, and re-verified with planted violations in bothsrc/andtests/with the file tracked.