diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml new file mode 100644 index 0000000..8c90d6b --- /dev/null +++ b/.github/workflows/pages.yml @@ -0,0 +1,71 @@ +name: Publish Studio preview + +on: + push: + branches: [main] + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + quality: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Enable pinned pnpm + run: corepack enable && corepack prepare pnpm@11.7.0 --activate + - name: Install project dependencies + run: pnpm install --frozen-lockfile + - name: Install Studio server dependencies + run: python -m pip install --disable-pip-version-check -r requirements.txt + - name: Install Chromium + run: pnpm exec playwright install --with-deps chromium + - name: Run release quality gate + env: + CI: true + CCA_STUDIO_VERBOSE: "1" + run: pnpm test + build: + needs: quality + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Enable pinned pnpm + run: corepack enable && corepack prepare pnpm@11.7.0 --activate + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Build AI-disabled preview + env: + VITE_CCAF_PUBLIC_PREVIEW: "true" + run: pnpm run studio:build && pnpm run studio:preview:check + - uses: actions/upload-pages-artifact@v3 + with: + path: studio/dist + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 0000000..1623cc6 --- /dev/null +++ b/.github/workflows/quality.yml @@ -0,0 +1,46 @@ +name: Course quality + +on: + push: + pull_request: + +jobs: + audit-and-test: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Enable pinned pnpm + run: corepack enable && corepack prepare pnpm@11.7.0 --activate + - name: Install project dependencies + run: pnpm install --frozen-lockfile + - name: Install Studio server dependencies + run: python -m pip install --disable-pip-version-check -r requirements.txt + - name: Install Chromium + run: pnpm exec playwright install --with-deps chromium + - name: Course audit + run: pnpm run audit + - name: Studio typecheck and unit tests + run: pnpm run typecheck && pnpm run test:unit + - name: Save-server tests + run: pnpm run test:server + - name: Studio server tests + run: pnpm run test:studio-server + - name: Production Studio build + run: pnpm run studio:build + - name: Verify release identity + run: pnpm run studio:release:check + - name: Browser journey tests + run: pnpm run test:e2e + - name: Upload verified Studio build + uses: actions/upload-artifact@v4 + with: + name: studio-dist + path: studio/dist + retention-days: 14 diff --git a/.gitignore b/.gitignore index 4a56977..187cb1e 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,11 @@ my-progress.json my-progress.backup.json my-progress.json.tmp .DS_Store +node_modules/ +.venv/ +.studio-data/ +studio/dist/ +test-results/ +playwright-report/ +__pycache__/ +*.pyc diff --git a/AGENTS.md b/AGENTS.md index 631a54c..3a7bc0e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,36 +1,74 @@ -# AI Tutor Briefing — CCA-F Study Course - -You are the learner's personal tutor for the CCA-F (Claude Certified Architect – Foundations) exam. This folder is a static study site (plain HTML/JS, no build step). Serve it with `python3 serve.py` (auto-saves progress to `my-progress.json`; plain `python3 -m http.server 8000` also works but skips file-saving). - -## Your job - -1. **Teach on request.** When the learner pastes an "Ask my tutor" prompt, answer in this order: plain meaning, tiny example, boxes-and-arrows sketch, production reason, then two short checks. Define jargon on first use. -2. **Grade exercise reports.** Grade the fixed build against the rubric in [exercise-library.js](exercise-library.js). State what is right, what needs repair, one small redo, and the current level: Beginner, Developing, Exam-ready, or Strong. -3. **Grow the course.** After grading or a study session: - - Log real mistakes in a `Mistake Log.md` you create/maintain (date, their wrong idea, the correct idea, a redo exercise). - - Add flashcards for new vocabulary or mistakes by **APPENDING** cards to the right deck in [flashcards.js](flashcards.js) — never reorder or delete existing cards (indices are how learner progress is stored). - - Add new exercises by APPENDING to [exercises.js](exercises.js). Do not replace the fixed build attached to a required unit without a migration plan. -4. **Keep quality up.** Follow [DESIGN-STANDARD.md](DESIGN-STANDARD.md) and [VISUAL-MEDIA-PIPELINE.md](VISUAL-MEDIA-PIPELINE.md): visual first, short chunks, one idea per scene, real screenshots for real interfaces, captioned audio/video, and typed fallbacks. -5. **Protect honest mastery.** A passing score with guesses is not mastery. Required evidence is five lesson steps, quiz at least 80% with zero guesses, an independent build, and a complete teach-back. - -## How the site fits together - -- `course-data.js` is the shared manifest for all 23 required units, prerequisites, resources, lesson cards, and checkpoint banks -- `dashboard.html` = Home · `today.html` = current lesson · `curriculum.html` = 23 units · `timeline.html` = visual progress path -- `foundation-lab.html` = visual/audio Workbench lessons · `concept-map.html` = prerequisite map -- `teachback.html` = voice/typed explanation · `review.html` = spaced review · `tutor-bridge.html` = grounded copy/paste tutor handoff -- `engineer-path.html` = the parallel Applied Engineer and technical-cofounder literacy path -- `flashcards.html?deck=X&mode=browse|learn` reads decks from `flashcards.js` -- `exercise.html?id=X` reads legacy exercises from `exercises.js` plus required fixed builds from `exercise-library.js` -- `quiz.html?set=X` reads question banks from `quizzes.js` · `pretest.html` = 30-Q diagnostic -- Article pages (`article-*.html`) retell Anthropic engineering posts as diagrams; `repair-map.html`, `learning-map.html`, and `concept-map.html` are visual guides -- Shared nav lives in `nav.js` (edit once, applies everywhere) · styles in `study.css` -- **All learner progress lives in browser localStorage** (`ccaf-*` keys). Key ones: `ccaf-curriculum` (units done/opened), `ccaf-pipeline` (today's 5 steps), `ccaf-learn-` (card mastery), `ccaf-ex-` (exercise answers), `ccaf-last` (resume pointer). When served via `serve.py`, nav.js also mirrors every `ccaf-*` change into `my-progress.json` (gitignored) and auto-restores from it — NEVER commit, edit, or delete that file; it is the learner's progress. - -## Rules - -- Content edits must be **append-only** for `flashcards.js` decks and legacy `exercises.js` entries because progress is index-based. -- Do not present reported exam specifications as official. Use the current Exam Facts page, label unverified numbers as "community-reported," and prefer current official Anthropic sources when available. -- Never paste in copyrighted material (book PDFs, full articles) — link instead. -- Never commit `my-progress.json`, backups, private PDFs, Obsidian settings, or personal study notes. -- After any curriculum or JS edit, run `node course-audit.mjs` and load the changed journey in a browser at desktop and phone widths. +# AI Tutor Briefing - CCA-F Study Studio + +You are the learner's tutor, grader, quizmaster, and architecture reviewer for +the Claude Certified Architect - Foundations exam. The learner is a complete +beginner and is dyslexic. Define jargon once, use short chunks, lead with a +visual example, and teach through: + +```text +watch -> draw -> build -> explain aloud -> flashcard +``` + +## Start here + +1. Read this file and `FRONTIER-AI.md`. +2. Launch `./Start CCA-F Study Studio.command` if the app is not already live. +3. Open `http://127.0.0.1:8765/`. +4. If MCP is available, call `get_tutor_briefing`, then `get_current_session`. +5. Continue the one next activity shown by the server. Do not infer progress from old HTML pages. + +## Current architecture + +- `studio/`: React + TypeScript + Vite desktop interface. +- `studio_server/`: FastAPI, deterministic lesson engine, SQLite, optional Ollama tutor, and stdio MCP server. +- `studio/src/content/course-manifest.json`: protected typed course manifest. +- `scripts/start_studio.py`: low-lag Mac launcher using cached runtime and build folders. +- `scripts/run_frontier_mcp.py`: common stdio entry point for Codex, Claude, or another MCP client. +- `/legacy/`: compatibility copy of the original HTML/JavaScript tutor. +- Mutable learner data: `~/Library/Application Support/CCA-F Study Studio/studio.sqlite3`. + +Only W1 is fully wired into the new interactive engine in this release. The +remaining units stay in the protected manifest for staged migration. + +## Teaching and grading + +1. Plain meaning in one or two lines. +2. One tiny concrete example. +3. A simple boxes-and-arrows sketch. +4. One learner action. +5. A brief check, then three flashcards for completed lessons. + +Grade with four levels: **Beginner**, **Developing**, **Exam-ready**, and +**Strong**. Track confidence and guessing separately from correctness. A +correct guess is not secure knowledge. + +## Authority boundaries + +- Deterministic code owns correctness, prerequisites, progression, mastery, and review scheduling. +- Ollama provides requested hints or simplification only. Its output is advisory and cannot change progress. +- Frontier models may grade work, identify failure modes, submit a review, report a content gap, or propose a plan update. +- Frontier models must never change mastery or curriculum directly. The learner accepts or rejects proposals in the app. + +## Content and privacy rules + +- Do not promote community-reported exam specifications to official facts. +- Do not alter exam facts, answer keys, lesson meaning, or video mappings without explicit approval and source verification. +- Never commit or expose progress databases, `my-progress*.json`, credentials, private notes, Obsidian settings, audio, or confidential PDFs. +- Real interface procedures require real screenshots or recordings. Generated visuals may explain invisible concepts but cannot impersonate real software. +- Preserve Atkinson Hyperlegible, 20px body text, visible focus, reduced motion, 200% reflow, and one primary action per scene. + +## Verification + +For code changes, run: + +```bash +pnpm run audit +pnpm run typecheck +pnpm run test:unit +python -m pytest tests/studio_server -q +pnpm run studio:build +pnpm run test:e2e +``` + +Keep the legacy tutor and existing progress compatible until a separately +approved cutover removes them. diff --git a/CLAUDE.md b/CLAUDE.md index 631a54c..229dc6a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,36 +1,16 @@ -# AI Tutor Briefing — CCA-F Study Course +# Claude Code Entry Point -You are the learner's personal tutor for the CCA-F (Claude Certified Architect – Foundations) exam. This folder is a static study site (plain HTML/JS, no build step). Serve it with `python3 serve.py` (auto-saves progress to `my-progress.json`; plain `python3 -m http.server 8000` also works but skips file-saving). +Read `AGENTS.md`, then `FRONTIER-AI.md`, before tutoring or changing code. -## Your job +Use the project MCP server named `ccaf-study-studio` when it is configured. Its +first two calls should be: -1. **Teach on request.** When the learner pastes an "Ask my tutor" prompt, answer in this order: plain meaning, tiny example, boxes-and-arrows sketch, production reason, then two short checks. Define jargon on first use. -2. **Grade exercise reports.** Grade the fixed build against the rubric in [exercise-library.js](exercise-library.js). State what is right, what needs repair, one small redo, and the current level: Beginner, Developing, Exam-ready, or Strong. -3. **Grow the course.** After grading or a study session: - - Log real mistakes in a `Mistake Log.md` you create/maintain (date, their wrong idea, the correct idea, a redo exercise). - - Add flashcards for new vocabulary or mistakes by **APPENDING** cards to the right deck in [flashcards.js](flashcards.js) — never reorder or delete existing cards (indices are how learner progress is stored). - - Add new exercises by APPENDING to [exercises.js](exercises.js). Do not replace the fixed build attached to a required unit without a migration plan. -4. **Keep quality up.** Follow [DESIGN-STANDARD.md](DESIGN-STANDARD.md) and [VISUAL-MEDIA-PIPELINE.md](VISUAL-MEDIA-PIPELINE.md): visual first, short chunks, one idea per scene, real screenshots for real interfaces, captioned audio/video, and typed fallbacks. -5. **Protect honest mastery.** A passing score with guesses is not mastery. Required evidence is five lesson steps, quiz at least 80% with zero guesses, an independent build, and a complete teach-back. +1. `get_tutor_briefing` +2. `get_current_session` -## How the site fits together +The Study Studio server owns correctness and mastery. Claude may review work +and propose changes, but it must not directly alter progress or curriculum. -- `course-data.js` is the shared manifest for all 23 required units, prerequisites, resources, lesson cards, and checkpoint banks -- `dashboard.html` = Home · `today.html` = current lesson · `curriculum.html` = 23 units · `timeline.html` = visual progress path -- `foundation-lab.html` = visual/audio Workbench lessons · `concept-map.html` = prerequisite map -- `teachback.html` = voice/typed explanation · `review.html` = spaced review · `tutor-bridge.html` = grounded copy/paste tutor handoff -- `engineer-path.html` = the parallel Applied Engineer and technical-cofounder literacy path -- `flashcards.html?deck=X&mode=browse|learn` reads decks from `flashcards.js` -- `exercise.html?id=X` reads legacy exercises from `exercises.js` plus required fixed builds from `exercise-library.js` -- `quiz.html?set=X` reads question banks from `quizzes.js` · `pretest.html` = 30-Q diagnostic -- Article pages (`article-*.html`) retell Anthropic engineering posts as diagrams; `repair-map.html`, `learning-map.html`, and `concept-map.html` are visual guides -- Shared nav lives in `nav.js` (edit once, applies everywhere) · styles in `study.css` -- **All learner progress lives in browser localStorage** (`ccaf-*` keys). Key ones: `ccaf-curriculum` (units done/opened), `ccaf-pipeline` (today's 5 steps), `ccaf-learn-` (card mastery), `ccaf-ex-` (exercise answers), `ccaf-last` (resume pointer). When served via `serve.py`, nav.js also mirrors every `ccaf-*` change into `my-progress.json` (gitignored) and auto-restores from it — NEVER commit, edit, or delete that file; it is the learner's progress. +Current local app: `http://127.0.0.1:8765/` -## Rules - -- Content edits must be **append-only** for `flashcards.js` decks and legacy `exercises.js` entries because progress is index-based. -- Do not present reported exam specifications as official. Use the current Exam Facts page, label unverified numbers as "community-reported," and prefer current official Anthropic sources when available. -- Never paste in copyrighted material (book PDFs, full articles) — link instead. -- Never commit `my-progress.json`, backups, private PDFs, Obsidian settings, or personal study notes. -- After any curriculum or JS edit, run `node course-audit.mjs` and load the changed journey in a browser at desktop and phone widths. +Legacy HTML is available at `/legacy/`; it is not the source of current session state. diff --git a/COURSE-AUDIT.md b/COURSE-AUDIT.md index 5fbd3f2..699411b 100644 --- a/COURSE-AUDIT.md +++ b/COURSE-AUDIT.md @@ -105,7 +105,7 @@ The broad lane covers programming, web/networking, data, Git/testing/delivery, s ## Release safeguards -- `course-data.js` is the single source for order, prerequisites, resources, builds, concepts, quiz destinations, and tutor prompts. +- `course-data.js` is the single editing source for order, prerequisites, resources, builds, concepts, quiz destinations, and tutor prompts; the Study Studio's protected `studio/src/content/course-manifest.json` is generated from it (plus `video-data.js`) by `scripts/export-studio-manifest.mjs` and checked in CI. - `course-audit.mjs` validates prerequisites, unique builds, review cards, beginner quiz banks, internal resources, and stale old-unit labels. - Private PDFs, personal progress JSON, Obsidian settings, and personal notes are never included in the public release. - Exam facts remain separately labeled **official** or **reported** and were not rewritten during this repair. diff --git a/FRONTIER-AI.md b/FRONTIER-AI.md new file mode 100644 index 0000000..6b9b6f4 --- /dev/null +++ b/FRONTIER-AI.md @@ -0,0 +1,59 @@ +# Frontier AI Handoff + +This repository contains two tutor surfaces: + +- **CCA-F Study Studio** at `http://127.0.0.1:8765/` is the current local tutor. +- **Legacy tutor** remains available at `/legacy/` for one compatibility release. + +Start the local app with: + +```bash +./Start\ CCA-F\ Study\ Studio.command +``` + +## Connect through MCP + +Study Studio exposes a local **stdio MCP server**. It gives frontier models a +server-authoritative learner session and accepts advisory reviews or proposals. +It cannot directly change mastery or curriculum. + +Universal command: + +```bash +/usr/bin/python3 scripts/run_frontier_mcp.py +``` + +The launcher reuses the cached Study Studio runtime and the same SQLite data in +`~/Library/Application Support/CCA-F Study Studio/`. Launch the app once before +the first MCP connection so that runtime dependencies exist. + +Available tools: + +- `get_tutor_briefing` +- `get_current_session` +- `get_review_packet` +- `submit_frontier_review` +- `propose_study_plan_update` +- `report_content_gap` + +Frontier workflow: + +```text +learner work -> deterministic server -> review packet -> frontier review + | + v + advisory proposal only + | + v + learner accepts or rejects +``` + +## Authority boundaries + +- The server owns correctness, progression, prerequisites, mastery, and review timing. +- The local Ollama model supplies optional hints only and unloads after each response. +- A frontier model may grade, diagnose, and propose changes. +- Only the learner can accept a plan proposal. +- Never read, print, commit, or upload SQLite data, progress snapshots, credentials, private notes, or confidential PDFs. + +Read `AGENTS.md` before tutoring or changing code. Run `npm test` before publishing a code change. diff --git a/QUALITY-REVIEW.md b/QUALITY-REVIEW.md new file mode 100644 index 0000000..cad8464 --- /dev/null +++ b/QUALITY-REVIEW.md @@ -0,0 +1,73 @@ +# CCA-F Tutor Quality Review + +Date: 2026-07-15 + +Branch: `codex/site-quality-review` + +## Findings + +### High - fixed + +1. **An older delayed save could replace newer learner progress.** + - Reproduced with out-of-order POST requests. + - Fixed with monotonic client revisions plus locked, timestamp-aware atomic writes. + - Code: `nav.js:65`, `serve.py:59`, `serve.py:77`. + - Regression: `tests/test_serve.py::test_older_delayed_save_cannot_replace_newer_progress`. + +2. **The wrong build could satisfy a lesson's required evidence.** + - An optional legacy exercise could be credited to a different unit. + - Fixed by requiring the manifest's exact exercise ID and clearing matching evidence when a build is unmarked. + - Code: `nav.js:199`, `exercise.html:209`, `exercise.html:234`. + - Regression: `tests/e2e/learner-journey.spec.js` covers canonical, optional, and unmark flows. + +### Medium - fixed + +3. **Progress imports and resume links trusted malformed or unsafe input.** + - Fixed with a shared size/type/key validator, same-origin HTML resume links, and import confirmation. + - Code: `nav.js:6-43`, `dashboard.html:287-300`, `serve.py:36-57`. + +4. **A weaker quiz retake could erase a previously earned zero-guess pass.** + - Fixed by preserving qualified mastery separately from the latest practice attempt. + - Code: `nav.js:192-216`, `quiz.html:210-214`, `pretest.html`. + +5. **Several pages could silently fall back to an older partial course path.** + - Fixed by using the shared 23-unit manifest and showing a visible load failure when it is absent. + - Code: `today.html:188-196`, plus the shared order in Dashboard, Notes, and Quiz. + +6. **Curriculum summaries had drifted from the shared course manifest.** + - Fixed after explicit learner approval by hydrating title, goal, tutor prompt, and quiz URL from the manifest. + - Rich words, chapters, preparation, diagrams, and videos remain unchanged. + - Code: `curriculum.html:273-305`. + +7. **Core interactions were mouse-first or did not announce state changes.** + - Fixed native buttons, menu keyboard behavior, focus return, visible focus, live feedback, flashcard state, and read-aloud semantics. + - Code: `nav.js:298-325`, `timeline.html:122`, `flashcards.html:58`, `read-aloud.js`, `review.html`, `teachback.html`. + +8. **Long lesson examples could push the Notes page sideways on a phone.** + - Reproduced at 390 px with the file-path example. + - Fixed with safe wrapping and retained diagnostic overflow reporting. + - Code: `notes.html:16`. + +### Low - fixed + +9. **Shared navigation had patchwork Back/Home behavior.** + - The old Back action could leave the course; its first repair duplicated Home. + - The later UX pass replaced it with stable Home, Today, Course, Practice, Progress, and Menu destinations. + - See `UX-FLOW-REVIEW.md` for the current journey contract. + +## Verification + +- Course integrity: **825 checks passed**. +- JavaScript syntax: **15 files passed**. +- Server safety: **9 tests passed**. +- Browser journeys: **20 desktop flows and 1 phone flow passed**. +- Phone reflow: **passed** across Dashboard, Today, Timeline, Curriculum, Notes, Quiz, Build, Teach-back, and Review. +- Manual browser pass: Dashboard, Today, Notes, and Quiz rendered without console errors; quiz keyboard focus was visibly clear. +- Protected content: no diff in exam facts, course data, unit data, lesson notes, quiz answers, exercises, or video mappings. + +## Remaining Risks + +1. `notes-corrections.js` still applies targeted string corrections. The audit now fails if a target disappears, but a later data-model cleanup would be safer than expanding this patch system. +2. GitHub Pages remains browser-only storage by design. Cross-browser file restore requires the local `serve.py` tutor. +3. Automated checks and manual keyboard testing do not equal a complete screen-reader or WCAG conformance audit. +4. A plaintext MCP credential was detected in the local Codex configuration. Rotate it outside this repository; it was never printed or committed. diff --git a/README.md b/README.md index 008de7b..0d24682 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ A complete, self-contained study site for Anthropic's **Claude Certified Archite - **⚛️ The Atomic Curriculum** — 23 prerequisite-aware units, starting with a five-lesson computer-skills Workbench and building through Claude foundations, agentic systems, reliability, and production scenarios - **🛤️ Timeline** — the whole course as one visual path with ✓ done / ⭐ you-are-here tracking - **▶️ Lesson page** — tells you exactly what to do next: your current lesson, its video, and its 5 steps (they stay with the lesson until you finish it) +- **🔊 Natural read-along** — the seven beginner Workbench lessons include local ElevenLabs narration, word highlighting, a seek bar, and remembered `0.75x`-`2x` speed control +- **🎥 Reviewed video library** — 22 recent community episodes catalogued, with 14 exact lesson clips, full-episode links, transcript provenance, and current-product warnings - **🗺️ Prerequisite concept map** + **3 engineering articles retold as ~30 diagrams** (Building Effective Agents, Multi-Agent Research System, Writing Tools for Agents — original links included) - **🃏 5 flashcard decks** with two modes: flip-through *and* a Quizlet-style Learn mode that re-asks what you miss - **🧪 Pre-test (30 Q) + 6 checkpoint quizzes** that track your score *and how much you guessed* @@ -17,12 +19,13 @@ A complete, self-contained study site for Anthropic's **Claude Certified Archite - **💬 Grounded tutor bridge** that copies the current lesson, prerequisite, rubric, and recent evidence into a focused tutor prompt - **🧰 Applied Engineer path** for programming, APIs, databases, Git, testing, systems, security, architecture, and technical-cofounder judgment - **🩹 Repair guide** — the trickiest pre-test questions explained as pictures -- Progress is saved automatically — every tick, card and typed answer, the instant you make it; no account, no tracking. On the hosted site it lives in your browser (per-browser, per-address — with **Export/Import backup buttons** on the Home page). Run it locally with `serve.py` and it's **also written to a real file, `my-progress.json`**, which auto-restores if the browser's copy is ever cleared. +- **🎛️ NEW: CCA-F Study Studio** — a rebuilt guided app (React + a local Python server + a private SQLite database) that walks one unit at a time through **Learn → Draw → Build → Teach → Quiz → Review**, with server-side grading, verified backups, and an MCP connection for AI tutors ([FRONTIER-AI.md](FRONTIER-AI.md)). Unit **W1 is fully interactive** today; the other 22 units are in the protected manifest for staged migration, and the classic pages above stay available at `/legacy/`. +- Progress is saved automatically **when you run the course locally** — every tick, card and typed answer; no account, no tracking. The classic pages save to your browser and (with `serve.py`) to a real file, `my-progress.json`, which auto-restores if the browser's copy is ever cleared; Study Studio saves to a private local database with verified export/import backups. The hosted site is a **preview only and does not save progress**. ## 🚀 Run it — two ways -### 🌐 Option 1: just use the website (zero setup) -Open **https://zengdaniel7.github.io/claude-architect-study-course/** — everything works right there: lessons, diagrams, quizzes, flashcards, exercises, and **your progress saves automatically in your browser** (checkmarks, mastered cards, exercise answers — no account needed). One catch: that progress lives in *that* browser on *that* device, and the course content itself is fixed — you can't change it. +### 🌐 Option 1: peek at the live preview (zero setup) +Open **https://zengdaniel7.github.io/claude-architect-study-course/** — a **preview of the new Study Studio**. You can click through the first unit (W1) end to end: Learn → Draw → Build → Teach → Quiz → Review. It shows **"Preview only. Progress is not saved."** and means it — nothing persists between visits, and the AI tutor is switched off. Use it to *see* the course; download it to *study*. ### 💻 Option 2: download it for FULL access (recommended) ```bash @@ -30,16 +33,22 @@ git clone https://github.com/zengdaniel7/claude-architect-study-course.git cd claude-architect-study-course python3 serve.py ``` -Open http://localhost:8000 — start at the **Home** page. Downloading unlocks what the website can't do: +Open http://localhost:8000 — start at the **Home** page. Downloading unlocks what the hosted preview can't do: - **Your progress becomes a real file** — `serve.py` mirrors every tick and typed answer into `my-progress.json` in the folder, automatically, and restores from it if browser data is ever cleared. (Plain `python3 -m http.server 8000` works too, but then saves stay browser-only.) - **The course becomes YOURS to grow** — run an AI coding agent (like [Claude Code](https://claude.com/claude-code)) in the folder and the included [CLAUDE.md](CLAUDE.md) turns it into your personal tutor: it grades your exercise reports, keeps your mistake log, **adds new flashcards and exercises to the actual files** as you learn. The hosted site can never edit itself — a local copy can. - Works offline, and you can edit any lesson to match how you learn. -| | 🌐 Website | 💻 Downloaded | +**⭐ Want the new Study Studio app locally?** It ships as source. Build it once with Node 20+ and pnpm (`corepack enable && pnpm install && pnpm run studio:build`), then launch: +```bash +./Start\ CCA-F\ Study\ Studio.command +``` +Open **http://127.0.0.1:8765/** — W1 fully guided with server-side grading, progress in a private local database (with verified export/import backups), the classic pages at `/legacy/`, and MCP hookup for AI tutors ([FRONTIER-AI.md](FRONTIER-AI.md)). + +| | 🌐 Hosted preview | 💻 Downloaded | |---|---|---| -| Lessons, quizzes, flashcards, exercises | ✅ | ✅ | -| Progress auto-saves (in your browser) | ✅ | ✅ | -| Progress also saved to a real file on disk, with auto-restore | ❌ | ✅ | +| See the new Study Studio (W1 guided journey) | ✅ preview | ✅ (after one build) | +| Full classic course: lessons, quizzes, flashcards, exercises | ❌ | ✅ | +| Progress saves | ❌ never (preview only) | ✅ browser + `my-progress.json`, or the Studio database | | AI tutor that grades + upgrades the course files | ❌ | ✅ | | Edit lessons / add your own content | ❌ | ✅ | | Works offline | ❌ | ✅ | @@ -53,7 +62,7 @@ The course is model-agnostic. Every **"Ask my tutor"** and **"🧠 Check my answ ## 📖 How to study with it 1. Open **Home** → take the **Pre-Test** to set your baseline (watch your *guess count*, not just the score) -2. Every day, open **Today** — it tees up one unit and 5 small steps (watch → draw → build → explain → flashcards) +2. Every day, open **Today** — watch the short assigned clip first, open the full episode when useful, then continue through notes → draw → build → explain → flashcards 3. Complete the unit's independent build and 60-second teach-back 4. Retake its quiz until you reach at least 80% with **zero guessing** 5. A unit is mastered only when all four evidence types are present: lesson steps, quiz, independent build, and teach-back @@ -62,8 +71,10 @@ The course is model-agnostic. Every **"Ask my tutor"** and **"🧠 Check my answ - Curriculum structure inspired by [Atomic Design](https://atomicdesign.bradfrost.com/) by Brad Frost - Accessibility baseline documented in [DESIGN-STANDARD.md](DESIGN-STANDARD.md) +- Video choices and timestamps are documented in [VIDEO-CURRICULUM-MAP.md](VIDEO-CURRICULUM-MAP.md); community videos are clearly separated from official Anthropic sources - Diagrams retell three Anthropic engineering articles (linked at the top of each article page) - Font: [Atkinson Hyperlegible](https://www.brailleinstitute.org/freefont/) (Braille Institute, SIL OFL) — designed for low-vision and dyslexic readers +- Foundation narration: generated through Higgsfield using an ElevenLabs preset voice; audio is stored locally and no API key is shipped in the site - Free prep courses: [Anthropic Academy](https://anthropic.skilljar.com/) ## 📄 License diff --git a/STUDIO-QUALITY-REVIEW.md b/STUDIO-QUALITY-REVIEW.md new file mode 100644 index 0000000..3fc1315 --- /dev/null +++ b/STUDIO-QUALITY-REVIEW.md @@ -0,0 +1,80 @@ +# CCA-F Study Studio Quality Review + +Date: 2026-07-16 +Branch: `codex/study-studio-rebuild` + +## Findings and repairs + +### P1 - Bodyless requests could freeze the whole app + +`BodyLimitMiddleware` waited for a request-body event even on `GET`. Uvicorn does not promise that event, so the page and every read API could stay blank indefinitely. + +**Repair:** bypass body buffering for `GET`, `HEAD`, and `OPTIONS`; preserve streaming size enforcement for writes; add an exact regression test that fails if a `GET` touches `receive()`. + +### P1 - Learner progress could be raced or self-scored + +Stage changes, review creation, and frontier submissions were not fully atomic. Quiz payloads could also report their own score. + +**Repair:** use `BEGIN IMMEDIATE` for transitions; enforce one pending review; derive quiz correctness and guess counts from the canonical manifest; require the real pending review ID; schedule Hard/Got it reviews deterministically; keep proposal decisions immutable; reject newer database schemas instead of silently downgrading them. + +### P1 - Local/private files had weak boundaries + +The legacy server could expose dot-prefixed paths such as `.studio-data`, and the Studio compatibility routes did not require the local instance token. + +**Repair:** block all dot-prefixed paths, progress files, and temporary files; validate Host and exact Origin including port; require the instance header or HttpOnly same-site cookie for private reads and writes; return the real stale-save result. + +### P1 - The learner journey had dead ends and overlays + +Stage changes retained the old scroll position. The sticky action bar covered explanations and inputs. A completed review still looked active, Home still said Continue, and the Review hub offered a zero-card review. + +**Repair:** focus and scroll each new scene to its heading; keep actions in normal document flow; add explicit mastered, empty-review, and completed-course states; update the top bar and Home state; replace completed weekly goals with a calm next-review message. + +### P2 - Several interactions could become stale or silently fail + +Strict Mode could initialize twice; failed saves had no learner-facing recovery; Stop tutor could leave a spinner; resetting CodeMirror did not reliably update the editor; microphone and speech resources could survive the screen. + +**Repair:** share one API initialization promise, show save failures without discarding on-screen work, make tutor waits abortable, synchronize CodeMirror from props, and clean up recorder, blob URL, speech, and tutor tasks. + +### P2 - A local startup failure could masquerade as preview mode + +If the local progress API failed during initialization, the app silently switched to the unsaved public demo. A learner could continue without realizing the work was temporary. + +**Repair:** localhost now shows a clear recovery screen and never enters demo mode after an API failure. AI-disabled preview remains available only when the static public site has no local API. + +### P2 - Development I/O looked like application lag + +The production bundle is modest, but Node and thousands of development files were being read from the synced Documents folder while an 8 GB Mac was under memory compression. + +**Repair:** daily launch now uses a cached Python environment, cached built site, cached server source, and SQLite in macOS Application Support. No Vite, Node, test worker, or model starts during study. The Ollama guard keeps the model off below 35% free memory on a low-memory Mac. + +### P2 - Public preview and CI did not cover Studio + +The Vite build used root-relative assets, the Pages flow was missing, and the quality workflow did not run Studio type, unit, server, or build checks. + +**Repair:** use a relative Vite base; add an AI-disabled GitHub Pages preview; expand CI; explicitly allow only the pinned `esbuild` install script under pnpm 11; add an isolated Studio browser server and a full W1 journey test. + +## Measured results + +- Warm production page: 16-22 ms local response time. +- Warm launcher: server announces within about 1 second; no dependency install on later launches. +- Initial JavaScript: 330.35 kB raw, 103.70 kB gzip. +- CodeMirror workbench: lazy 293.94 kB raw, 95.56 kB gzip; it loads only during Build. +- CSS: 22.95 kB raw, 5.35 kB gzip. +- Production build: PASS, 130 modules, 2m 15s under current synced-folder pressure. +- Curriculum audit: PASS, 825 checks. +- Protected curriculum baseline: PASS, 4 files unchanged. +- Typed manifest check: PASS, 23 canonical units match. +- TypeScript: PASS. +- Frontend unit suite: PASS, 6 files and 10 tests from the local test cache. +- Studio server: PASS, 17 tests. +- Legacy save server: PASS, 9 tests. +- In-app browser: PASS through Learn, Draw, Build boundary, Teach, zero-guess Quiz, Review, mastery, empty queue, scheduled review, Again/Hard spacing, and low-memory Settings state. + +## Remaining risks + +- Vitest workers cannot start within their fixed timeout when launched directly from the synced folder. The identical cached worktree passes all 10 tests in 1.93 seconds; CI remains the clean repository gate. +- The in-app browser driver cannot synthesize a local file selection. The live file UI was inspected, the server transition was tested separately, and the committed Playwright journey uses `setInputFiles` in CI. +- Only W1 is wired into the interactive engine in this release. The full course remains in the protected typed manifest for staged migration. +- FastAPI's current TestClient emits a deprecation warning about its HTTPX adapter; behavior is covered, but the adapter should be updated when the upstream replacement is stable. + +No exam claim, quiz answer, video mapping, or protected curriculum file changed in this repair. diff --git a/Start CCA-F Study Studio.command b/Start CCA-F Study Studio.command new file mode 100755 index 0000000..1e0097c --- /dev/null +++ b/Start CCA-F Study Studio.command @@ -0,0 +1,3 @@ +#!/bin/zsh +cd "$(dirname "$0")" +exec /usr/bin/python3 scripts/start_studio.py diff --git a/UX-FLOW-REVIEW.md b/UX-FLOW-REVIEW.md new file mode 100644 index 0000000..d9933e9 --- /dev/null +++ b/UX-FLOW-REVIEW.md @@ -0,0 +1,95 @@ +# CCA-F Tutor UX and Flow Review + +Date: 2026-07-15 + +Branch: `codex/ux-flow-overhaul` + +## Target Journey + +Every lesson now follows one visible path: + +`Learn -> Draw -> Build -> Teach -> Quiz -> Review` + +Each stage has one primary action. Optional tools and alternate routes stay behind disclosures or in the Practice hub. + +## Findings + +### Critical - fixed + +1. **The local tutor could stall on a blank page after rendering only the navigation shell.** + - Reproduced in the in-app browser while opening Flashcards. + - Plain `http.server` was receiving unsupported progress POSTs on page after page. Its terminal log could fill while course scripts were still loading. + - Fixed with a one-time `/__health` capability check. Plain servers remain browser-only and issue no progress POSTs; `serve.py` stays quiet and keeps file backups. + - Code: `nav.js`, `serve.py`. + - Regression: `plain static-server mode never floods unsupported progress saves` and the server health tests. + +### High - fixed + +2. **The site did not behave like one course.** + - Learn, Notes, Build, Teach-back, Quiz, and Review each had different exits and generic Back links. + - Added one shared six-stage rail and a shared next-action component across the complete lesson journey. + - Code: `nav.js`, `dashboard.html`, `today.html`, `foundation-lab.html`, `notes.html`, `draw.html`, `exercise.html`, `teachback.html`, `quiz.html`, `review.html`. + +3. **Review cards had no visible Next-card step.** + - The old flow auto-advanced after grading, and the large blank card made the control relationship unclear. + - Review now uses: Reveal answer -> choose Again/Hard/Got it -> explicit Next card. + - A card is not scheduled until Next card is pressed. + - Code: `review.html`. + +4. **Quiz and Pre-Test controls covered answer choices.** + - Reproduced visually at desktop size: the sticky Previous/Next bar sat over the final answer and guessing checkbox. + - Both assessments now show one question at a time, place navigation after the answers, retain progress, and move focus to the next question. + - Code: `quiz.html`, `pretest.html`. + - Regression: `quiz controls come after the answer choices instead of covering them`. + +5. **Draw was a named stage without a real activity.** + - The old Draw link returned to a checklist row. + - Added a touch/mouse sketchpad with concept boxes, color swatches, pen size, undo, clear, autosave, a paper option, and a text alternative. + - Completing it saves lesson evidence and hands off directly to Build. + - Code: `draw.html`, `nav.js`, `today.html`. + +### Medium - fixed + +6. **Several pages competed with the primary action.** + - Stale resume links, lesson browsers, tutor-copy controls, and optional practice appeared beside the required next step. + - Resume and alternate actions now live in disclosures. Build and Teach-back end with one next-stage action. + +7. **Two flashcard systems looked like the same requirement.** + - The lesson Review queue and the optional Flashcard library used overlapping names and modes. + - The Practice hub and library now state which is required. Library modes are named Browse and Quiz me. + +8. **Normal navigation caused avoidable request and save churn.** + - File restore is checked once per tab, static course files can revalidate, and long text inputs save on a short debounce instead of every keystroke. + - Code: `nav.js`, `serve.py`, `exercise.html`, `teachback.html`. + +9. **Keyboard and screen-reader names were incomplete.** + - Weekly controls, daily checkboxes, exercise fields, filter controls, progress feedback, and disclosure state now expose names and state. + - A global hidden rule prevents hidden controls from reappearing when a component sets its own display style. + +10. **Mobile navigation carried the desktop information load.** + - Phone navigation now keeps Home, Today, and Menu visible. Course, Practice, and Progress move into Menu. + +## Protected Content + +- Exam claims and reported/official labels were not changed. +- Unit order, lesson meaning, quiz answers, exercise prompts, and video mappings were not rewritten. +- Existing `ccaf-*` storage keys remain compatible. +- Personal progress files are excluded from the change set. + +## Remaining Risks + +1. **Content sequencing needs a separate curriculum decision.** The first file lesson's build asks for valid JSON before the following JSON lesson teaches the syntax. This review flags it but does not rewrite protected curriculum content. +2. **Speech features depend on browser support.** Typing, paper drawing, and text alternatives remain complete fallbacks. +3. **GitHub Pages remains browser-only storage.** Local `serve.py` is required for automatic `my-progress.json` backups. +4. **Older reference pages are denser than the primary lesson journey.** They remain optional and no longer interrupt the required path. + +## Acceptance Matrix + +- Fresh and established progress +- Home -> lesson -> Learn -> Draw -> Build -> Teach -> Quiz -> Review +- Explicit card progression and scheduling +- One-question Quiz and Pre-Test progression +- Export/import and malformed progress +- Plain server and file-saving server modes +- Desktop, phone, 200% zoom, reduced motion, keyboard operation, long text, and overflow +- No unintended curriculum or exam-fact edits diff --git a/VIDEO-CURRICULUM-MAP.md b/VIDEO-CURRICULUM-MAP.md new file mode 100644 index 0000000..ebb0b0b --- /dev/null +++ b/VIDEO-CURRICULUM-MAP.md @@ -0,0 +1,57 @@ +# Video Curriculum Map + +Use this note to audit how reviewed videos enter the course. The live learner view is [video-library.html](video-library.html). + +## July 15, 2026 snapshot + +- Reviewed all 22 available videos in the Peace Of Code playlist from native captions. +- Assigned 14 exact clips across 13 lessons; every clip is under 10 minutes. +- Each assigned video has two choices: **watch the lesson clip** or **open the full episode**. +- Kept official Anthropic lessons and documentation as the authority. +- Excluded the promo, unofficial exam-coaching episode, and two unavailable playlist items from the teaching path. +- Corrected current-product differences for stop reasons, MCP Tool Search, Structured Outputs, Skills, CLAUDE.md, Batch API, and deliberate memory persistence. + +## Alignment gate + +A segment enters a lesson only when it: + +- matches the lesson objective; +- does not require an untaught prerequisite; +- is current enough for the product or API shown; +- supports an exam concept, practical build, or applied-engineer skill; +- has a verified timestamp and a clear reason to watch. + +## Approved lesson segments + +| Lesson | Video | Start-end | One-line focus | Domain | Evidence | +|---|---|---|---|---|---| +| o1 · Agent Loop | [Ep 01 clip](https://www.youtube.com/watch?v=ldqOnljDINc&t=1157s) · [full](https://www.youtube.com/watch?v=ldqOnljDINc) | 19:17-21:46 | Reason, call a tool, read the result, decide again. | Agentic | Native captions; ends before stale stop-reason claim | +| o2 · Orchestrator-Workers | [Ep 02 clip](https://www.youtube.com/watch?v=ejPWvBcc_DU&t=362s) · [full](https://www.youtube.com/watch?v=ejPWvBcc_DU) | 06:02-08:34 | Name the coordinator's jobs before adding workers. | Agentic | Native captions | +| t2 · Research system | [Ep 03 clip](https://www.youtube.com/watch?v=a2N6vKdQUfE&t=640s) · [full](https://www.youtube.com/watch?v=a2N6vKdQUfE) | 10:40-18:24 | Carry sources with findings and resolve conflicts. | Agentic | Native captions | +| t1 · Support system | [Ep 05 clip](https://www.youtube.com/watch?v=JJBcpwpsKzk&t=1338s) · [full](https://www.youtube.com/watch?v=JJBcpwpsKzk) | 22:18-27:40 | Block an action until a required fact is verified. | Agentic / Code | Native captions | +| m2 · One tool call | [Ep 06 clip](https://www.youtube.com/watch?v=s1j1vTnCKns&t=58s) · [full](https://www.youtube.com/watch?v=s1j1vTnCKns) | 00:58-09:48 | See how names and descriptions change tool choice. | Tools & MCP | Native captions | +| o3 · MCP server | [Ep 08 clip](https://www.youtube.com/watch?v=IVUxGTxSuH8&t=104s) · [full](https://www.youtube.com/watch?v=IVUxGTxSuH8) | 01:44-11:24 | See the MCP client-server picture and connection. | Tools & MCP | Native captions; stale later section excluded | +| m4 · Built-in tools | [Ep 09 clip](https://www.youtube.com/watch?v=eh-xxQpfBBY&t=1216s) · [full](https://www.youtube.com/watch?v=eh-xxQpfBBY) | 20:16-27:28 | Follow search -> read -> edit through a codebase. | Claude Code | Native captions | +| o4 · Claude Code workflows | [Ep 12 clip](https://www.youtube.com/watch?v=q-n1cut5e7c&t=280s) · [full](https://www.youtube.com/watch?v=q-n1cut5e7c) | 04:40-09:08 | Choose plan mode for complex, ambiguous, or risky work. | Claude Code | Native captions | +| d2 · Commits, PRs, CI | [Ep 13 clip](https://www.youtube.com/watch?v=GWCnDhgH840&t=342s) · [full](https://www.youtube.com/watch?v=GWCnDhgH840) | 05:42-08:22 | Connect a pull request to automatic checks. | Claude Code | Native captions | +| m3 · Prompt techniques | [Ep 14 clip](https://www.youtube.com/watch?v=HqwULqy1egw&t=902s) · [full](https://www.youtube.com/watch?v=HqwULqy1egw) | 15:02-22:00 | Replace vague guidance with pass/fail criteria. | Prompting | Native captions; primary | +| m3 · Prompt techniques | [Ep 15 clip](https://www.youtube.com/watch?v=FbIcU6YFrhw&t=772s) · [full](https://www.youtube.com/watch?v=FbIcU6YFrhw) | 12:52-17:26 | Target ambiguous edge cases with a few examples. | Prompting | Native captions; optional | +| p2 · PR-review capstone | [Ep 17 clip](https://www.youtube.com/watch?v=BXs7QoLQxX0&t=1246s) · [full](https://www.youtube.com/watch?v=BXs7QoLQxX0) | 20:46-28:46 | Review each item, then run an integration pass. | Reliability | Native captions | +| rel · Reliability | [Ep 18 clip](https://www.youtube.com/watch?v=7kaJdZ7veDs&t=206s) · [full](https://www.youtube.com/watch?v=7kaJdZ7veDs) | 03:26-11:42 | Separate working context from durable memory. | Reliability | Native captions | +| px · Anti-patterns | [Ep 20 clip](https://www.youtube.com/watch?v=tsIxzFg76Nw&t=2544s) · [full](https://www.youtube.com/watch?v=tsIxzFg76Nw) | 42:24-45:42 | Use a human checkpoint for high-risk synthesis. | Reliability | Native captions | + +## Reference-only episodes + +- Episodes 04, 07, 10, 11, 16, and 19 remain available as extra review in the video library. +- Each reference card explains any historical or simplified behavior before the learner opens the full episode. +- Episode 00 and the bonus exam-coaching episode are visible as **not assigned**, so exclusions are transparent. + +## Rules + +- Keep one primary video and at most one optional video per lesson. +- Link to the exact YouTube timestamp; do not copy full transcripts. +- Store the source URL and review date for provenance. +- Use transcript-first review for long videos, then focused frames around demonstrations. +- Mark outdated or contradictory claims instead of silently teaching them. +- Turn only verified ideas into lesson notes, flashcards, or build steps. +- Keep the learner flow visible: **watch clip -> open full episode if useful -> read notes -> review notes**. diff --git a/VISUAL-MEDIA-PIPELINE.md b/VISUAL-MEDIA-PIPELINE.md index b08e489..5f2045b 100644 --- a/VISUAL-MEDIA-PIPELINE.md +++ b/VISUAL-MEDIA-PIPELINE.md @@ -22,3 +22,11 @@ Every lesson communicates its main idea visually before sustained reading. 5. alt text that states the teaching point No autoplay. No dense body copy inside an image. Every video needs a still or text fallback. Generated interfaces must never be presented as real product screenshots. + +## Reviewed video rule + +- Review long videos transcript-first, then inspect frames around demonstrations. +- Link the exact lesson segment and keep a separate full-episode link. +- Use one primary source and at most one optional community clip per lesson. +- Label community material clearly; current official documentation wins when behavior differs. +- Keep captions, a one-line focus, and a local notes fallback. diff --git a/artifacts/studio-audit/01-home-natural.png b/artifacts/studio-audit/01-home-natural.png new file mode 100644 index 0000000..866bac7 Binary files /dev/null and b/artifacts/studio-audit/01-home-natural.png differ diff --git a/artifacts/studio-audit/01-home.png b/artifacts/studio-audit/01-home.png new file mode 100644 index 0000000..7219533 Binary files /dev/null and b/artifacts/studio-audit/01-home.png differ diff --git a/artifacts/studio-audit/02-learn.png b/artifacts/studio-audit/02-learn.png new file mode 100644 index 0000000..310dd27 Binary files /dev/null and b/artifacts/studio-audit/02-learn.png differ diff --git a/artifacts/studio-audit/03-draw.png b/artifacts/studio-audit/03-draw.png new file mode 100644 index 0000000..a0bcaaf Binary files /dev/null and b/artifacts/studio-audit/03-draw.png differ diff --git a/artifacts/studio-audit/04-build-bridge.png b/artifacts/studio-audit/04-build-bridge.png new file mode 100644 index 0000000..cabdd4e Binary files /dev/null and b/artifacts/studio-audit/04-build-bridge.png differ diff --git a/artifacts/studio-audit/05-build-practice.png b/artifacts/studio-audit/05-build-practice.png new file mode 100644 index 0000000..d48c267 Binary files /dev/null and b/artifacts/studio-audit/05-build-practice.png differ diff --git a/artifacts/studio-audit/06-build-mac.png b/artifacts/studio-audit/06-build-mac.png new file mode 100644 index 0000000..a88c25f Binary files /dev/null and b/artifacts/studio-audit/06-build-mac.png differ diff --git a/artifacts/studio-audit/07-teach.png b/artifacts/studio-audit/07-teach.png new file mode 100644 index 0000000..eae2a3e Binary files /dev/null and b/artifacts/studio-audit/07-teach.png differ diff --git a/artifacts/studio-audit/08-quiz.png b/artifacts/studio-audit/08-quiz.png new file mode 100644 index 0000000..0d333d5 Binary files /dev/null and b/artifacts/studio-audit/08-quiz.png differ diff --git a/artifacts/studio-audit/09-quiz-feedback.png b/artifacts/studio-audit/09-quiz-feedback.png new file mode 100644 index 0000000..9fb0c99 Binary files /dev/null and b/artifacts/studio-audit/09-quiz-feedback.png differ diff --git a/artifacts/studio-audit/10-review-front.png b/artifacts/studio-audit/10-review-front.png new file mode 100644 index 0000000..a579667 Binary files /dev/null and b/artifacts/studio-audit/10-review-front.png differ diff --git a/artifacts/studio-audit/11-review-back.png b/artifacts/studio-audit/11-review-back.png new file mode 100644 index 0000000..965f0be Binary files /dev/null and b/artifacts/studio-audit/11-review-back.png differ diff --git a/artifacts/studio-audit/12-complete-stuck.png b/artifacts/studio-audit/12-complete-stuck.png new file mode 100644 index 0000000..0c857c1 Binary files /dev/null and b/artifacts/studio-audit/12-complete-stuck.png differ diff --git a/artifacts/studio-audit/13-split-800.png b/artifacts/studio-audit/13-split-800.png new file mode 100644 index 0000000..53710b2 Binary files /dev/null and b/artifacts/studio-audit/13-split-800.png differ diff --git a/artifacts/studio-audit/14-zoom-200.png b/artifacts/studio-audit/14-zoom-200.png new file mode 100644 index 0000000..a77a2ef Binary files /dev/null and b/artifacts/studio-audit/14-zoom-200.png differ diff --git a/artifacts/studio-audit/15-home-after.jpg b/artifacts/studio-audit/15-home-after.jpg new file mode 100644 index 0000000..ecf3c44 Binary files /dev/null and b/artifacts/studio-audit/15-home-after.jpg differ diff --git a/artifacts/studio-audit/16-learn-after.jpg b/artifacts/studio-audit/16-learn-after.jpg new file mode 100644 index 0000000..f8040ff Binary files /dev/null and b/artifacts/studio-audit/16-learn-after.jpg differ diff --git a/artifacts/studio-audit/17-quiz-feedback-after.jpg b/artifacts/studio-audit/17-quiz-feedback-after.jpg new file mode 100644 index 0000000..8e3b8ea Binary files /dev/null and b/artifacts/studio-audit/17-quiz-feedback-after.jpg differ diff --git a/artifacts/studio-audit/18-review-after.jpg b/artifacts/studio-audit/18-review-after.jpg new file mode 100644 index 0000000..dc03a84 Binary files /dev/null and b/artifacts/studio-audit/18-review-after.jpg differ diff --git a/artifacts/studio-audit/19-review-comparison.jpg b/artifacts/studio-audit/19-review-comparison.jpg new file mode 100644 index 0000000..66fdc09 Binary files /dev/null and b/artifacts/studio-audit/19-review-comparison.jpg differ diff --git a/artifacts/studio-audit/comparison.html b/artifacts/studio-audit/comparison.html new file mode 100644 index 0000000..02f09b3 --- /dev/null +++ b/artifacts/studio-audit/comparison.html @@ -0,0 +1,30 @@ + + + + + + Review flow comparison + + + +

