Skip to content

feat(study_material): add the sources list and coach setup to download study material - #92

Merged
lbildzinkas merged 4 commits into
masterfrom
fm/ic-study-sources
Oct 10, 2026
Merged

lbildzinkas merged 4 commits into
masterfrom
fm/ic-study-sources

Conversation

@lbildzinkas

@lbildzinkas lbildzinkas commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Intent

Add a committed sources list naming each piece of study material the coach teaches from, and a coach setup command that downloads it into the git-ignored data/study-material/ folder, so third-party material is downloaded at setup rather than committed (ADR-0002).

The sources list covers the System Design Primer README text (no images), its worked system design solutions and its Anki decks, all under CC BY 4.0, and the Tech Interview Handbook's six behavioural pages plus its system design, engineering levels and coding rubric pages, under MIT and fetched from the repository rather than the website. Each entry records its download URL, a pinned commit SHA, its licence and whether it may be used only locally, and the list is validated against a schema.

coach setup must be safe to run twice and must never write outside the git-ignored folder. A third-party notices file credits Donne Martin for the Primer and carries the Handbook's MIT notice. Tests validate the sources list against its schema and exercise the downloader against a local fake source, the project's single check command passes locally and in CI, and code comments link the technical references used so the change can be studied while reviewed.

Closes #15

What Changed

  • Add sources.yaml, a committed manifest pinning each study source (System Design Primer text, worked solutions and Anki decks; Tech Interview Handbook pages) to a full commit SHA with its SPDX licence, local_only flag and download URL template, validated by new Pydantic Source/SourcesList models in src/interview_coach/study_material.py that reject bad commits, escaping paths, images, malformed URL templates and duplicate names.
  • Add a coach setup subcommand that downloads every source into the git-ignored data/study-material/ folder and is safe to run twice: files are written to a temporary name and renamed into place, and a .commit stamp makes already-downloaded sources skip fetching; failures print a readable coach: error: message and exit 1.
  • Add THIRD_PARTY_NOTICES.md crediting Donne Martin (CC BY 4.0) and the Tech Interview Handbook (MIT), document coach setup in the README, add the pydantic and pyyaml dependencies, and add tests covering the sources-list schema and the downloader against a local file:// fake source.

Risk Assessment

✅ Low: The change is well-bounded: all acceptance criteria are source-verified (pinned URLs resolve, coverage matches the report, notices credit both sources, behavioral tests for the schema and downloader), and both fix-round changes were verified by execution to do exactly what was prescribed with no new defects or unrequired components.

Testing

Drove the real coach CLI live: clean-clone setup downloaded every pinned source into the git-ignored folder with a clean git status, the second run was a no-op, a local-only fake source stayed inside the data folder and was labelled, and five corrupted/hand-edited sources lists all failed with a readable one-line error and exit 1; all targeted tests pass and every scenario passed with no findings.

  • Live validation: ✅ go - 8 of 8 scenarios driven live against the product
Scenario Result Live Evidence
A clean-clone coach setup (no API key) downloads every source at its pinned commit into data/study-material ✅ pass live setup-first-run.txt + downloaded-tree.txt (25 files across 4 sources; stamps hold SHAs ae9bbd7b…/e1d28e88…; zero image files)
Running coach setup twice is safe: the second run skips every source without refetching ✅ pass live setup-second-run.txt — all four sources report 'already up to date', exit 0
After coach setup, git status shows nothing new to commit ✅ pass live git status --porcelain returned empty after both runs
The sources list covers the Primer text (no images), its 8 worked solutions, the 3 Anki decks, and the 10 chosen Handbook pages, each pinned to a full commit SHA ✅ pass live downloaded-tree.txt — exactly README+LICENSE, 8 solutions/, 3 .apkg decks, 10 Handbook files; fetches succeeded only because the pinned SHAs exist upstream
A local-only source is marked '(local only)' and is never written outside the git-ignored data folder ✅ pass live local-only-fake-source.txt + find of the scenario dir showing zero files outside data/study-material
A hand-edited or corrupted sources list prints a readable coach: error: … and exits 1 instead of a traceback ✅ pass live Live CLI drives: missing file, tab-indented YAML, {oops} placeholder, space in download_url, ../escape.md path — all exit 1 with one-line errors
THIRD_PARTY_NOTICES.md credits Donne Martin (CC BY 4.0) and carries the Handbook's full MIT notice ✅ pass live Shipped file inspected: 'Copyright 2017 Donne Martin' + CC BY 4.0 link + verbatim MIT License block for Yangshun Tay
README's 'Downloading the study material' section is a ## section placed above ## License ✅ pass live grep -n '^## ' README.md shows the section at line 64, before ## License at line 75
Evidence: First `coach setup` run on clean data folder (no API key)

