Six Skills You Must Show Without AI
This course requires AI. It also requires that you can do six things with the AI switched off. This page says exactly what they are, why they matter, when you learn them, how they're checked, and how to practice.
| # | Skill | Taught in | Practice (exit tickets) | Shown in (oral walkthroughs) |
|---|---|---|---|---|
| 1 | Read an error message and find the failing line | Week 4 (first seen in week 1) | Week 4 | 1, 2 and 3 (Debug) |
| 2 | Explain any function you committed | Weeks 1–2, then every week (each teach-back) | Week 1 | 1, 2 and 3 (Explain) |
| 3 | Write an acceptance criterion and a test for it | Week 3 (criteria), week 4 (manual tests and your first automated test), weeks 5–6 (check-first tests) | Week 3 | 2 (Modify: always this task) |
| 4 | Revert a bad commit | Week 2 (web), week 4 (terminal, practiced just before walkthrough 1), week 6 (agents and merges) | Week 2 | 1 and 2 (Process) |
| 5 | Spot a committed secret | Week 5, again in week 7 | Week 5 | 2 and 3 (Process: a sample diff) |
| 6 | Say where authorization is enforced in your app | Week 7 (groundwork in week 5) | Week 7 and week 8 | 3 (Explain) |
How the requirement works
- Each skill must be shown at least once in an oral walkthrough, a walkthrough retake or a short skill follow-up, and showing all six is needed for a C or higher (syllabus).
- "Shown" means you do it correctly, with the AI off and no more than one hint. Once shown, a skill stays shown.
- Exit tickets are practice. They're graded on completion and don't count as showing a skill, but they tell you which skill to work on.
- Not yet? The skill comes up again in the next walkthrough that checks it. After walkthrough 3, any skill still "not yet" gets a 5-minute follow-up by appointment in week 8.
- Skills 3 and 6 have the fewest scheduled chances (one walkthrough each), so practice them early.
The exact rules, and what the examiner asks, are in Oral Walkthroughs: The six skills you must show without AI (what to expect). Practice questions: . Grading: Rubrics.
Why this list exists
Because students asked for it. UCSD rebuilt its first programming course around an AI assistant. Afterwards, 31.1% of students were not confident which problems they should be able to solve without the AI, and the instructors said they should have spelled it out (CS1-LLM). This page spells it out.
Because feeling that you understand is not the same as understanding. In one study, students who struggled while using AI finished believing they had done better than they had (Prather et al.). In a large trial, students who used an unrestricted chatbot for practice scored lower on the exam and didn't notice (Bastani et al., PNAS). A check with the AI off is the only way you, or anyone, can tell the difference.
Because understanding drops when agents take over. In a similar course at Carnegie Mellon, students' self-rated understanding was lowest during the assignments where agents wrote most of the code (CMU 15-113 Student Wisdom report). In fall 2026, satisfaction on the same assignments rose while self-rated understanding fell on all four (CMU F26 report). That's why two of the three oral walkthroughs fall in the agent weeks.
Because finishing with AI isn't remembering. In a 2026 experiment, students using ChatGPT scored 89% on the task against 69% for students using web search, but two days later recalled less of what they had done (39% against 52%) and credited themselves with less of their own code (45% against 81%) (Bergh et al.). In another, 77% of learners who had used AI without restrictions failed a maintenance task once the AI was switched off, against 39% of those who had to explain the code before adding it (Sankaranarayanan). That's why the Safe Loop has a teach-back, and why these checks happen with the AI off.
Practice with AI, prove without it
You may use AI to learn these skills: ask it to explain code, use tutor mode, or have it quiz you. The checks are 🔴 AI off (AI use policy). "Without AI" means no chat assistant, no AI completions and no agent. You still have your own code, the browser and DevTools, the terminal, and (in oral walkthroughs) the course glossary. None of the six skills is about memorizing syntax. They're about reading, reasoning and using those tools.
1. Read an error message and find the failing line
Why it matters. Debugging is the skill AI use erodes most. In Anthropic's trial, the biggest gap between people who learned with AI and people who learned without it was on debugging questions (Anthropic, 2026). Students vibe coding spent only 7.4% of their actions looking at code or logs, and 61% of their prompts asked the AI to debug (Geng et al.). Non-programmers tend to re-prompt instead of debugging (Fawzy et al.). An error message usually tells you where to look. Reading it takes seconds.
When you learn it. You first open the Console in week 1. Week 4 teaches it properly with DevTools, and the Debug Clinic has you fix planted bugs with the AI switched off. Week 6 adds a planted bug in agent-written code.
How it's checked. Practice: the week 4 exit ticket. Shown: the Debug part of every oral walkthrough: an error the examiner causes (walkthrough 1), a failing test's output (walkthrough 2), a planted bug (walkthrough 3).
Practice (15 minutes).
A. Here is a browser Console error. Answer the questions before opening the answers.
Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
at app.js:12:7- Which file, and which line?
- What was
null? - What's a likely cause?
Answers
app.js, line 12 (the7is the column, the character position on the line).- Whatever comes just before
.addEventListeneron line 12, usually a variable holding the result ofdocument.querySelector(...)orgetElementById(...).nullmeans "nothing was found". - The
idor class in the JavaScript doesn't match the HTML (check spelling and capitals), or the script runs before the HTML element exists.
B. Here is real output from npm test. Find the line in your code that failed.
✖ AC3 (edge case): missing text counts as zero words
TypeError [Error]: Cannot read properties of undefined (reading 'trim')
at countWords (file:///workspaces/word-counter/public/lib/words.js:2:22)
at TestContext.<anonymous> (file:///workspaces/word-counter/tests/words.test.js:14:16)
at Test.runInAsyncScope (node:async_hooks:214:14)
at Test.run (node:internal/test_runner/test:1047:25)Answer
Read from the top. The first line that points at one of your files is where it broke: public/lib/words.js, line 2, inside countWords. The next line says who called it: the test on line 14 of tests/words.test.js. Lines starting with node: are Node's own machinery; skip them. The message says the code called .trim() on something undefined: the test passed no text at all, and countWords doesn't handle that case.
C. Make an error on purpose. Open any of your pages, open DevTools → Console, type this and press Enter:
document.querySelector('#does-not-exist').textContent = 'hi'Read the error out loud in plain English: "I tried to set the text of something that doesn't exist."
Self-check.
- ☐ Given an error, I can name the file and line without help.
- ☐ I can say what the error means in plain words.
- ☐ When something breaks, I look at the Console or terminal before I ask the AI.
2. Explain any function you committed
Why it matters. "If you can't explain it, you didn't build it" (UMich syllabus). Simon Willison's rule for responsible AI-assisted programming is never to commit code you couldn't explain to someone else (Willison). Learners who generated whole solutions from one prompt did worst when they later had to change that code (Kazemitabaar et al.). You can only change what you understand.
When you learn it. Week 1: explain three parts of your page. Week 2: explain one function in a classmate's game. Every week after: step 5 of the Safe Loop, "keep only what you can explain", and the teach-back you write before committing AI-written code. Each teach-back is practice for this skill.
How it's checked. Practice: the week 1 exit ticket, and each week's delayed-recall exit-ticket question about last week's project. Shown: the Explain part of every oral walkthrough: you explain your code (in walkthrough 2, the code the agent wrote), then change it live.
Practice (15 minutes): the four-question explanation. Pick a function from your latest commit. Without AI, write short answers:
- What goes in? Its inputs, and anything it reads (the page, localStorage).
- What comes out, or changes? Its return value, what changes on the page or in storage.
- How, step by step? Three to five plain-English steps.
- What would break it? One input or situation it doesn't handle.
Then change one line and predict what will happen. Run it. Were you right?
Here's a function to try it on:
export function countWords(text) {
const words = text.trim().split(/\s+/);
return words.filter((w) => w.length > 0).length;
}A sample explanation
- In: a piece of text.
- Out: a number, the count of words. It doesn't change anything else.
- How: it cuts spaces off both ends of the text; splits it wherever there's one or more spaces, tabs or line breaks; throws away any empty pieces; and counts what's left.
- Breaks on: being given no text at all (
undefined), because you can't.trim()nothing. That's the test failure in skill 1.
Change one line: remove .trim(). Prediction: " hi" would split into ["", "hi"], the filter would drop the empty piece, and the count would still be 1. So .trim() is doing less work than it looks. Run it to check.
Afterwards, if you like, use explain this code and compare. Where did you and the AI differ? Who was right?
Self-check.
- ☐ I can explain every function in my latest commit with the chat closed.
- ☐ I can predict what changing one line will do, and I'm usually right.
- ☐ I can name at least one input that would break each function.
3. Write an acceptance criterion and a test for it
Why it matters. Beginners test the happy path. In one study of students vibe coding, 91.7% of their tests tried common cases, only 2.2% tried edge cases, and no student wrote a unit test (Geng et al.). Courses that grade robustness give credit only for edge cases and how features interact (Utah syllabus). The WHEN … SHALL format comes from a requirements style people without programming experience can learn in minutes (Kiro). With agents, tests are how the AI checks its own work and how you check its claims (Claude Code best practices).
When you learn it. Week 3: acceptance criteria in SPEC.md. Week 4: manual edge-case tests in TESTS.md, and your first automated test, from a worked example in Studio B (a pure function tested with node --test). Week 5: a validation test from a fill-in skeleton. Week 6: check-first tests, written before the agent writes the code, red first, then green.
How it's checked. Practice: the week 3 exit ticket. Shown: walkthrough 2, whose Modify task is always this: say a new criterion in WHEN … THE APP SHALL … form, write its test by hand, watch it fail, then make it pass. Walkthrough 3 may also ask you to explain a test. Your capstone's TESTS.md and tests are graded in the capstone rubric.
Practice (20 minutes). The feature: a live word count under a text box.
- Write one normal criterion in the form WHEN … THE APP SHALL ….
- Write two edge-case criteria.
- Turn one of them into a manual test row: ID · Checks · Steps · Expected result.
- (Week 4 onward) Write an automated test for it, before the code that makes it pass.
Sample answers
AC1: WHEN I type "hello big world", THE APP SHALL show "3 words".
AC2: WHEN the box is empty, THE APP SHALL show "0 words". AC3: WHEN I type only spaces, THE APP SHALL show "0 words".
| T2 | AC2 (edge case) | 1. Open the page. 2. Leave the box empty. | The count says "0 words". |
Using Node's built-in test runner, in
tests/words.test.js:jsimport { test } from 'node:test'; import assert from 'node:assert/strict'; import { countWords } from '../public/lib/words.js'; test('AC1: counts words separated by spaces', () => { assert.equal(countWords('hello big world'), 3); }); test('AC2 (edge case): an empty box shows 0 words', () => { assert.equal(countWords(''), 0); }); test('AC3 (edge case): only spaces shows 0 words', () => { assert.equal(countWords(' '), 0); });Run it with
npm test. Each test's name says which criterion it checks.
Self-check.
- ☐ I can turn a feature into WHEN … THE APP SHALL … sentences that someone else could test.
- ☐ Every feature I build has at least two edge-case criteria.
- ☐ I can point to the test that checks each criterion, and I've watched a new test fail before it passed.
4. Revert a bad commit
Why it matters. Git is your undo button when an AI goes wrong. In July 2025 an AI agent deleted a company's production database, then wrongly claimed it couldn't be rolled back (Fortune). Anthropic warns that its agent's own checkpoints are "not a replacement for git" (Claude Code best practices). Google's DORA research names strong version control and small batches as two of the conditions under which AI helps teams rather than hurts them (DORA AI Capabilities Model).
When you learn it. Week 2 on github.com, with a deliberate break-and-rollback in the Game in an Hour. Week 4 in the Codespace terminal, in a practice session just before walkthrough 1. Week 6: commit before and after every agent task, and merge features through pull requests (reverting a merge needs one extra flag: how).
How it's checked. Practice: the week 2 exit ticket. Shown: the Process part of walkthroughs 1 (revert a commit) and 2 (undo an agent's commit).
Practice (10 minutes). In a practice repo, or on a line of your home page you don't mind breaking:
Make a deliberately bad change (change your heading to
BROKEN), commit it, and push.Find it:
bashgit log --onelineUndo it with a new commit, and push:
bashgit revert --no-edit [hash] git pushCheck that the page is back to normal, and that
git log --onelineshows both the bad commit and the revert.
Do it once looking at the git cheat sheet, then once without it, saying out loud what each command does.
Self-check.
- ☐ I can find the hash of a bad commit.
- ☐ I can revert it without looking up the command.
- ☐ I can explain why
git revertis safer thangit reset --hard(why).
5. Spot a committed secret
Why it matters. AI-assisted commits leak secrets about twice as often as ordinary ones: 3.2% versus 1.6% (GitGuardian 2026). Leaked keys cost money and data. Moltbook's database key sat in its public JavaScript (Wiz), and the Nx attack leaked 2,349 credentials from 1,079 systems (GitGuardian). Stories: case studies.
When you learn it. Week 5: keys, .env, .gitignore, which keys are secret and which aren't, and proving your key isn't visible in the browser or in git. Week 7: a security sweep of your capstone, including a secret scan of its whole history.
How it's checked. Practice: the week 5 exit ticket and the week 5 understanding check ("show where the key lives and who can read it"); the secrets section of your SECURITY_CHECKLIST.md template. Shown: walkthroughs 2 and 3, where you're shown a sample diff and asked to find the secret, or to say why a key in it is fine.
Practice A (10 minutes). Which of these is a problem? Decide for each, then check.
- In
api/ask.js:const apiKey = process.env.LLM_API_KEY; - In
.env.example:LLM_API_KEY=paste-your-key-here - In
public/app.js:const LLM_API_KEY = "xyzFAKEkey0123notReal"; git ls-files .envprints.env.- Your README includes a screenshot of Vercel's environment variables page with the values visible.
- In
public/config.js, your Supabase project URL and publishable key (sb_publishable_…). - In
public/app.js, a Supabase client created with the secret key (sb_secret_…, or a legacyservice_rolekey).
Answers
- Fine. It reads the key from an environment variable, on the server.
- Fine. A placeholder, not a real key.
- Leak. A key in front-end code is public, and now it's in git history too. Revoke it.
- Leak.
.envis tracked by git, so its contents are in the repo. Revoke every key in it. - Leak. A screenshot is still a copy of the key. Revoke it and replace the image.
- Allowed by design. Not every key is a secret: the publishable key is meant to be public, but it's safe only if row-level security is on, with policies, for every table (skill 6).
- Serious leak. That key bypasses all access rules. Revoke it immediately.
Practice B (10 minutes). Check your own project:
git ls-files .env
git log --oneline -S "LLM_API_KEY="
npm run check:secretsThe first should print nothing. The second lists every commit that added or removed that text. Open each with git show [hash]: you should find only placeholders, as in .env.example. The third scans your current files and every past commit for the key formats the course uses, and prints the file or commit of any match with the key masked. A clean scan is good evidence, not proof: it only knows the formats it looks for. Finally, open your live site, and search DevTools → Sources and Network for your key.
If you find a real key: revoke it first.
Self-check.
- ☐ I can say where my key lives, both locally and on my host, and who can read it.
- ☐ I can prove
.envwas never committed. - ☐ I know the first thing to do when I find a leaked key: revoke it.
6. Say where authorization is enforced in your app
Why it matters. This is where real vibe-coded apps failed. A scan of apps built with Lovable found 170 of 1,645 with exposed databases, because the browser used the database's public key and the access rules were missing (Superblocks). In September 2026, UpGuard found 16,326 Supabase databases with publicly readable tables, and noted that tables agents create through the API start without row-level security (case 12). In an audit of 200 deployed apps built with AI tools, 91% had at least one vulnerability, mostly broken access control (Deng et al.). Moltbook had the same pattern and exposed about 1.5 million API tokens (Wiz). Karpathy describes agents building his app to match users across services by email address instead of a permanent user ID, a design mistake only someone who understood the code would catch (Karpathy, 2026). Newer AI models are not writing more secure code (Veracode Spring 2026), so this check stays your job.
When you learn it. Week 5 lays the groundwork: the browser is public, the server is not (trust boundary). Week 7 teaches authentication versus authorization and has you attack your own table in the RLS Attack Lab, then fix it with row-level security.
How it's checked. The week 7 and week 8 exit tickets; the "Authorization is enforced in:" line of your capstone README (template); section 3 of your SECURITY_CHECKLIST.md template; and walkthrough 3.
Practice (15 minutes). For each app, where is authorization enforced? Or is it missing?
- A to-do list that saves to localStorage.
- A notes app whose page reads a Supabase table with the publishable key. Row-level security is on, with a policy that returns a row only when its
user_idmatches the logged-in user. - The same notes app, but row-level security is off. The page hides other people's notes with
notes.filter((n) => n.user_id === me.id)inapp.js. - An admin page whose "Delete everything" button is hidden with CSS unless you're an admin. The server route that deletes everything has no checks.
- The week 5 AI micro-app: anyone can use it, and
api/ask.jsrejects questions that are too long before calling the LLM.
Answers
- Not needed. It's a single-user app; data never leaves that browser. (Anyone using that device can still read it.)
- In the database, by the row-level security policy on the notes table. This is the right answer.
- Nowhere. The filter runs in the browser, which the user controls. Anyone with the publishable key can read every note. This is the Lovable and Moltbook pattern.
- Nowhere. Hiding a button isn't authorization. Anyone can call the server route directly.
- There are no users to authorize. The server protects the key and enforces limits on input. Saying so clearly is a correct answer.
Now write the sentence for your own capstone:
In my app, authorization is enforced in ________ (a file or a database policy),
which checks ________ before ________.Self-check.
- ☐ I can finish that sentence for my app, pointing to a real file or policy.
- ☐ I can explain why checks in browser JavaScript don't count.
- ☐ I've tried to read or change data I shouldn't be able to, using only the public key, and watched it fail.
Before each oral walkthrough
- ☐ I can explain every function I committed since the last walkthrough (skill 2).
- ☐ I've practiced finding a bug from an error message with the AI closed (skill 1).
- ☐ I can write a criterion and its test by hand, and point to the test for each criterion (skill 3, shown in walkthrough 2).
- ☐ I've reverted a commit in this project at least once (skill 4).
- ☐ I've run the secret checks on this project (skill 5, walkthroughs 2 and 3).
- ☐ I can say where authorization is enforced (skill 6, walkthrough 3).
Can't do one yet? That's what the practice above and office hours are for. The walkthroughs are there to find gaps while there's still time to close them.