Review flow: reported problem and verified repair

+
+
+
Before: no visible next-card path
+ Original legacy review queue screenshot +
+
+
After: reveal, rate, then a clear Finish review action
+ Rebuilt Study Studio review screen +
+
+ + diff --git a/artifacts/studio-audit/design-qa.md b/artifacts/studio-audit/design-qa.md new file mode 100644 index 0000000..2988a13 --- /dev/null +++ b/artifacts/studio-audit/design-qa.md @@ -0,0 +1,28 @@ +# Studio Design QA + +## Reviewed journey + +Home -> Learn -> Draw -> Build bridge -> practice editor -> Mac file check -> Teach -> Quiz -> Review -> Complete -> Home -> empty Review -> scheduled Review -> Settings. + +## Visible checks + +- New stages begin at the heading instead of inheriting the prior scroll position. +- Action rows no longer cover lesson text, the file picker, the teach-back field, or quiz feedback. +- The first correct quiz answer immediately shows `1 correct so far`. +- Review has a visible sequence: Show answer -> rating -> Finish review. +- A mastered lesson shows `Review due`; `Again` repeats the card and `Hard` returns it in two days without lowering mastery. +- Completion changes the top bar to `Complete` and removes false Continue/Start review actions. +- The local tutor visibly reports when it is paused to protect memory. +- Atkinson Hyperlegible, 20px base text, semantic colors, visible focus, and 8px-or-less radii remain intact. + +## Evidence + +- `15-home-after.jpg` - fresh Home state. +- `16-learn-after.jpg` - corrected Learn layout. +- `17-quiz-feedback-after.jpg` - immediate score and unobscured explanation. +- `18-review-after.jpg` - reveal/rate/finish sequence. +- `19-review-comparison.jpg` - original reported review screen beside the repaired flow. + +## Result + +PASS for the W1 desktop journey at the in-app browser's current Mac viewport. Earlier split-view checks at 800px and 200% browser zoom found no horizontal overflow. The CI browser suite now repeats 800, 1024, 1440, and 1728px Mac window widths. diff --git a/artifacts/studio-audit/reference-legacy-review.png b/artifacts/studio-audit/reference-legacy-review.png new file mode 100644 index 0000000..13a63da Binary files /dev/null and b/artifacts/studio-audit/reference-legacy-review.png differ diff --git a/audio/foundation/d1-one-idea.mp3 b/audio/foundation/d1-one-idea.mp3 new file mode 100644 index 0000000..fab1446 Binary files /dev/null and b/audio/foundation/d1-one-idea.mp3 differ diff --git a/audio/foundation/d2-one-idea.mp3 b/audio/foundation/d2-one-idea.mp3 new file mode 100644 index 0000000..8b28b52 Binary files /dev/null and b/audio/foundation/d2-one-idea.mp3 differ diff --git a/audio/foundation/w1-one-idea.mp3 b/audio/foundation/w1-one-idea.mp3 new file mode 100644 index 0000000..7eaf830 Binary files /dev/null and b/audio/foundation/w1-one-idea.mp3 differ diff --git a/audio/foundation/w2-one-idea.mp3 b/audio/foundation/w2-one-idea.mp3 new file mode 100644 index 0000000..170c66a Binary files /dev/null and b/audio/foundation/w2-one-idea.mp3 differ diff --git a/audio/foundation/w3-one-idea.mp3 b/audio/foundation/w3-one-idea.mp3 new file mode 100644 index 0000000..b35a10b Binary files /dev/null and b/audio/foundation/w3-one-idea.mp3 differ diff --git a/audio/foundation/w4-one-idea.mp3 b/audio/foundation/w4-one-idea.mp3 new file mode 100644 index 0000000..398fc83 Binary files /dev/null and b/audio/foundation/w4-one-idea.mp3 differ diff --git a/audio/foundation/w5-one-idea.mp3 b/audio/foundation/w5-one-idea.mp3 new file mode 100644 index 0000000..7a47335 Binary files /dev/null and b/audio/foundation/w5-one-idea.mp3 differ diff --git a/course-audit.mjs b/course-audit.mjs index a1fd8c6..2380551 100644 --- a/course-audit.mjs +++ b/course-audit.mjs @@ -5,12 +5,21 @@ const root = new URL("./", import.meta.url); const read = (name) => fs.readFileSync(new URL(name, root), "utf8"); const exists = (name) => fs.existsSync(new URL(name, root)); const context = vm.createContext({ window: {} }); +const rawNotes = read("notes-data.js"); +const correctionSource = read("notes-corrections.js"); vm.runInContext(read("course-data.js"), context, { filename: "course-data.js" }); +vm.runInContext(read("video-data.js"), context, { filename: "video-data.js" }); +vm.runInContext(rawNotes, context, { filename: "notes-data.js" }); +vm.runInContext(correctionSource, context, { filename: "notes-corrections.js" }); +vm.runInContext(read("units-data.js"), context, { filename: "units-data.js" }); vm.runInContext(read("exercises.js"), context, { filename: "exercises.js" }); vm.runInContext(read("exercise-library.js"), context, { filename: "exercise-library.js" }); const course = context.window.CCAF_COURSE; +const media = context.window.CCAF_MEDIA; +const notes = context.window.LESSON_NOTES; +const chapters = context.UNIT_CHAPTERS; const exercises = context.EXERCISES; const failures = []; const pass = []; @@ -39,6 +48,66 @@ for (const [index, unit] of course.units.entries()) { check(Array.isArray(course.cards[unit.id]) && course.cards[unit.id].length >= 3, `${unit.id}: at least three review cards exist`); } +check(media && media.lessons && media.clips && media.episodes, "reviewed video manifest loads"); +check(media.reviewedAt === "2026-07-15", "video manifest records its transcript review date"); +check(Object.values(media.episodes).filter((episode) => episode.status !== "unavailable").length === 22, "playlist records 22 available episodes"); + +const assignedClips = new Set(); +for (const unit of course.units) { + const lesson = media.lessons[unit.id]; + check(Boolean(lesson), `${unit.id}: media lesson entry exists`); + check(Boolean(lesson && lesson.primary), `${unit.id}: primary watch source exists`); + check(!lesson || lesson.optional == null || lesson.optional.type === "clip", `${unit.id}: optional slot contains at most one reviewed clip`); + for (const item of lesson ? [lesson.primary, lesson.optional].filter(Boolean) : []) { + if (item.type !== "clip") continue; + const resolved = media.resolve(item); + assignedClips.add(item.clip); + check(Boolean(resolved), `${unit.id}: reviewed clip resolves`); + if (!resolved) continue; + check(resolved.startSec < resolved.endSec, `${unit.id}: clip has a valid time range`); + check(resolved.endSec - resolved.startSec <= 600, `${unit.id}: clip stays under ten minutes`); + check(resolved.endSec <= media.episodes[resolved.episodeKey].durationSec, `${unit.id}: clip ends inside the full episode`); + check(/[?&]t=\d+s/.test(resolved.url), `${unit.id}: clip URL includes its exact start time`); + check(!/[?&]t=\d+s/.test(resolved.fullUrl), `${unit.id}: full-episode URL starts at the beginning`); + check(resolved.captionSource && resolved.reviewedAt, `${unit.id}: clip records caption source and review date`); + } +} +check(assignedClips.size === Object.keys(media.clips).length, "every selected playlist clip is assigned to a lesson"); +for (const [key, clip] of Object.entries(media.clips)) { + check(assignedClips.has(key), `${key}: selected clip appears in the course`); + check(media.episodes[clip.episode].status !== "unavailable", `${key}: selected clip does not use an unavailable episode`); +} +for (const [key, episode] of Object.entries(media.episodes)) { + if (episode.status !== "used") continue; + check(Object.values(media.clips).some((clip) => clip.episode === key), `${key}: assigned episode has an exact lesson clip`); +} + +const correctedTeachingText = JSON.stringify({ + chapters, + notes:Object.fromEntries(Object.entries(notes).map(([id,note]) => [id,{title:note.title,html:note.html}])) +}); +for (const stale of [ + "short-term memory", + "re-reads every request", + "tools from every connected MCP server are all available at once", + "scratchpad + memory files let agents resume after context loss", + "tool_use = continue, end_turn = done", + "The 6 exam scenarios", + "The shape is guaranteed, not left to luck", + "a feature that guarantees valid JSON via constrained decoding", + "so JSON is always valid", + "so it is always valid JSON", + "reliable way to guarantee the JSON is valid" +]) check(!correctedTeachingText.includes(stale), `rendered teaching text removes stale phrase: ${stale}`); + +const correctionPairs = [...correctionSource.matchAll(/\[\s*("(?:\\.|[^"\\])*")\s*,\s*("(?:\\.|[^"\\])*")\s*\]/g)]; +check(correctionPairs.length >= 20, "notes correction targets are discoverable by the audit"); +for (const match of correctionPairs) { + const target = JSON.parse(match[1]); + check(rawNotes.includes(target), `notes correction still matches its source phrase: ${target.slice(0, 58)}`); +} +check(rawNotes.includes("The exam gives you scenarios"), "production-scenario correction still matches its source phrase"); + const requiredExercises = course.units.map((unit) => unit.exercise); check(new Set(requiredExercises).size === requiredExercises.length, "every required unit has a unique fixed build"); const exerciseMap = new Map(exercises.map((exercise) => [exercise.id, exercise])); @@ -55,12 +124,27 @@ for (const id of ["w1", "w2", "w3", "w4", "w5", "d1", "d2"]) { check(course.banks[id] && course.banks[id].questions.length >= 5, `${id}: beginner checkpoint bank has at least five questions`); } -for (const page of ["dashboard.html", "today.html", "curriculum.html", "timeline.html", "quiz.html", "pretest.html"]) { +for (const page of ["dashboard.html", "today.html", "notes.html", "curriculum.html", "timeline.html", "quiz.html", "pretest.html", "video-library.html"]) { const html = read(page); check(html.indexOf("course-data.js") < html.indexOf("nav.js"), `${page}: loads the manifest before navigation`); check(!/0 \/ 16 units|\/16 units|All 16 units/.test(html), `${page}: no stale 16-unit progress label`); } +for (const page of ["today.html", "notes.html", "curriculum.html", "video-library.html"]) { + const html = read(page); + const courseIndex = html.indexOf("course-data.js"); + const dataIndex = html.indexOf("video-data.js"); + const uiIndex = html.indexOf("video-ui.js"); + const navIndex = html.indexOf("nav.js"); + check(courseIndex >= 0 && courseIndex < dataIndex && dataIndex < uiIndex && uiIndex < navIndex, `${page}: loads course, video data, media UI, then navigation`); +} + +const videoLibrary = read("video-library.html"); +check(videoLibrary.includes("Full episode") && videoLibrary.includes("Watch "), "video library exposes exact clips and full episodes"); +check(videoLibrary.includes("notes.html?unit=") && videoLibrary.includes("review.html?unit="), "video library connects watch, notes, and review"); +check(!/ 10000, `${id}: natural foundation narration exists and is nonempty`); +} const visualPipelineName = exists("Visual Media Pipeline.md") ? "Visual Media Pipeline.md" : "VISUAL-MEDIA-PIPELINE.md"; const designStandardName = exists("Dyslexia UI Standard.md") ? "Dyslexia UI Standard.md" : "DESIGN-STANDARD.md"; diff --git a/course-data.js b/course-data.js index bf9fe90..fc58200 100644 --- a/course-data.js +++ b/course-data.js @@ -90,7 +90,7 @@ prereq:["m2"],concepts:["agent-loop","stop-reason","tool-use-loop","guardrail","workflow-vs-agent"],exercise:"agent-loop-board", quiz:"quiz.html?set=agentic",notes:"notes.html?unit=o1", ask:"Teach me the agent loop: model -> tool request -> application -> tool result -> model. Cover stop_reason, runaway guards, and when one call is enough.", - watch:[["article-effective-agents.html","Building effective agents | Visual article","Focus: workflow holds a fixed map; agent chooses its next step."],["https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons","Anthropic docs | Handling stop reasons","Focus: tool_use continues; end_turn finishes."]] + watch:[["article-effective-agents.html","Building effective agents | Visual article","Focus: workflow holds a fixed map; agent chooses its next step."],["https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons","Anthropic docs | Handling stop reasons","Focus: branch on the returned reason; tool_use requires a tool result."]] }, { id:"a2",level:"Atoms",title:"Model physics and economics", @@ -199,7 +199,7 @@ ]; var lessons={ - w1:{plain:"A file is one saved item. A folder holds files. A path is the full route to an item. An extension is the ending after the final dot.",example:"/Users/learner/Documents/study/tiny-order.json",diagram:["Finder","study folder","tiny-order.json","JSON text"],danger:"Saving rich text or adding .txt changes the file you meant to create."}, + w1:{plain:"A file is one saved item. A folder holds files. A path is the full route to an item. An extension is the ending after the final dot.",example:"/Users/student/Documents/study/tiny-order.json",diagram:["Finder","study folder","tiny-order.json","JSON text"],danger:"Saving rich text or adding .txt changes the file you meant to create."}, w2:{plain:"JSON is plain text arranged as labeled key and value pairs. The punctuation is part of the format.",example:'{ "item": "tea", "quantity": 2 }',diagram:["{ object }","\"key\"","value","validator"],danger:"Missing quotes, extra commas, and smart quotes make JSON invalid."}, w3:{plain:"A program follows instructions. A function is a named action. Arguments go in, a return value comes out, and an error explains why it could not finish.",example:"total(2, 3) -> 5",diagram:["arguments","function","return value","caller"],danger:"An error is not proof you failed. It is evidence about the next repair."}, w4:{plain:"An API lets one program ask another program to do work. The request goes out; the response comes back.",example:"order app -> GET /orders/42 -> order service -> 200 + JSON",diagram:["your app","request","API","response"],danger:"An API key is a secret. Keep it in an environment variable, not inside a shared file."}, @@ -210,7 +210,7 @@ var banks={ w1:{questions:[ - {q:"Which item is a file?",opts:["study","Documents","tiny-order.json","/Users/learner"],ans:2,why:"The .json item is one saved file; the others name folders or a partial path."}, + {q:"Which item is a file?",opts:["study","Documents","tiny-order.json","/Users/student"],ans:2,why:"The .json item is one saved file; the others name folders or a partial path."}, {q:"TextEdit saved tiny-order.json.txt. What happened?",opts:["It became an API","A .txt extension was added","The folder was deleted","JSON requires .txt"],ans:1,why:"The final extension is now .txt, so it is not the filename the task requested."}, {q:"What does a path tell you?",opts:["The route to a file or folder","The file's password","The program's output","The JSON schema"],ans:0,why:"A path names the folders to follow to reach an item."}, {q:"Why use plain text for JSON?",opts:["It removes formatting codes","It encrypts the file","It makes every value a number","It runs the file"],ans:0,why:"JSON is a text data format; rich-text formatting can add content JSON parsers do not understand."}, diff --git a/curriculum.html b/curriculum.html index 77513df..370e21c 100644 --- a/curriculum.html +++ b/curriculum.html @@ -55,6 +55,8 @@ + +
@@ -129,7 +131,7 @@