system-design-primer-text: downloaded system-design-primer-solutions: downloaded system-design-primer-anki: downloaded tech-interview-handbook: downloaded exit=0

system-design-primer-text: downloaded
system-design-primer-solutions: downloaded
system-design-primer-anki: downloaded
tech-interview-handbook: downloaded
Evidence: Second `coach setup` run (idempotent)

system-design-primer-text: already up to date system-design-primer-solutions: already up to date system-design-primer-anki: already up to date tech-interview-handbook: already up to date exit=0

system-design-primer-text: already up to date
system-design-primer-solutions: already up to date
system-design-primer-anki: already up to date
tech-interview-handbook: already up to date
Evidence: Full listing of downloaded study material (30 files, no images)
./.gitkeep
./system-design-primer-anki/.commit
./system-design-primer-anki/LICENSE.txt
./system-design-primer-anki/resources/flash_cards/OO Design.apkg
./system-design-primer-anki/resources/flash_cards/System Design Exercises.apkg
./system-design-primer-anki/resources/flash_cards/System Design.apkg
./system-design-primer-solutions/.commit
./system-design-primer-solutions/LICENSE.txt
./system-design-primer-solutions/solutions/system_design/mint/README.md
./system-design-primer-solutions/solutions/system_design/pastebin/README.md
./system-design-primer-solutions/solutions/system_design/query_cache/README.md
./system-design-primer-solutions/solutions/system_design/sales_rank/README.md
./system-design-primer-solutions/solutions/system_design/scaling_aws/README.md
./system-design-primer-solutions/solutions/system_design/social_graph/README.md
./system-design-primer-solutions/solutions/system_design/twitter/README.md
./system-design-primer-solutions/solutions/system_design/web_crawler/README.md
./system-design-primer-text/.commit
./system-design-primer-text/LICENSE.txt
./system-design-primer-text/README.md
./tech-interview-handbook/.commit
./tech-interview-handbook/LICENSE
./tech-interview-handbook/apps/website/contents/behavioral-interview-questions.md
./tech-interview-handbook/apps/website/contents/behavioral-interview-rubrics.md
./tech-interview-handbook/apps/website/contents/behavioral-interview-senior-candidates.md
./tech-interview-handbook/apps/website/contents/behavioral-interview.md
./tech-interview-handbook/apps/website/contents/coding-interview-rubrics.md
./tech-interview-handbook/apps/website/contents/engineering-levels.md
./tech-interview-handbook/apps/website/contents/final-questions.md
./tech-interview-handbook/apps/website/contents/self-introduction.md
./tech-interview-handbook/apps/website/contents/system-design.md
Evidence: Local-only fake source via real CLI (second run shows skip)

fake-deck (local only): already up to date

fake-deck (local only): already up to date

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 1 issue found → auto-fixed (2) ✅
  • ⚠️ src/interview_coach/cli.py:46 - coach setup's readable-error handler is incomplete, so some bad sources lists produce a raw traceback instead of coach: error: ... and exit 1. Verified by execution: (1) a malformed sources.yaml (e.g. tab indentation) raises yaml.scanner.ScannerError, whose MRO is YAMLError -> Exception — neither OSError nor ValueError — so it escapes except (OSError, ValueError) at cli.py:46, contradicting the comment at cli.py:47-48 that 'a bad sources list is a ValueError'; the sibling is the yaml.safe_load call in load_sources (src/interview_coach/study_material.py:80). (2) A download_url with a stray placeholder (e.g. https://x/{commit}/{path}/{oops}) passes _url_template (src/interview_coach/study_material.py:26-29) and raises KeyError('oops') in Source.url_for's str.format (src/interview_coach/study_material.py:61) — also uncaught. Remedy (non-functional, error path only): wrap yaml.YAMLError into ValueError inside load_sources, and reject unknown {...} placeholders in _url_template. Reachable only via a hand-edited or corrupted manifest — the exact input class this handler exists for — so warning, not error.