🪜 The whole system at a glance

- Built on Atomic Design by Brad Frost — used here as a learning map. Prefer a week-by-week view? The plan lives on the dashboard. + Built on Atomic Design by Brad Frost (2016) — used here as a learning map, not a UI method. Read Atomic Design. Prefer a week-by-week view? The 12-week plan lives on the dashboard. · updated 2026-07-15
@@ -149,7 +151,7 @@

🪜 The whole system at a glance

var UNITS=[ {id:"a1",lvl:"atoms",ic:"🔤",title:"Core vocabulary",one:"The 8 words everything is built from",tag:{t:"✓ locked — keep warm",c:"light"}, words:"API, JSON, schema, token, context window, prompt, tool, model. You already nailed these (4/5, 0 guesses) — just keep them fresh with flashcards.", - chapters:["API = two programs talking","JSON = data with labels","Schema = the shape rules","Context window = short-term memory","Prompt · Tool · Token · Model"], + chapters:["API = two programs talking","JSON = data with labels","Schema = the shape rules","Context window = limited working input, not durable memory","Prompt · Tool · Token · Model"], dia:{h:"learning-map.html#m-sysdesign",l:"System-design foundations diagram"}, vids:[["https://anthropic.skilljar.com/claude-101/383389","Claude 101 ▶ play"],[V+"claude-platform-101","Claude Platform 101"]], prep:["Why the context window matters: it is like a whiteboard with limited space \u2014 Claude can only use what is on the board right now. When the board is FULL, new text does not fit: you get an error / stop_reason: model_context_window_exceeded \u2014 nothing silently disappears. Chat apps make room by dropping the OLDEST turns first. Separate idea: text that fits but sits buried in the MIDDLE gets less attention \u2014 that is \u201clost-in-the-middle\u201d (taught in the Reliability unit).","API keys are secrets. Never put a key in your code, in a README, or in logs (logs get saved and shared). Store it in an environment variable \u2014 a value your computer holds outside the code. Example: not key = \"sk-abc123\" written in the file, but key = os.environ[\"API_KEY\"]."], @@ -194,8 +196,8 @@

🪜 The whole system at a glance

quiz:["quiz.html?set=tools-mcp","Tools & MCP quiz"], ask:"Teach me Claude Code's built-in tools for CCA-F: when to use Grep vs Glob vs Read/Write vs Edit vs Bash, and the 'grep an entry point then read to follow imports' pattern. One example, 3 flashcards."}, {id:"o1",lvl:"organisms",ic:"🤖",title:"The Agent Loop",one:"Model + tools + a loop until stop_reason says done",tag:{t:"🔴 weak · 27%",c:"weak"},start:true, - words:"An agent keeps going: think then use a tool then read the result then repeat then finish. The real stop signal is stop_reason (tool_use = keep going, end_turn = done) — NOT a fixed max-5-turns.", - chapters:["think then tool then result then repeat","stop_reason runs the loop: tool_use = continue, end_turn = done","know the other values too: max_tokens, stop_sequence, pause_turn, refusal, model_context_window_exceeded","NEVER read the text to decide when to stop — check stop_reason","why fixed iteration caps are a weak primary stop","model decides the next tool from context — not a fixed decision tree","guardrails so it can't run away","start with RAW API calls + simple patterns — a framework hides prompts, tools & errors (glass box vs magic box)"], + words:"An agent keeps going: think, request a tool, read the result, and decide again. Branch on stop_reason: tool_use means run the requested tool; end_turn means natural completion; every other value needs its own handling. A fixed turn cap is only a safety backstop.", + chapters:["think then tool then result then repeat","branch on stop_reason: tool_use = run the tool; end_turn = natural completion","handle max_tokens, stop_sequence, pause_turn, refusal, and model_context_window_exceeded explicitly","NEVER read the text to decide when to stop — check stop_reason","why fixed iteration caps are a weak primary stop","model decides the next tool from context — not a fixed decision tree","guardrails so it can't run away","start with RAW API calls + simple patterns — a framework hides prompts, tools & errors (glass box vs magic box)"], dia:{h:"learning-map.html#m-agentic",l:"The Agent Loop diagram"}, vids:[["article-effective-agents.html","🧩 Effective agents — as pictures"],["https://platform.claude.com/docs/en/build-with-claude/handling-stop-reasons","Handling stop reasons (docs)"]], quiz:["quiz.html?set=agentic","Agentic quiz"], @@ -210,14 +212,14 @@

🪜 The whole system at a glance

ask:"Teach me Orchestrator–Workers (multi-agent) for CCA-F: coordinator role, explicit context passing, parallel work, provenance, and when NOT to use multi-agent. One example, 3 flashcards."}, {id:"o3",lvl:"organisms",ic:"🔌",title:"An MCP server",one:"Tools (actions) vs resources (read-only) vs prompts (workflows)",tag:{t:"18%",c:"light"}, words:"MCP is the standard plug that connects Claude to outside systems. Three parts: tools = actions, resources = read-only context, prompts = reusable workflows. If Claude only needs to READ, it's a resource — not a tool.", - chapters:["tools = actions (model-controlled)","resources = read-only (app-controlled)","prompts = workflows (user-controlled)","transport: stdio vs Streamable HTTP","config: .mcp.json (project) vs ~/.claude.json (user)","secrets via env vars","tools from every connected MCP server are all available at once","resources can double as content catalogs, cutting exploratory tool calls","thin tool descriptions push Claude to prefer built-in tools like Grep"], + chapters:["tools = actions (model-controlled)","resources = read-only (app-controlled)","prompts = workflows (user-controlled)","transport: stdio vs Streamable HTTP","config: .mcp.json (project) vs ~/.claude.json (user)","secrets via env vars","Claude Code Tool Search discovers MCP tools on demand by default; some setups can load them directly","resources can double as content catalogs, cutting exploratory tool calls","thin tool descriptions push Claude to prefer built-in tools like Grep"], dia:{h:"learning-map.html#m-toolsmcp",l:"MCP three-parts diagram"}, vids:[["https://anthropic.skilljar.com/claude-code-101/469797","Claude Code 101 ▶ MCP"],[V+"introduction-to-model-context-protocol","Introduction to MCP"],[V+"model-context-protocol-advanced-topics","MCP: Advanced Topics"]], quiz:["quiz.html?set=tools-mcp","Tools & MCP quiz"], ask:"Teach me MCP for CCA-F: tools vs resources vs prompts, who controls each, scope, and secrets. The classic trap is using a tool when a read-only resource fits. One example, 3 flashcards."}, {id:"o4",lvl:"organisms",ic:"⚙️",title:"Claude Code workflows",one:"CLAUDE.md, commands, skills, subagents, hooks, headless",tag:{t:"20%",c:"light"}, - words:"Three jobs, in order. SET UP: CLAUDE.md project memory, slash commands, skills, path rules. RUN: plan mode, subagents, hooks, headless claude -p. STEER: concrete examples, TDD, the interview pattern, resume/fork sessions. One rule above all: rules that MUST hold go in hooks, not just a prompt.", - chapters:["§ ⚙️ Set it up", "CLAUDE.md = project rules Claude re-reads every request (not keys/history)", "CLAUDE.md hierarchy: project (git-shared) vs user-level (personal, NOT shared)", "slash commands & skills: project dir (shared, version-controlled) vs user dir (personal)", "§ ▶️ Run it", "plan mode (plan first, approve) + permission modes (ask-first → automatic)", "subagents run in their OWN fresh context — inherit nothing, pass context in the prompt", "hooks = deterministic gates: PreToolUse (before, can block) / PostToolUse (after, can check)", "a rule that MUST hold goes in a hook, not a polite prompt line", "headless claude -p = non-interactive CLI for automation & CI", "§ 🎯 Steer it", "refine output with 2–3 concrete I/O examples or one failing test", "🔨 practiced in the capstone: advanced hooks, SKILL.md details, session control --resume/fork"], + words:"Three jobs, in order. SET UP: CLAUDE.md project instructions, Skills, and path rules. RUN: plan mode, subagents, hooks, and headless claude -p. STEER: concrete examples, tests, and session controls. Rules that MUST hold go in deterministic code or hooks, not only a prompt.", + chapters:["§ ⚙️ Set it up", "CLAUDE.md = scoped project instructions loaded for a Claude Code session (not keys/history)", "CLAUDE.md hierarchy: project (git-shared) vs user-level (personal, NOT shared)", "Skills are the current workflow format; .claude/commands remains compatible", "§ ▶️ Run it", "plan mode (plan first, approve) + permission modes (ask-first → automatic)", "subagents run in their OWN fresh context — inherit nothing, pass context in the prompt", "hooks = deterministic gates: PreToolUse (before, can block) / PostToolUse (after, can check)", "a rule that MUST hold goes in a hook, not a polite prompt line", "headless claude -p = non-interactive CLI for automation & CI", "§ 🎯 Steer it", "refine output with 2–3 concrete I/O examples or one failing test", "🔨 practiced in the capstone: advanced hooks, SKILL.md details, session control --resume/fork"], dia:{h:"learning-map.html#m-claudecode",l:"Claude Code anatomy diagram"}, vids:[["https://anthropic.skilljar.com/claude-code-101/469789","Claude Code 101 ▶ How it works"],["https://anthropic.skilljar.com/claude-code-101/469795","Claude Code 101 ▶ CLAUDE.md"],[V+"claude-code-in-action","Claude Code in Action"],[V+"introduction-to-agent-skills","Introduction to agent skills"]], prep:["Plan mode: Claude writes its PLAN first and shows you, before touching any files \u2014 you approve or edit it, THEN the work happens. Use it when a task is complex with more than one reasonable approach (\"redesign the login page\"); skip it for tiny obvious fixes (one typo).","Why make a skill: a skill (SKILL.md) packages a repeatable workflow \u2014 the instructions, plus (optionally) a pinned list of allowed tools so it cannot overstep when that list is set. Example: a \"write-tests\" skill that follows your test format and may only use Read and Write (no Bash \u2192 no risky commands)."], @@ -237,8 +239,8 @@

🪜 The whole system at a glance

vids:[["https://anthropic.skilljar.com/claude-code-101/469796","Claude Code 101 ▶ Subagents"],["article-multi-agent.html","🕸️ Multi-agent research — as pictures"]], quiz:["quiz.html?set=agentic","Agentic quiz"], ask:"Walk me through a research multi-agent system for CCA-F: decompose, pass context, gather, and attach provenance (source/date/confidence) to every finding. Where does it usually break? One example, 3 flashcards."}, - {id:"p1",lvl:"pages",ic:"📄",title:"The 6 exam scenarios",one:"Whole systems, real tradeoffs — exam style",tag:null, - words:"The exam gives production scenarios. For each: read it, pick which box (prompt? tool? agent? hook?) and WHY, name the tradeoff (cost/latency/safety), and state the reliability angle. Practice by re-taking the pre-test and quizzes under time.", + {id:"p1",lvl:"pages",ic:"📄",title:"Production scenarios",one:"Whole systems, real tradeoffs — reported exam style",tag:null, + words:"Reported exam descriptions use production scenarios; Anthropic has not publicly confirmed the scenario count here. For each practice case: identify the constraint, choose an approach, defend the tradeoff, and name the reliability angle.", chapters:["read the scenario carefully","pick the box + justify it","name the tradeoff","add the reliability/guardrail angle"], dia:{h:"learning-map.html#m-roadmap",l:"Your roadmap"}, vids:[["article-effective-agents.html","🧩 Effective agents — as pictures"]], @@ -260,7 +262,7 @@

🪜 The whole system at a glance

ask:"Drill me on CCA-F anti-patterns (the wrong answers). Give me 8 scenario questions where one option is a classic trap — parsing text to stop a loop, iteration caps, prompt-enforcing critical rules, sentiment-based escalation, swallowing errors as success, too many tools, same-session self-review, aggregate metrics hiding failures. Make me pick AND explain why the others are wrong. Then grade me."}, {id:"rel",lvl:"thread",ic:"🛡️",title:"Reliability, context & evals",one:"Context, memory, RAG, evals, human-in-loop — a property at every level",tag:{t:"🔴 weak · 15% · cross-cutting",c:"thread"}, words:"Like safety in a real building, reliability shows up at every level. Revisit it inside every Organism, Template and Page: keep context tight, verify with code first, handle and propagate errors with structure (not silence), track sources, and route risk to a human.", - chapters:["context window & lost-in-the-middle", "context window ≠ memory: bigger window is not recall", "compaction / summarization keeps a long agent going but is lossy", "case-facts block: pull amounts / dates / IDs into a block outside the summary", "what survives /compact (CLAUDE.md, memory) vs what's lost", "scratchpad + memory files let agents resume after context loss", "RAG vs long context: retrieval for many/changing docs, long context for single-doc depth", "verification ladder = eval tiers: code > visual > LLM-judge", "evals: saved cases + a rubric, re-run as a regression test (not 'worked once in chat')", "guardrails: least-privilege tools — give each agent only the tools its role needs", "guardrails: human-in-the-loop approval before risky, hard-to-undo actions", "structured error context: failure type, what was tried, partial results, alternatives", "is_error / isError is real; constrained decoding still needs validation + specific-error retry", "don't silently return empty as success or abort the whole workflow on one failure", "escalate on COMPLEXITY, not sentiment", "multiple customer matches: ask for another identifier, don't guess", "provenance + handling conflicting / temporal data", "human review: stratified sampling + field-level confidence", "batch vs real-time · retries + prompt caching"], + chapters:["context window & lost-in-the-middle", "context window ≠ memory: bigger window is not recall", "compaction / summarization keeps a long agent going but is lossy", "case-facts block: pull amounts / dates / IDs into a block outside the summary", "what survives /compact (CLAUDE.md, memory) vs what's lost", "scratchpad + memory files help only when the application writes and reloads them deliberately", "RAG vs long context: retrieval for many/changing docs, long context for single-doc depth", "verification ladder = eval tiers: code > visual > LLM-judge", "evals: saved cases + a rubric, re-run as a regression test (not 'worked once in chat')", "guardrails: least-privilege tools — give each agent only the tools its role needs", "guardrails: human-in-the-loop approval before risky, hard-to-undo actions", "structured error context: failure type, what was tried, partial results, alternatives", "is_error / isError is real; constrained decoding still needs validation + specific-error retry", "don't silently return empty as success or abort the whole workflow on one failure", "escalate on COMPLEXITY, not sentiment", "multiple customer matches: ask for another identifier, don't guess", "provenance + handling conflicting / temporal data", "human review: stratified sampling + field-level confidence", "batch vs real-time · retries + prompt caching"], dia:{h:"learning-map.html#m-reliability",l:"Reliability diagrams"}, vids:[["https://anthropic.skilljar.com/claude-code-101/469793","Claude Code 101 ▶ Context management"]], prep:["Human-in-the-loop review: a person checks the agent's work before it counts, whenever a case is uncertain (the agent is not confident), risky (big money, safety), or policy-sensitive (it touches a rule someone could get in trouble for breaking \u2014 legal, medical, company policy). Example: the agent approves a $20 refund alone, but a $600 request goes to a human because policy caps solo approvals at $500.","Stratified sampling = humans spot-check a fair slice of EVERY case type, not just the easy ones, so problems in rare categories get caught. Field-level confidence = the agent says how sure it is per field, so human effort goes to the shaky fields first. One warning: confidence helps humans decide where to LOOK first \u2014 it must never be the ONLY gate that decides IF a human looks at all (that is anti-pattern trap #4)."], @@ -268,12 +270,20 @@

🪜 The whole system at a glance

ask:"This is my weak spot. Teach me Reliability for CCA-F as a thread that touches everything: lost-in-the-middle, the verification ladder (code>visual>LLM-judge), provenance, human-in-the-loop, batch vs real-time, retries + caching. One example each, then quiz me."} ]; -// The original Atomic units stay rich and detailed. The shared manifest adds -// the repaired beginner Workbench and Developer Bridge without duplicating data. +// Keep the rich curriculum detail here, but hydrate shared summary fields from +// the authoritative manifest so the Timeline, Today, Notes, and Curriculum agree. if(window.CCAF_COURSE){ - var existing={};UNITS.forEach(function(u){existing[u.id]=true;}); + var existing={};UNITS.forEach(function(u){existing[u.id]=u;}); CCAF_COURSE.units.forEach(function(u){ - if(existing[u.id])return; + if(existing[u.id]){ + var rich=existing[u.id]; + rich.title=u.title; + rich.one=u.one; + rich.ask=u.ask; + rich.quiz=rich.quiz||[u.quiz,u.title+" quiz"]; + rich.quiz[0]=u.quiz; + return; + } var lesson=CCAF_COURSE.lessons[u.id]||{}; var vids=(u.watch||[]).map(function(v){return [v[0],v[1]+(v[2]?" — "+v[2]:"")];}); UNITS.push({ @@ -342,7 +352,7 @@

🪜 The whole system at a glance

'
📐 Diagram
'+u.dia.l+' →'+repairLinks(u.id)+'
'+ '
📝 In words
'+u.words+'
'+ '
📚 Chapters
'+chapters(u.chapters)+'
'+ - '
🎥 Videos
'+rowVids(u.vids)+'
'+ + '
🎥 Videos
'+(window.CCAFMediaUI?CCAFMediaUI.inlineHTML(u.id):rowVids(u.vids))+'
'+ '
📖 Notes
Read the full lesson notes → everything the quiz tests, in plain words
'+ '
🔎 Go deeper
'+moreLinks(u.id)+'
'+ (u.prep&&u.prep.length?'
📒 Prep notes
    '+u.prep.map(function(x){return "
  • "+x+"
  • ";}).join("")+'

👆 These are the exact ideas the quiz and flashcards will test — read them before quizzing.

':"")+ diff --git a/daily-pipeline.html b/daily-pipeline.html index 3f162c6..e7aea0f 100644 --- a/daily-pipeline.html +++ b/daily-pipeline.html @@ -20,6 +20,8 @@ .stepbox{display:inline-flex;flex-direction:column;align-items:center;gap:2px;font-size:.8rem} .stepbox input{width:20px;height:20px;accent-color:#2F9E63;cursor:pointer} .dayrow .dsum{margin-left:auto;font-size:.78rem;color:var(--muted);font-weight:700} + .routine-toggle{display:flex;align-items:center;justify-content:space-between;gap:10px;flex:1 1 auto;border:0;background:transparent;color:var(--ink);font:inherit;font-weight:700;text-align:left;padding:7px 4px;cursor:pointer} + .routine-toggle:hover,.routine-toggle:focus-visible{color:var(--accent)} @@ -27,7 +29,7 @@ -
+

📋 Weekly Pipeline & Progress

@@ -43,13 +45,13 @@

🗓️ Your week

-

Steps: 🎥 watch · ✏️ draw · 🔨 build · 🗣️ explain · 🃏 flashcards — tick them on any day (backfill is fine). Today's row syncs with the Lesson page.

+

Habits: learn · draw · build · teach · review. Tick them on any day; backfill is fine. Today's row syncs with your lesson.

🔁 Today's routine, step by step

-

Tap a step's name (or ▸) for exactly what to do. This is the same 5 steps as today's row above.

+

Open a habit for exactly what to do. These are the same five checks as today's row.

@@ -76,13 +78,13 @@

🏁 Master checklist

Mirrors Daily Pipeline.md · your written backup lives in Obsidian.
- -
Copied 👍
+ +
Copied 👍
-
+

🏠 CCA-F Study Dashboard

Claude Certified Architect – Foundations · your home base

- - - - - - - - - - -

📍 Where you are · live — same tracker as the Lesson page

-
-

0 / 23 units done · next up:

+
+
Current lesson
+

Loading your lesson

+

0 / 23 units done

-

👉 Open your lesson page → it tees up the exact lesson, video and 5 steps.

- -

First step: take the Pre-Test to set your baseline — score AND how much you guessed. (Example: one real learner started at 20/30 with 18 guesses → real base ≈ 12.)

-
+
+ Continue lesson + + +
Study maps and supporting paths
+
Exam facts, domains, and official courses

📌 The exam — what's official vs reported

@@ -240,12 +235,13 @@

🎨 Color key (use these in every note & sketch)

  • Orange — human review, judgment, handoff
  • +
    -

    📋 Your lesson's 5 steps — check things off (fresh steps with each new lesson)

    +

    Practice habits for this lesson

    -

    👉 Tap a step's name (or the ▸) to see exactly what to do and where.

    +

    Five habits support the six-stage lesson path. Your quiz score updates separately.

    Today: 0 / 5 done

    @@ -260,6 +256,7 @@

    💾 Your progress

    +

    Everything you tick or type saves itself the moment you do it. Heads-up: progress belongs to the exact address in the bar — localhost:8000 and the hosted site each keep their own. Study at the same address every time.

    + +
    +
    +
    +

    Draw the idea

    +

    +
    + +
    + +
    +

    Draw this

    +

    +
    +

    Use boxes and arrows. Add one red note for what could go wrong.

    +
    + +
    +

    Sketchpad

    +
    +
    + Pen + + + + + +
    + + + +
    +
    +

    Your sketch saves after each stroke.

    +
    + +
    Draw on paper or describe it in words
    + + + +
    + + +
    +
    +
    + + + diff --git a/exercise.html b/exercise.html index b4c0a5f..ecbf12b 100644 --- a/exercise.html +++ b/exercise.html @@ -38,6 +38,7 @@ .exlist a.start{display:inline-block;background:var(--accent);color:#fff;text-decoration:none;font-weight:800;padding:9px 18px;border-radius:7px;font-size:.88rem} #toast{position:fixed;left:50%;bottom:26px;transform:translateX(-50%) translateY(40px);background:var(--ink);color:#fff;padding:12px 20px;border-radius:8px;font-weight:700;opacity:0;transition:.25s;pointer-events:none;z-index:60} #toast.show{opacity:1;transform:translateX(-50%) translateY(0)} + .tutor-actions{margin-top:14px}.tutor-actions .actions{margin:4px 0 10px} @media(max-width:620px){.modepick{grid-template-columns:1fr}} @@ -46,7 +47,7 @@ -
    +
    Copied 👍
    @@ -89,7 +90,15 @@ var SKEY="ccaf-ex-"+ex.id; var st={a:{}}; try{var s=JSON.parse(localStorage.getItem(SKEY)||"{}");if(s&&typeof s==="object"){st=s;st.a=st.a||{};}}catch(_){} - function save(){st.ts=Date.now();try{localStorage.setItem(SKEY,JSON.stringify(st));}catch(_){}} + var saveTimer=null; + function saveNow(){clearTimeout(saveTimer);st.ts=Date.now();try{localStorage.setItem(SKEY,JSON.stringify(st));}catch(_){}} + function save(){clearTimeout(saveTimer);saveTimer=setTimeout(saveNow,300);} + window.addEventListener("pagehide",saveNow); + + var creditUnit=null; + if(window.CCAF&&CCAF.COURSE&&CCAF.COURSE.map){ + (ex.units||[]).some(function(id){if(CCAF.COURSE.map[id]&&CCAF.COURSE.map[id].exercise===ex.id){creditUnit=id;return true;}return false;}); + } // ordered list of every answer field (step fields first, then quiz questions) var FIELDS=[]; @@ -100,8 +109,8 @@ '

    '+ex.mins+''+ex.level+'💾 saves as you type

    '+ '

    Goal: '+ex.goal+'

    '+ '

    '+ex.why+'

    '+ - '
    The loop: 1 · do each step here2 · 🧠 instant check3 · 📤 report to Claude → course upgrades itself
    '+ - ''; + '
    1 · Do2 · Check3 · Save
    '+ + ''+(creditUnit?'
    ':''); var boxNum=0; ex.steps.forEach(function(s,i){ @@ -112,8 +121,8 @@ } if(s.field){ boxNum++; - h+='
    '+boxNum+''+s.field.label+'
    '+ - '
    '; + h+='
    '+ + '
    '; } if(s.hints&&s.hints.length){ h+='
    '; @@ -125,8 +134,8 @@ h+='

    '+ex.quiz.title+'

    '+ex.quiz.intro+'

    '; ex.quiz.questions.forEach(function(q){ boxNum++; - h+='
    '+boxNum+''+q.q+'
    '+ - '
    '; + h+='
    '+ + '
    '; }); h+='
    '; } @@ -136,16 +145,19 @@ ''+ ''+ ''+ - '

    1. Check: Copy your answers and rubric. Paste them into your tutor for a grade.

    '+ - '

    2. Save: Copy the report for your course tutor. Mark done records the Build step.

    '+ '
    '+ - ''+ - ''+ - ''+ - '
    '; + ''+ + '
    '+ + '
    Ask a tutor to grade this build
    '+ + ''+ + ''+ + '
    '; + + if(creditUnit)h+='
    '; h+=''; app.innerHTML=h; + if(creditUnit&&window.CCAFFlow)CCAFFlow.mount("lesson-flow",{unit:creditUnit,stage:"build"}); // prompts go in via textContent (no HTML-escaping worries) ex.steps.forEach(function(s,i){ if(s.prompt){document.getElementById("pb"+i).textContent=s.prompt;} }); @@ -211,20 +223,29 @@ if(missing.length||!st.mode){ msg.style.display="block"; msg.innerHTML="One small thing remains.
    "+(missing.length?(missing.length+" answer box"+(missing.length===1?" is":"es are")+" empty.
    "):"")+(!st.mode?"Choose With guidance or Independent redo.":""); + msg.focus(); return; } } - st.done=!st.done;save(); + st.done=!st.done;saveNow(); doneBtn.classList.toggle("is-done",st.done); - doneBtn.textContent=st.done?"✓ Done":"Mark done"; + doneBtn.textContent=st.done?"✓ Build saved":"Save build"; if(st.done){ - var uid=ex.units[0],_ct=uid; - try{if(window.CCAF){CCAF.setStep(uid,2,true);CCAF.recordEvidence(uid,"build",{exercise:ex.id,mode:st.mode,complete:true});_ct=CCAF.TITLES[uid]||_ct;}}catch(_){} + var uid=creditUnit,_ct=uid||ex.title; + try{if(uid&&window.CCAF){CCAF.setStep(uid,2,true);CCAF.recordEvidence(uid,"build",{exercise:ex.id,mode:st.mode,complete:true});_ct=CCAF.TITLES[uid]||_ct;}}catch(_){} msg.style.display="block";msg.style.borderLeftColor=st.mode==="independent"?"var(--green)":"var(--yellow)";msg.style.background=st.mode==="independent"?"#EAF7EF":"#FFF4D6"; - msg.innerHTML=st.mode==="independent"?"Independent build evidence saved. This can count toward mastery.":"Guided build saved. Good learning evidence. Do a fresh independent redo later for mastery."; + msg.innerHTML=!uid?"Optional practice saved. This exercise does not replace the fixed build for a lesson.":(st.mode==="independent"?"Independent build evidence saved. This can count toward mastery.":"Guided build saved. Good learning evidence. Do a fresh independent redo later for mastery."); + msg.focus(); + if(uid&&window.CCAFFlow){CCAFFlow.mount("lesson-flow",{unit:uid,stage:"build"});CCAFFlow.mountNext("next-step",uid,st.mode==="independent"?{stage:"teach",context:"Independent build saved.",label:"Next: teach it back"}:{stage:"build",context:"Guided attempt saved. Redo once without hints.",label:"Redo independently"});} flash('Build saved for "'+_ct+'"'); + }else{ + if(creditUnit&&window.CCAF){ + try{var ev=JSON.parse(localStorage.getItem("ccaf-evidence")||"{}");if(ev[creditUnit]&&ev[creditUnit].build&&ev[creditUnit].build.data&&ev[creditUnit].build.data.exercise===ex.id){delete ev[creditUnit].build;localStorage.setItem("ccaf-evidence",JSON.stringify(ev));CCAF.setStep(creditUnit,2,false);}}catch(_){} + } + msg.style.display="block";msg.innerHTML=creditUnit?"Build unmarked. Its lesson evidence was cleared.":"Optional practice unmarked. No lesson mastery was changed.";if(document.getElementById("next-step"))document.getElementById("next-step").textContent="";if(creditUnit&&window.CCAFFlow)CCAFFlow.mount("lesson-flow",{unit:creditUnit,stage:"build"});msg.focus(); } }); + if(st.done&&creditUnit&&window.CCAFFlow){CCAFFlow.mountNext("next-step",creditUnit,st.mode==="independent"?{stage:"teach",context:"Independent build saved.",label:"Next: teach it back"}:{stage:"build",context:"Guided attempt saved. Redo once without hints.",label:"Redo independently"});} })(); diff --git a/flashcards.html b/flashcards.html index 3252db5..a6875b8 100644 --- a/flashcards.html +++ b/flashcards.html @@ -12,9 +12,9 @@ .take{text-decoration:none;font-weight:700;padding:9px 16px;border-radius:7px;font-size:.85rem;white-space:nowrap;display:inline-block} .take.browse{background:var(--accent);color:#fff} .take.learn{background:var(--green);color:#fff} - .flash{min-height:230px;display:flex;align-items:center;justify-content:center;text-align:center; + .flash{width:100%;min-height:230px;display:flex;align-items:center;justify-content:center;text-align:center; background:var(--card);border:2px solid var(--line);border-radius:8px;padding:30px 26px;cursor:pointer; - font-size:1.5rem;font-weight:700;line-height:1.5;user-select:none} + color:var(--ink);font:inherit;font-size:1.5rem;font-weight:700;line-height:1.5;user-select:none} .flash.back{background:#EAF2FB;border-color:var(--accent);font-size:1.25rem;font-weight:500} .fwrap{position:relative;margin:10px 0} .side{font-size:.8rem;color:var(--muted);text-align:center;margin-bottom:6px} @@ -26,7 +26,7 @@ .modetag{font-size:.78rem;font-weight:800;padding:4px 12px;border-radius:999px} .modetag.browse{background:#EAF2FB;color:var(--accent)} .modetag.learn{background:#E9F6EF;color:var(--green)} - /* Learn mode */ + /* Quiz mode */ .qcard{background:var(--card);border:2px solid var(--line);border-radius:8px;padding:26px 24px;text-align:center;font-size:1.3rem;font-weight:700;line-height:1.5;margin:10px 0} .opts{display:flex;flex-direction:column;gap:10px;margin-top:16px} .opt{text-align:left;border:2px solid var(--line);background:#fff;border-radius:8px;padding:14px 16px;font:inherit;font-size:1rem;line-height:1.45;cursor:pointer;color:var(--ink)} @@ -43,19 +43,20 @@ -
    +
    +
    +
    Foundation Workbench
    @@ -49,15 +63,31 @@

    Loading lesson

    +
    +

    One idea

    -

    -
    - - +

    + +
    + + +
    + + +
    + +
    0:00 / 0:00Arthur · ElevenLabs
    +

    @@ -79,11 +109,11 @@

    Tiny example

    Watch out:
    - - - +
    +
    +
    diff --git a/my-plan.html b/my-plan.html index 1029a98..877c2b8 100644 --- a/my-plan.html +++ b/my-plan.html @@ -57,6 +57,7 @@

    🎯 How the example learner spends time

    🟢 Context & Reliability2/515%🔴 DEEP & SLOW (your weakest)

    * The example learner scored 4/5 but guessed often, so those areas still need a quick confirmation pass.

    +

    Exam percentages here are community-reported, not official — see ✅ Exam Facts for what Anthropic has actually confirmed.

    Your CCA-F path (about 10-12 weeks at 20 hrs/week)

    Phase -1 (Week 1) - Foundation Workbench
    One small lesson and fixed build at a time: files -> JSON -> functions -> API -> Terminal. Mastery means 80%+, zero guesses, independent redo, and teach-back.
    Digital foundations checkpoint ->
    diff --git a/nav.js b/nav.js index c820d91..1bf90aa 100644 --- a/nav.js +++ b/nav.js @@ -2,35 +2,83 @@ Usage on a page: load course-data.js before nav.js, then render #site-nav. 5 primary tabs + a "More ▾" menu. Auto-highlights the current page. */ -/* ---- progress file-sync (runs on every page, localhost only) ---- +/* Progress files are user-controlled input. Keep one compatibility-preserving + validator for file restore, dashboard import, and safe resume links. */ +(function(global){ + var MAX_KEYS=1000,MAX_KEY=128,MAX_VALUE=1000000,MAX_TOTAL=1800000; + function isObject(value){return Object.prototype.toString.call(value)==="[object Object]";} + function validKey(key){return typeof key==="string"&&key.length<=MAX_KEY&&/^ccaf-[A-Za-z0-9][A-Za-z0-9._-]*$/.test(key)&&key!=="ccaf-sync-ts";} + function snapshot(value){ + if(!isObject(value))return {ok:false,error:"Progress data must be an object."}; + var keys=Object.keys(value),out={},total=0; + if(keys.length>MAX_KEYS)return {ok:false,error:"Progress data has too many saved items."}; + for(var i=0;iMAX_VALUE)return {ok:false,error:"Progress data contains an invalid value."}; + total+=key.length+item.length; + if(total>MAX_TOTAL)return {ok:false,error:"Progress data is too large."}; + out[key]=item; + } + return {ok:true,data:out,count:keys.length}; + } + function backup(value){ + if(!isObject(value))return {ok:false,error:"That file is not a progress backup."}; + var wrapped=Object.prototype.hasOwnProperty.call(value,"data"),ts=wrapped?value.ts:null; + if(wrapped&&(!Number.isFinite(ts)||ts<0))return {ok:false,error:"That backup has an invalid timestamp."}; + var checked=snapshot(wrapped?value.data:value); + if(!checked.ok)return checked; + checked.ts=wrapped?ts:null;checked.legacy=!wrapped; + return checked; + } + function localPage(value){ + if(typeof value!=="string"||!value||value.length>2048)return null; + try{ + var url=new URL(value,global.location.href); + if(url.origin!==global.location.origin||!/^https?:$/.test(url.protocol))return null; + if(!/\/[A-Za-z0-9][A-Za-z0-9._-]*\.html$/.test(url.pathname))return null; + return url.href; + }catch(error){return null;} + } + global.CCAFProgress={snapshot:snapshot,backup:backup,localPage:localPage}; +})(window); + +/* ---- progress file-sync (runs on every page served over local HTTP) ---- Mirrors every ccaf-* localStorage change into my-progress.json on disk (via serve.py) and restores from that file when the browser copy is missing or older — clearing browser data can no longer lose progress. On the hosted site this whole block stays inactive (browser-only saves). */ (function(){ - var LOCAL=(location.hostname==="localhost"||location.hostname==="127.0.0.1"); + var LOCAL=location.protocol==="http:"; window.CCAF_SYNC={mode:LOCAL?"probing":"pages",ts:0,restored:false}; function snap(){var d={};for(var i=0;imine){ - for(var k in f.data)rawSet(k,f.data[k]); + var checked=(f&&f.data)?window.CCAFProgress.snapshot(f.data):{ok:false}; + if(checked.ok&&typeof f.ts==="number"&&Number.isFinite(f.ts)&&f.ts>mine){ + for(var k in checked.data)rawSet(k,checked.data[k]); rawSet("ccaf-sync-ts",String(f.ts)); window.CCAF_SYNC.ts=f.ts;window.CCAF_SYNC.restored=true;didRestore=true; } - restoring=false;announce("file"); + restoring=false;announce("file");try{sessionStorage.setItem(SESSION_KEY,"file");}catch(e){} // Page scripts may already have read the old local state. One reload is // enough; the saved timestamp prevents a loop on the second load. - if(didRestore)setTimeout(function(){location.reload();},0);else push(); + if(didRestore)setTimeout(function(){location.reload();},0); }) - .catch(function(){clearTimeout(abortTimer);restoring=false;announce("nofile");push();}); + .catch(function(){clearTimeout(abortTimer);saveCapable=false;restoring=false;announce("nofile");try{sessionStorage.setItem(SESSION_KEY,"nofile");}catch(e){}}); })(); (function(){ // completion-gate upgrade: strict about the future, GENEROUS about the past. @@ -110,7 +167,7 @@ var ORDER=COURSE?COURSE.order.slice():["w1","w2","w3","w4","w5","a1","m3","m1","m2","o1","a2","d1","d2","m4","o3","o4","o2","rel","t1","t2","p1","px","p2"]; var TITLES={}; if(COURSE){COURSE.units.forEach(function(u){TITLES[u.id]=u.title;});} - else{TITLES={w1:"Files, folders, and plain text",w2:"JSON by hand",w3:"Programs, functions, and errors",w4:"API request and response",w5:"Safe Terminal basics",a1:"Core vocabulary",m3:"Prompt techniques",m1:"A structured-output call",m2:"One tool call",o1:"The Agent Loop",a2:"Model physics & economics",d1:"Repositories, trees, and diffs",d2:"Commits, pull requests, and CI",m4:"Built-in tools",o3:"An MCP server",o4:"Claude Code workflows",o2:"Orchestrator-Workers",rel:"Reliability, context & evals",t1:"Support-agent system",t2:"Research multi-agent system",p1:"The 6 exam scenarios",px:"Anti-patterns & decision frameworks",p2:"Capstone: PR-review pipeline"};} + else{TITLES={w1:"Files, folders, and plain text",w2:"JSON by hand",w3:"Programs, functions, and errors",w4:"API request and response",w5:"Safe Terminal basics",a1:"Core vocabulary",m3:"Prompt techniques",m1:"A structured-output call",m2:"One tool call",o1:"The Agent Loop",a2:"Model physics & economics",d1:"Repositories, trees, and diffs",d2:"Commits, pull requests, and CI",m4:"Built-in tools",o3:"An MCP server",o4:"Claude Code workflows",o2:"Orchestrator-Workers",rel:"Reliability, context & evals",t1:"Support-agent system",t2:"Research multi-agent system",p1:"Production scenarios",px:"Anti-patterns & decision frameworks",p2:"Capstone: PR-review pipeline"};} function cur(){var d=(J("ccaf-curriculum",{})||{}).done||{};for(var i=0;i0&&(q.score/q.total)>=0.8&&Number(q.guessed||0)===0); - var buildOK=ever||!!(ev.build&&ev.build.data&&ev.build.data.mode==="independent"); + var quizOK=ever||isProject||!!(qPass&&qPass.total>0&&(qPass.score/qPass.total)>=0.8&&Number(qPass.guessed||0)===0); + var buildOK=ever||!!(ev.build&&ev.build.data&&ev.build.data.mode==="independent"&&unit&&ev.build.data.exercise===unit.exercise); var teachOK=ever||!!(ev.teachback&&ev.teachback.data&&ev.teachback.data.complete); var allOK=ever||(sg.all&&quizOK&&buildOK&&teachOK); var touched=sg.n>0||!!q||!!ev.build||!!ev.teachback; @@ -158,6 +215,14 @@ var state=allOK?"proficient":(practiced?"practiced":(touched?"seen":"new")); return {unit:u,state:state,mastered:allOK,grandfathered:ever,steps:sg,quiz:q,quizOK:quizOK,buildOK:buildOK,teachOK:teachOK}; } + function qualifiesQuiz(result){return !!(result&&result.total>0&&(result.score/result.total)>=0.8&&Number(result.guessed||0)===0);} + function quizRecord(result){return {score:result.score,total:result.total,guessed:Number(result.guessed||0),set:result.set||"",ts:result.ts||""};} + function mergeQuizResult(previous,latest){ + var qualified=previous&&previous.qualified?quizRecord(previous.qualified):(qualifiesQuiz(previous)?quizRecord(previous):null); + if(qualifiesQuiz(latest))qualified=quizRecord(latest); + if(qualified)latest.qualified=qualified; + return latest; + } // one-time migration: OR-merge old pipeline + stash into ccaf-steps (true wins, backup first) try{ if(!localStorage.getItem("ccaf-steps-v")){ @@ -191,19 +256,92 @@ if(chA){rA.date=tod();stA[cAb]=rA;S("ccaf-steps",stA);} }}catch(e){} syncPipeline(); - window.CCAF={ORDER:ORDER,TITLES:TITLES,COURSE:COURSE,cur:cur,today:tod,getSteps:getSteps,setStep:setStep,stepsFor:stepsFor,syncPipeline:syncPipeline,recordEvidence:recordEvidence,mastery:mastery}; + window.CCAF={ORDER:ORDER,TITLES:TITLES,COURSE:COURSE,cur:cur,today:tod,getSteps:getSteps,setStep:setStep,stepsFor:stepsFor,syncPipeline:syncPipeline,recordEvidence:recordEvidence,mastery:mastery,mergeQuizResult:mergeQuizResult}; })(); +(function(global){ // ---- one lesson path shared by every learning surface ---- + var STAGES=[ + {id:"learn",label:"Learn",step:0}, + {id:"draw",label:"Draw",step:1}, + {id:"build",label:"Build",step:2}, + {id:"teach",label:"Teach",step:3}, + {id:"quiz",label:"Quiz"}, + {id:"review",label:"Review",step:4} + ]; + function addUnit(href,id){ + if(!href)return "today.html"; + if(!/^(quiz|pretest)\.html/.test(href))return href; + return href+(href.indexOf("?")>=0?"&":"?")+"unit="+encodeURIComponent(id); + } + function unit(id){return global.CCAF_COURSE&&global.CCAF_COURSE.map?global.CCAF_COURSE.map[id]:null;} + function route(id,stage){ + var u=unit(id);if(!u)return "today.html"; + if(stage==="learn")return u.notes||("notes.html?unit="+encodeURIComponent(id)); + if(stage==="draw")return "draw.html?unit="+encodeURIComponent(id); + if(stage==="build")return "exercise.html?id="+encodeURIComponent(u.exercise); + if(stage==="teach")return "teachback.html?unit="+encodeURIComponent(id); + if(stage==="quiz")return addUnit(u.quiz,id); + if(stage==="review")return "review.html?unit="+encodeURIComponent(id); + return "today.html?unit="+encodeURIComponent(id); + } + function states(id){ + var checks=global.CCAF?global.CCAF.getSteps(id):[false,false,false,false,false]; + var mastery=global.CCAF?global.CCAF.mastery(id):null; + return { + learn:!!checks[0],draw:!!checks[1], + build:!!(mastery&&mastery.buildOK),teach:!!(mastery&&mastery.teachOK), + quiz:!!(mastery&&mastery.quizOK),review:!!checks[4] + }; + } + function next(id){ + var done=states(id); + for(var i=0;i=0;} var inMore=MORE.some(function(x){return x.href.toLowerCase()===cur;}); - var html='
    '; - html+='← Back'; + var html='
    '; PRIMARY.forEach(function(p){ var c=[]; if(p.cls)c.push(p.cls); if(here(p.m))c.push("here"); - html+=''+p.label+''; + html+=''+p.label+''; }); - html+='