🔧 Fix applied.
2 issues (1 warning, 1 info) still open:

  • ⚠️ src/interview_coach/study_material.py:38 - Residual sibling of finding R1 that fix round d436932 left behind: a hand-edited sources list can still produce a raw traceback instead of coach: error: ... and exit 1. Verified by execution: a download_url whose literal text contains a raw space or control character (e.g. https://example.com/my folder/{commit}/{path}) passes _url_template (it inspects only {...} placeholders, not the literal template text), reaches urllib.request.urlopen, and raises http.client.InvalidURL — an HTTPException, neither OSError nor ValueError — which escapes except (OSError, ValueError) at src/interview_coach/cli.py:46 and makes the comment at cli.py:47-49 ('a bad sources list is a ValueError') inaccurate again. Probe output: urlopen('https://example.com/my folder/x') → InvalidURL -> HTTPException -> Exception. Remedy at the earliest shared boundary every download_url passes through: reject characters http.client refuses ([\x00-\x20\x7f]) in the literal template inside _url_template (src/interview_coach/study_material.py:38), with one CLI test mirroring the two R1 tests (tests/test_study_material.py:175,184); catching http.client.HTTPException in _setup() additionally covers server-borne mid-connection failures but alone would be a symptom patch for the manifest-borne class. This is the only manifest field that can still raise outside (OSError, ValueError): name/commit/licence/local_only are constrained by patterns, and files paths are percent-encoded in url_for (study_material.py:58) and re-checked with resolve/is_relative_to at download time (study_material.py:102-105). Reachable only via a hand-edited or corrupted manifest — the exact input class this handler exists for — so warning, not error; the remedy is a one-condition error-path fix, not an extension of intent.
  • ℹ️ README.md:68 - The new usage section ### Downloading the study material (README.md:68) is placed after and nested under ## License (README.md:64), so the setup instructions read as a subsection of the license. Remedy: move the block above ## License and promote the heading to ##. Non-functional documentation-structure fix; introduced with this change.

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 8 of 8 scenarios driven live against the product
Scenario Result Live Evidence
A clean-clone coach setup (no API key) downloads every source at its pinned commit into data/study-material ✅ pass live setup-first-run.txt + downloaded-tree.txt (25 files across 4 sources; stamps hold SHAs ae9bbd7b…/e1d28e88…; zero image files)
Running coach setup twice is safe: the second run skips every source without refetching ✅ pass live setup-second-run.txt — all four sources report 'already up to date', exit 0
After coach setup, git status shows nothing new to commit ✅ pass live git status --porcelain returned empty after both runs
The sources list covers the Primer text (no images), its 8 worked solutions, the 3 Anki decks, and the 10 chosen Handbook pages, each pinned to a full commit SHA ✅ pass live downloaded-tree.txt — exactly README+LICENSE, 8 solutions/, 3 .apkg decks, 10 Handbook files; fetches succeeded only because the pinned SHAs exist upstream
A local-only source is marked '(local only)' and is never written outside the git-ignored data folder ✅ pass live local-only-fake-source.txt + find of the scenario dir showing zero files outside data/study-material
A hand-edited or corrupted sources list prints a readable coach: error: … and exits 1 instead of a traceback ✅ pass live Live CLI drives: missing file, tab-indented YAML, {oops} placeholder, space in download_url, ../escape.md path — all exit 1 with one-line errors
THIRD_PARTY_NOTICES.md credits Donne Martin (CC BY 4.0) and carries the Handbook's full MIT notice ✅ pass live Shipped file inspected: 'Copyright 2017 Donne Martin' + CC BY 4.0 link + verbatim MIT License block for Yangshun Tay
README's 'Downloading the study material' section is a ## section placed above ## License ✅ pass live grep -n '^## ' README.md shows the section at line 64, before ## License at line 75
  • env -u OPENAI_API_KEY .venv/bin/coach setup in the worktree on a clean data/study-material (first run: 4 sources downloaded, exit 0)
  • env -u OPENAI_API_KEY .venv/bin/coach setup second run (4 sources 'already up to date', exit 0)
  • git status --porcelain after both setup runs (empty — nothing new to commit)
  • find data/study-material -type f + stamp files + file on .apkg decks + zero image/.part files (content integrity at pinned SHAs ae9bbd7… and e1d28e8…)
  • Bad-manifest drives of the real coach setup in disposable dirs: missing sources.yaml, tab-indented malformed YAML, {oops} unknown placeholder, download_url with a space, ../escape.md path — all exit 1 with coach: error: and no traceback
  • Local-only drive: fake file:// source with local_only: true through the real CLI — output fake-deck (local only): downloaded, find proves zero files outside data/study-material
  • .venv/bin/python -m pytest tests/test_study_material.py -v (21 passed)
  • .venv/bin/python -m pytest tests/test_cli.py tests/test_study_material.py tests/test_smoke.py -q (24 passed)
  • Verified THIRD_PARTY_NOTICES.md credits Donne Martin (CC BY 4.0) and carries the Handbook's full MIT notice; README's ## Downloading the study material sits above ## License at ## level (R3)
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

sources.yaml names the System Design Primer text, worked solutions and Anki
decks and the chosen Tech Interview Handbook pages, each pinned to a commit
with its licence and whether it is local-only, validated by Pydantic models.
coach setup downloads them into the git-ignored data/study-material/ folder,
skipping sources already at their pinned commit. THIRD_PARTY_NOTICES.md
credits both sources.

Closes #15
@lbildzinkas
lbildzinkas merged commit 35c97bc into master Oct 10, 2026
1 check passed
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.

Sources list and a setup command for study material

1 participant